The Easter Egg Hunt on the Hill

17

2

Easter Egg Hunt

Bot find egg before bunny find egg. Bot happy.

Overview

This is a challenge in honor of Easter and the Easter egg hunting tradition!

Your bot has a vision of two spaces in every direction, including diagonals, creating a 5x5 square around you that you can see. It is looking for eggs, and whoever finds the most eggs wins!

The Board

The board will consist of os, which are Easter eggs, #s, which are walls, *s, which are other players, and s, which are empty spaces.

  • It will be a square with edge length (number of entries) * 3.
  • It will be surrounded by walls.
  • Inside of the walls will be an assortment of randomly placed, straight line walls of #, which will have a random length between 2 and 10 inclusive. There will be (number of entries) * 3 of them.
  • The eggs will then be placed randomly. There will be (number of entries) * 4 of them, and they will only be generated on blank () squares.
  • There must be at least 7 entires for the board generating process to work properly.

Here is a JSFiddle that will generate a random board for you to test with. Here's an example, with (number of entries) = 7:

#####################
#        o         ##
#    #    o        ##
#    #o    ######  ##
######     #       ##
## o #     #       ##
##  o#   #o#    o o##
##   #o  # # o  #   #
##   # o # #    #   #
##  ##   # #  o #   #
##  #    #  o   # # #
##  # o  #   ## # # #
##  #           # # #
# o #          ## # #
# o oo         ##o  #
#o  ####### oo ##   #
#        #      #   #
#   o o o#          #
#   o ####   o     o#
#                   #
#####################

After the board is generated, each player is placed on a random square (empty space).

Input

You will take six lines of input. The first five lines are your field of vision (spaces out of bounds of the board will be represented by X, and the middle space will always be *, you), and the sixth line will be empty (at first).

Output

You will output three lines. First, the direction that you want to move in:

1  2  3
8 YOU 4
7  6  5

(9 is a no-op if you don't want to move), second, one of Attack, Counter, or Nothing (this will be explained in depth soon), and the thrid line will be any string of length up to 1024. This will be your bot's memory. You may use it for whatever you would like, or you may leave it blank. This memory will then be the sixth line of input to your program on the next run.

All further lines of output are ignored, and if there is only one line, the second is assumed to be blank.

Moving

The following process is used to determine where you moved:

  • If, when you move, you end up in an empty space (), your player is placed into that space.
  • If you end up in a wall (#), your move is ignored and you lose your turn.
  • If you end up in an egg (o) or on a player (*), this information is stored and will be used after everybody has moved.

After everybody has moved, ambiguities are resolved.

If there are two players that have landed on the same space, a fight occurs! This is where the A/C/N comes in to play. Attack beats Nothing (normal attack), Nothing beats Counter (you can't counter nothing), and Counter beats Attack (counterattack). The player who wins this fight stays on their square, and the player who loses goes back to the original square that they started on. In the event of a tie, both players go back to where they were.

If a losing or tied player goes back to where they were and there is another player there, there is no fight and the other player will also revert to its original space. If this space has another player, that player goes back, and this continues until all players are in different spaces.

If there are three or more players on one space, they all revert back to their original positions.

If any player is still standing on an egg...

  • If the player chose A, the egg is destroyed.
  • If the player chose C, nothing happens and the player reverts to its original space.
  • If the player chose N, the player picks up the egg! The player's score is incremented by one and the egg is removed.

Languages

You may use any language that is freely available on Windows, OSX, and Linux, to ensure fairness among each contestant. If the code is not freely runnable but can be compiled or packaged into a format that is, please include this format in your answer as well. Ideally, if you can compile your code into a more common language (i.e. CoffeeScript -> JavaScript), please do so.

Scoring

Your score will be the average number of eggs you collect out of ten runs. A run ends when all eggs are collected or when (number of entries * 25) turns have passed. I will manually make sure that it is possible to reach all eggs for each map (by continually generating maps until all eggs are reachable).

Scoreboard

A scoreboard will be added when all of the following conditions are met:

  • At least seven valid entries with a positive or zero score (not downvoted) have been submitted
  • At least 48 hours has passed since the creation of this challenge (UTC 14:23)

The rules will not change during this pre-contest period, except to add clarification where a rule was unclear. Once the scoreboard is put up, the testing program will also be posted here so that you can test your entries. The testing code for this is still work-in-progress, but it's playable and it works. Here's the GitHub repo.

Doorknob

Posted 2014-04-20T14:23:10.060

Reputation: 68 138

4Can we get the testing program before 7 entries are posted? I like to test before posting, even if it's against "dumb" test-bots. It seems this gives a significant advantage to not posting until several others have. – Geobits – 2014-04-20T14:44:25.017

1Regarding players going back. So I could potentially be unlucky and win against an opponent but he steps back into another player and starts a cascade that loop around back to the site of our fight, such that the player who started there sends me back a step as well? (if that's not clear, I'll post a github gist with an example) – Martin Ender – 2014-04-20T15:01:22.540

@m.buettner Ok fixed that (sorry I'm in a hurry right now, will clarify more later) – Doorknob – 2014-04-20T15:04:23.633

Oh and we can see through walls? – Martin Ender – 2014-04-20T15:06:09.173

1A sample control program would be very useful here. – starbeamrainbowlabs – 2014-04-20T15:35:33.040

@Geobits Alright, I'll upload my testing program in a sec. There's still a few bugs that need to be ironed out, but it works. (That's why I didn't post it immediately in the first place.) – Doorknob – 2014-04-20T17:06:05.973

@m.buettner Yes, that could happen, but the board scales according to how many players there are so it's unlikely. – Doorknob – 2014-04-20T17:06:32.897

@m.buettner The "walls" are more like... unpassable obstacles, shall we say. ;) I'll add a cap on the amount of moves per game, but I still think this generation method produces better obstacles for this kind of game. – Doorknob – 2014-04-20T17:07:24.807

@m.buettner Yeah, that discarding method sounds better. Thanks for all the help you're putting in to this ;) I would assume that at least one bot would have the ability to scan the whole map, but a move cap would be good anyway in case of an infinite loop or it just taking way too long. – Doorknob – 2014-04-20T17:30:46.937

Why not just wrap the map in two layers of walls (#)? It seems simpler to me. – Justin – 2014-04-20T20:42:10.167

1Will I be informed if I am pushed back (whether or not I win)? Also, what will I get for the tile that I'm on? Will I see a space, a *, or what? – Justin – 2014-04-20T21:06:23.897

@Quincunx in the current implementation your own position is a space. – Martin Ender – 2014-04-21T00:30:26.937

What is the procedure in determining the order of which bot fights which bot in the event where more than one bots go to the same space? And what happen when bot reverts back to its own space after doing C on an egg? – justhalf – 2014-04-21T06:27:54.327

How can I use the testing code to test a bot? I don't know ruby and am new here :) – starbeamrainbowlabs – 2014-04-21T09:15:30.490

@starbeamrainbowlabs at the end of the tester.rb there's a string with loads of ruby dumbbot.rb lines. Add the command for your own bot to that string (and remove some of the dumb bots if you wish). Then do either ruby tester.rb < map.txt on Unix or cat map.txt | ruby tester.rb on Windows. – Martin Ender – 2014-04-21T10:15:24.797

@m.buettner Thanks! That worked, lthough I had to change chat map.txt | ruby tester.rb to type map.txt | ruby tester.rb in order to pass the map to tester.rb. – starbeamrainbowlabs – 2014-04-21T10:31:59.240

3I like the memory line idea – Einacio – 2014-04-21T15:31:30.340

@Einacio I was just about to post that, I think more KotH challenges should use that. However, due to the variable size of the problem (i.e. the map) a fixed size of memory could really be a problem. I'm still not sure if I like that or not (although I suppose it was a conscious decision). This allows me to build a bot that memorises the entire map (or what it has seen of it so far), but might break if there are suddenly more then, say 15 submissions, a fix for which would make the bot considerably more difficult. – Martin Ender – 2014-04-21T15:43:47.653

After doing a few tests on a new bot I have to agree with @Quincunx that some feedback about the result of a fight would be very useful. Otherwise keeping track of where you are will require some quite elaborate pattern matching (and won't even be possible if you're in a region like the bottom left of the example map where there are no walls at all). – Martin Ender – 2014-04-22T12:36:29.560

2Also are you aware of the implication of your rules: if a player (A) chooses 9, he can never be meaningfully attacked. If another player (B) steps onto that players square and wins, A will be moved back to its original square (which is the same). But now there is a clash because both A and B are there, so B has to go back to his own square. So the result is independent of the actual fight, B always moves back to the initial square and A always stays put. That would allow me to write a both that could help another submission by blocking of a path for everyone else. – Martin Ender – 2014-04-22T12:40:46.060

Yet another thing: if two walls touch on a corner can I move through them diagonally? i.e. if there is a wall in direction 2 and 4 can I move to 3? – Martin Ender – 2014-04-23T14:06:09.530

Okay I just answered the question myself be looking at the test script. Such a move is indeed possible. Is that intentional or a bug? – Martin Ender – 2014-04-23T14:30:51.027

Unfortunately, it doesn't currently look like we're going to get far beyond 7 entries (so this question probably doesn't really matter), but what's your rationale behind increasing the map size with the square of the submissions but the number of walls only linearly (and their size not at all). If you generate maps for like 20 participants, they look really sparse. – Martin Ender – 2014-04-24T20:42:26.393

I'm also not sure I'm happy with the "If there are three or more players on one space, they all revert back to their original positions." rule (which you did add after the challenge started). If two other bots are in deadlock over an egg that makes it impossible for any other bot to break up that deadlock. Basically the three (or more) positions of the egg and the two (or more) players around the egg are completely inaccessible for the rest of the round. – Martin Ender – 2014-04-28T00:57:58.610

Answers

3

Cart'o'Gophers

Here is another submission - and this one is actually meant to be competitive. Again, it's in Ruby. So run it with ruby cartogophers.rb. This took a lot longer than expected...

require 'zlib'
require 'base64'

def encode map, coords
    zipped = Zlib::Deflate.deflate map.join
    encoded = Base64.encode64(zipped).gsub("\n",'')
    "#{coords[:x]}|#{coords[:y]}|#{map.length}|#{encoded}"
end

def decode memory
    memory =~ /^(\d+)[|](\d+)[|](\d+)[|](.*)$/
    coords = {x: $1.to_i, y: $2.to_i}
    n_rows = $3.to_i
    encoded = $4
    decoded = Base64.decode64 encoded
    unzipped = Zlib::Inflate.inflate decoded
    n_cols = unzipped.length / n_rows;
    return unzipped.scan(/.{#{n_cols}}/), coords
end

def update map, fov, coords
    if coords[:x] < 2
        map.map! { |row| '?' << row }
        coords[:x] += 1
    elsif coords[:x] >= map[0].length - 2
        map.map! { |row| row << '?' }
    end

    if coords[:y] < 2
        map.unshift '?' * map[0].length
        coords[:y] += 1
    elsif coords[:y] >= map.length - 2
        map.push '?' * map[0].length
    end

    fov.each_index do |i|
        map[coords[:y]-2+i][coords[:x]-2, 5] = fov[i]
    end

    return map, coords
end

def clean_up map
    map.each do |row|
        row.gsub!('*', ' ')
    end
end

DIRECTIONS = [
    [],
    [-1,-1],
    [ 0,-1],
    [ 1,-1],
    [ 1, 0],
    [ 1, 1],
    [ 0, 1],
    [-1, 1],
    [-1, 0],
    [ 0, 0]
]

def move_to dir, coords
    {
        x: coords[:x] + DIRECTIONS[dir][0],
        y: coords[:y] + DIRECTIONS[dir][1]
    }
end

def get map, coords
    if coords[:x] < 0 || coords[:x] >= map[0].length ||
       coords[:y] < 0 || coords[:y] >= map.length
        return '?'
    end
    map[coords[:y]][coords[:x]]
end

def set map, coords, value
    unless coords[:x] < 0 || coords[:x] >= map[0].length ||
       coords[:y] < 0 || coords[:y] >= map.length
        map[coords[:y]][coords[:x]] = value
    end
    map[coords[:y]][coords[:x]]
end

def scan_surroundings map, coords
    not_checked = [coords]
    checked = []
    cost = { coords => 0 }
    direction = { coords => 9 }
    edges = {}

    while not_checked.length > 0
        current = not_checked.pop

        checked.push current
        (-1..1).each do |i|
            (-1..1).each do |j|
                c = { x: current[:x]+i, y: current[:y]+j }
                unless not_checked.include?(c) || checked.include?(c)
                    if get(map, c) == '#'
                        checked.push c
                    elsif get(map, c) == '?'
                        checked.push c
                        edges[current] = { cost: cost[current], move: direction[current] }
                    else
                        not_checked.unshift c

                        cost[c] = cost[current] + 1
                        if direction[current] == 9 # assign initial direction
                            direction[c] = DIRECTIONS.find_index([i,j])
                        else
                            direction[c] = direction[current]
                        end

                        if get(map, c) == 'o'
                            return direction[c], if cost[c] == 1 then 'N' else 'A' end
                        end

                        edges[c] = { cost: cost[c], move: direction[c] } if c[:x] == 0 || c[:x] == map[0].length - 1 ||
                                                                            c[:y] == 0 || c[:y] == map.length - 1
                    end
                end
            end
        end
    end

    # If no egg has been found return the move to the closest edge
    nearest_edge = edges.keys.sort_by { |c| edges[c][:cost] }.first
    if edges.length > 0
        return edges[nearest_edge][:move], 'A'
    else
        # The entire map has been scanned and no more eggs are left.
        # Wait for the game to end.
        return 9, 'N'
    end
end

input = $<.read.split "\n"
fov = input[0..4]
memory = input[5]

if memory
    map, coords = decode memory
    map, coords = update(map, fov, coords)
else
    map = fov
    coords = {x: 2, y: 2}
end
clean_up map

move, attack = scan_surroundings(map, coords)

memory = encode map, move_to(move, coords)

puts "#{move}
#{attack}
#{memory}"

This bot remembers what it has seen before and tries to construct a larger map at each turn. It then uses a breadth-first search for the nearest egg and heads that way. If there is no egg that can be reached on the current map, the bot heads for the nearest open edge of its map (so as to expand the map quickly in a direction it can still move).

This bot has no concept of other bots yet and no fighting strategy either. Since I haven't found a reliable way to determine if my move has been successful, this can cause some problems. I simply always assume that the move has been successful - so if it wasn't new patches will be loaded into the map in the wrong places, which may or may not be harmful to pathfinding.

The bot uses the memory to store the map and its new position on the map (assuming the move will be successful). The map is stored without line breaks, zipped and base64 encoded (along with the number of rows of the map, so that the line breaks can be reinserted). This compression brings the size down to about a third of the uncompressed map, so having a shade over 1000 bytes, I could store a map of about 3000 cells, which roughly corresponds to fully exploring a map with 18 bots. As long as there are nowhere near that many submissions, I don't think I can be bothered to figure out a fix for that case.

After a few test runs against 5 dumbbots and 1 naivebot (my other submission), it either performed really badly (like 1 or 2 eggs) or outperformed the others by a considerable margin (7 to 9 eggs). I may think about a better fighting strategy and how I can determine if I actually moved or not. Both might be able to improve the score somewhat.

Oh and if you're wondering about the name of the bot, you should read The Order of The Stick (last panel on this comic).

EDIT: There were a few bugs with detecting the edges of the discovered map. Now that I've fixed them this bot always gets scores of about 20 against 5 dumbbots and 1 naivebot. That's more like it! If you add $stderr.puts map to my bot now, you can really see how he systematically uncovers the map and collects all eggs in the meantime. I've also decided to choose A instead of N whenever not stepping onto an egg, to reduce the probability of moving back to the bot's original cell (which partly screws up the map).

(It doesn't perform quite as well against 6 naivebots, especially since it's very possible to end up in a "deadlock" with another bot when they both repeatedly want to grab an egg and choose N. I need to think about that...)

Martin Ender

Posted 2014-04-20T14:23:10.060

Reputation: 184 808

3

Java Bunny

This bunny hasn't finished growing up yet (I still plan to make changes), but it's a starting point for right now. He looks for the closest egg and goes towards it. There isn't wall detection or out-of-bounds detection (yet). He'll go to pick up the egg he lands on, but otherwise he'll try to push he way around and attack anything else. If there are no nearby eggs, he'll start following the nearest bunny. They might know something that he doesn't. Otherwise, he'll just pick a random direction to walk. And he's pretty forgetful (no use of the memory variable).

Plans moving forward:

  • Make decisions based on walls/out-of-bounds
  • Pick paths with a purpose, rather than randomly
  • Use the memory to determine the direction I was going before

Update 1 My bunny will follow other bunnies if he doesn't see an egg. Also refactored the "find nearest egg" code into it's own method.

import java.util.*;

public class EasterEggHunt {

    // board chars
    public static final char EGG = 'o';
    public static final char WALL = '#';
    public static final char BUNNY = '*';
    public static final char SPACE = ' ';
    public static final char OUT_OF_BOUNDS = 'X';

    // player moves
    public static final char ATTACK = 'A';
    public static final char COUNTER = 'C';
    public static final char NOTHING = 'N';

    // directions
    public static final int UPPER_LEFT = 1;
    public static final int UP = 2;
    public static final int UPPER_RIGHT = 3;
    public static final int RIGHT = 4;
    public static final int LOWER_RIGHT = 5;
    public static final int DOWN = 6;
    public static final int LOWER_LEFT = 7;
    public static final int LEFT = 8;
    public static final int STAY = 9;


    // the size of the immediate area
    // (I'll be at the center)
    public static final int VISION_RANGE = 5;

    public static void main(String[] args) {

        Scanner input = new Scanner(System.in);

        char[][] immediateArea = new char[VISION_RANGE][VISION_RANGE];

        for (int i = 0; i < VISION_RANGE; ++i) {
            String line = input.nextLine();
            for (int j = 0; j < VISION_RANGE; ++j) {
                immediateArea[i][j] = line.charAt(j);
            }
        }

        String memory = input.nextLine();

        int moveDirection = decideMoveDirection(immediateArea, memory);
        System.out.println(moveDirection);

        char action = decideAction(immediateArea, memory, moveDirection);
        System.out.println(action);

        // change the memory?
        System.out.println(memory);

    }

    private static int decideMoveDirection(char[][] immediateArea, String memory) {

        // if there's a nearby egg, go towards it
        int direction = nearestBoardObject(immediateArea, EGG);

        // if we didn't find an egg, look for a bunny
        // (maybe he knows where to find eggs)
        if (direction == STAY)
            direction = nearestBoardObject(immediateArea, BUNNY);

        // otherwise, pick a random direction and go
        // we want to also have the chance to stop and catch our breath
        if (direction == STAY)
            direction = new Random().nextInt(STAY + 1);

        return direction;
    }

    private static int nearestBoardObject(char[][] immediateArea, char boardObject) {

        // start at the center and go outward (pick a closer target over a farther one)
        int spacesAway = 1;
        int meX = immediateArea.length / 2;
        int meY = immediateArea[meX].length / 2;

        while (spacesAway <= immediateArea.length / 2) {

            // I like to look right, and go clockwise
            if (immediateArea[meX][meY + spacesAway] == boardObject)
                return RIGHT;
            if (immediateArea[meX + spacesAway][meY + spacesAway] == boardObject)
                return LOWER_RIGHT;
            if (immediateArea[meX + spacesAway][meY] == boardObject)
                return DOWN;
            if (immediateArea[meX + spacesAway][meY - spacesAway] == boardObject)
                return LOWER_LEFT;
            if (immediateArea[meX][meY - spacesAway] == boardObject)
                return LEFT;
            if (immediateArea[meX - spacesAway][meY - spacesAway] == boardObject)
                return UPPER_LEFT;
            if (immediateArea[meX - spacesAway][meY] == boardObject)
                return UP;
            if (immediateArea[meX - spacesAway][meY + spacesAway] == boardObject)
                return UPPER_RIGHT;

            ++spacesAway;
        }

        // if the target object isn't in the immediate area, stay put
        return STAY;

    }

    private static char decideAction(char[][] immediateArea, String memory, int moveDirection) {

        char destinationObject = getDestinationObject(immediateArea, moveDirection);

        switch (destinationObject) {

            case EGG:
                // don't break the egg
                return NOTHING;
            default:
                // get really aggressive on everything else
                // other players, walls, doesn't matter
                return ATTACK;

        }

    }

    private static char getDestinationObject(char[][] immediateArea, int moveDirection) {

        // start at my spot (middle of the board) and figure out which direction I'm going
        int targetX = immediateArea.length / 2;
        int targetY = immediateArea[targetX].length / 2;

        switch (moveDirection) {

            case RIGHT:
                ++targetY;
                break;
            case LOWER_RIGHT:
                ++targetX;
                ++targetY;
                break;
            case DOWN:
                ++targetX;
                break;
            case LOWER_LEFT:
                ++targetX;
                --targetY;
                break;
            case LEFT:
                --targetY;
                break;
            case UPPER_LEFT:
                --targetX;
                --targetY;
                break;
            case UP:
                --targetX;
                break;
            case UPPER_RIGHT:
                --targetX;
                ++targetY;
                break;
            // otherwise we aren't moving

        }

        return immediateArea[targetX][targetY];

    }

}

Brian J

Posted 2014-04-20T14:23:10.060

Reputation: 653

I also learned that Java enums are pretty much full on classes, and I like .NET enums a lot better. – Brian J – 2014-06-22T15:27:27.980

0

NaiveBot (in Ruby)

Here is a very simplistic bot to get the egg rolling (we want to hit those 7 submissions quick, right?). My Ruby isn't very idiomatic so this code may make proper rubyists cringe in pain. Read at your own risk.

input = $<.read
$data = input.split("\n")

def is_egg x, y
    $data[y+2][x+2] == 'o'
end

def is_wall x, y
    $data[y+2][x+2] == '#'
end

def is_empty x, y
    $data[y+2][x+2] == ' '
end

def is_player x, y
    $data[y+2][x+2] == '*'
end

if (is_egg(-2,-2) || is_egg(-2,-1) || is_egg(-1,-2)) && !is_wall(-1,-1) || is_egg(-1,-1)
    dir = 1
elsif is_egg(0,-2) && !is_wall(0,-1) || is_egg(0,-1)
    dir = 2
elsif (is_egg(2,-2) || is_egg(2,-1) || is_egg(1,-2)) && !is_wall(1,-1) || is_egg(1,-1)
    dir = 3
elsif is_egg(2,0) && !is_wall(1,0) || is_egg(1,0)
    dir = 4
elsif (is_egg(2,2) || is_egg(2,1) || is_egg(1,2)) && !is_wall(1,1) || is_egg(1,1)
    dir = 5
elsif is_egg(0,2) && !is_wall(0,1) || is_egg(0,1)
    dir = 6
elsif (is_egg(-2,2) || is_egg(-2,1) || is_egg(-1,2)) && !is_wall(-1,1) || is_egg(-1,1)
    dir = 7
elsif is_egg(-2,0) && !is_wall(-1,0) || is_egg(-1,0)
    dir = 8
else
    dir = rand(8) + 1
end

attack = 'N'
puts "#{dir}
#{attack}
"

Run with ruby naivebot.rb.

I'm simply hardcoding a few cases, where an egg is visible and not obstructed by a wall. It doesn't even go for the closest egg, but picks the first move that makes sense. If no such egg is found, the bot makes a random move. It disregards all other players and never attacks or counters.

Martin Ender

Posted 2014-04-20T14:23:10.060

Reputation: 184 808

0

WallFolower

(deliberate pun) in Python 3:

import sys
import random

#functions I will use
dist       = lambda p1,p2: max(abs(p2[1] - p1[1]), abs(p2[0] - p1[0]))
distTo     = lambda p    : dist((2,2), p)
cmp        = lambda x,y  : (x > y) - (x < y)
sgn        = lambda x    : (-1,0,1)[(x>0)+(x>=0)]
move       = lambda p    : (sgn(p[0] - 2), sgn(p[1] - 2))
unmove     = lambda p    : (p[0] * 2 + 2, p[1] * 2 + 2)
outputmove = lambda p    : (1,2,3,8,9,4,7,6,5)[(sgn(p[0] - 2) + 1) + 3*(sgn(p[1]-2) + 1)]
def noeggfinish(move):
    print(outputmove(unmove(move)))
    print('ACN'[random.randint(0, 2)])
    print("1"+move)
    sys.exit(0)

#beginning of main body
view    = [list(l) for l in map(input, ('',)*5)] #5 line input, all at once.
memory  = input() #currently used only as last direction moved in a tuple
eggs    = []
enemies = []
for y in range(5):
    for x in range(5):
        if   view[y][x] == 'o': eggs    += [(x,y)]
        elif view[y][x] == '*': enemies += [(x,y)]

eggs.sort(key = lambda p:distTo(p)) #sort by how close to me they are.

tiedeggs = []
end = 0
for egg in eggs[:]:
    if end:break
    for enemy in enemies:
        exec({
            -1: 'eggs.remove(egg)',
             0: 'tiedeggs += egg',
             1: 'end=1'
        }[cmp(dist(enemy, egg), distTo(egg))])
        if end:break
if eggs:
    print(outputmove(eggs[0]))
    print('N')              #no attack here
    print("0"+move(eggs[0]))
    sys.exit(0)
elif tiedeggs:
    print(outputmove(tiedeggs[0]))
    print('N')              #no attack here
    print("0"+move(tiedeggs[0]))
    sys.exit(0) 
#now there are no eggs worth going for
#do a LH wall follow

lastmove = eval(memory[1:]) #used to resolve ambiguity
if lastmove[0] and lastmove[1]:
    lastmove[random.randint(0,1)] = 0 #disregard diagonal moves
if eval(memory[0]):
    exec("check=view[%n][%n]"%{(0,-1):(0,0),(1,0):(4,0),(0,1):(4,4),(-1,0):(0,4)}[lastmove])
    if check == '#':
        noeggfinish(lastmove)
    else:pass
#currently unimplemented
#move randomly
noeggfinish(tuple([(x,y) for x in [-1,0,1] for y in [-1,0,1] if (x,y) != (0,0)))

Moves to an egg if there is an egg in sight, but only if it is closer to that egg than another robot. If there is a tie in distance, it goes for it anyways. Otherwise, does a LH wall follow (not currently well implemented).

Still needs work on the wall follow, but I'll post this here anyways.

Justin

Posted 2014-04-20T14:23:10.060

Reputation: 19 757

1

When I run your bot with the tester.py, I get this error in the console: http://pastebin.com/cT5xGdSW

– starbeamrainbowlabs – 2014-04-21T11:25:43.787

Same here. Could you look into that? I'd like to test my new bot against this. – Martin Ender – 2014-04-23T23:37:21.063

@m.buettner What happens if you change sys.exit(0) to exit(0)? Also, I do need to work on this (right now, it assumes itself is a ), but I don't really have the time. When I do have time, I'll come and fix this. – Justin – 2014-04-24T00:12:34.440

@Quincunx unfortunately, that didn't change anything. – Martin Ender – 2014-04-24T09:16:39.580