31
\$\begingroup\$

This is the Grid Game:

Example game board

It's a game based on cellular automata, where the aim is to remove all of the pieces belonging to your opponent.

How it works:

  • There are two kinds of piece in the game, cities and walkers.
  • Each player starts with one city (marked with C and a number, which is it's health), which will regularly send out walkers (marked with a number, initially the number 1) in a given direction.
  • The player can change the direction of all of their walkers to be north, south, east or west at any time.
  • When walkers can't go any further, they will stay still and can be joined by other walkers, increasing their number.
  • When 10 or more walkers join up, they become another city. All new cities have 10 health.
  • When walkers meet walkers or cities belonging to the opponent, they deal damage to the opponent equal to their number, and take damage equal to the opponent's number.
  • Damage is dealt to all adjacent opponent pieces.
  • There is no way to replenish the health of a city.
  • The game ends when either player has no pieces remaining, or when a clear stale-mate is reached.

Because this question is already very long, I've attempted to write a more detailed description of the game, addressing specific queries about it in this wiki page.

The Challenge

To write a bot to play Grid Game, and defeat as many rival bots as possible.

  • A bot is some code which will be run on each turn of the game.
  • It can only be JavaScript, sorry.
  • The size of the code is immaterial.
  • An object named api will be provided as an interface to the player from your bot.
  • In this iteration of the challenge, there is no way for your bot to know what it's opponent is doing. The challenge is to write a proactive (not reactive) strategy.

Forbidden:

  • Interacting with GridGame except via the documented api methods.

The API

  • api.turn() - Returns the numbered turn the game is on.
  • api.towardsX() - Aim your walkers towards the opponent on the East-West axis.
  • api.towardsY() - Aim your walkers towards the opponent on the North-South axis.
  • api.awayX() - Aim your walkers away from the opponent on the East-West axis.
  • api.awayY() - Aim your walkers away from the opponent on the North-South axis.
  • api.random_direction() - Aim your walkers in a randomly selected direction.
  • api.north() - Alias of awayY. North for green player, South for red player.
  • api.south() - Alias of towardsY. South for green player, North for red player.
  • api.east() - Alias of towardsX. East for green player, West for red player.
  • api.west() - Alias of AwayX. West for green player, East for red player.
  • api.wait(turns) - Your bot code will not be run again until turns turns after this method is called.
  • api.spawning_turn() - Returns a boolean which if true if the Cities are going to send out a Walker this turn.

Notes:

  • The last direction function called will define the next direction the walkers move in from that turn until a different direction is called.
  • If no direction function is called walkers will continue in their current direction.
  • Please do not set global variables, as these may conflict with those used by oponents, instead use this.variable_name to communicate between method calls.

How to write a bot

Note: I recommend playing a manual game or two first; to do this, grab a friend to play against and select 'Manual (simple)' in the footer.

To test it:

  • Select an opponent bot as the other colour (or 'Manual' if you'd like to challenge it yourself.
  • Open the developer console (f12) in case of errors in your code.
  • Click Start.
  • Watch the game unfold.
  • Click Reset and repeat the process as desired.

How to deploy your bot

Once you've written a boss you'd like to keep:

  • Go to https://gist.github.com
  • Log in, if not already logged in.
  • (The default page is the form to create a new gist, this is where we want to be.)
  • Name the file 'bot.js'
  • Copy the code into bot.js
  • Save the gist
  • Copy the gist ID (an alphanumeric string found after the last forward slash in the URL).

This Gist ID can now be used to import your bot into Grid Game at any time:

  • Select Gist Id in a coloured box.
  • Paste the ID into the field which appears.

You will need to include this gist ID in your answer.

Note: Grid Game will use the most recent version of bot.js in the gist, updating the gist will update your answer.

Answer Format

Your answer will consist of:

  • A Title consisting of
    • A name for your bot
    • The gist ID (which should be a link the gist).
  • A brief description of the bot's strategy.
  • Any notes you wish to include.

Note: I would like to include answers in the respository's code, partly to sidestep rate limiting on github's gist and partly to include more interesting bots for future users to challenge or modify. Please clearly indicate if you consent to your bot becoming a part of the game code or not.

Example answer:

### The Faraday Cage - d9eb9a70ad0dc0fb1885be0fce032adc

The Faraday Cage is an arrangement of four cities in the player's starting corner, which this bot will attempt to build, which then allows it to repeatedly send two 9's towards the opponent.

* This is named after Alan Faraday, the elder brother of the game creator, who discovered it while playing the game manually.    
* It has proven difficult to defeat.

Please include this in the repository.

The Tournament

The competition will involve running a match for every permutation of two of the available bots.

There are three possible outcomes to a match:

  • Outright win - A player is completely removed from the board. 3 points to the winner.
  • Timeout win - The game will end if it reaches 3,000 turns. At this point, the winner is determined by the total health count. 2 points to the winner.
  • Draw - If the game reaches 3,000 and the bots have an identical total health, it's a draw. Both players get 1 point.

Notes:

  • The below scores are from the very first working tournament runner. I hope to present the results better in future.
  • Currently this is a single match for each permutation. There will likely be multiple matches in future to smooth out the results for bots which use random functions.
  • I also want to present the results of specific matches in future.
  • I'll try to run it again for new bots, please alert me to changes in existing bots to request a re-run.

Current scores

(Run at 2019/11/12 09:15 UTC)

Detailed results (with links to replay matches) can be found at https://ajfaraday.github.io/grid_game/results/rankings.html

Avi - Intercept and Destroy              60
Brilliand - Line Drive                   60
Brilliand - Galeforce                    57
Brilliand - CBC Goes With Everything     55
william porter - Twin Citites            54
Brilliand - CBC Forever                  51
Brilliand - Feint                        51
Brilliand - Cage Bar Cutter              49
Brilliand - Parry and Slice              48
Avi - Hocus Pocus(!?)                    48
Alion - Evolvor: First Encounter         47
Alion - Evolvor: Overnight               45
Brilliand - Backstabber                  42
BradC - Sweeping Endgame                 36
BradC - Quad Rush                        35
Alion - Doombeam                         33
Alion - Slideout                         31
AJFaraday - Faraday Cage                 28
Alion - Zerg Rush                        25
BradC - Double Barrel                    22
Alion - Weirdflow                        21
Alion - Rushdown                         15
AJFaraday - Rotate                       12
AllirionX - 3 Base rush                   9
AJFaraday - Orbit                         8
AJFaraday - All Towards                   3

(Thanks to @brilliand for correcting the unexpected interactions between bots in the tournament runner.)

——

Chat room for this challenge

\$\endgroup\$
  • 7
    \$\begingroup\$ Since we're using computers and they are fast, does the tournament really have to be single-elimination? \$\endgroup\$ – my pronoun is monicareinstate Oct 21 at 12:28
  • 1
    \$\begingroup\$ Based on running a sample game, a few questions: walkers spawn every 3 ticks, yeah? Walkers are stopped by their own cities, yeah? What happens if there's two green cities in a row and try to spawn? Is one walker lost? Two walkers collide and they do damage orthogonally or diagonally? \$\endgroup\$ – Veskah Oct 21 at 12:29
  • 5
    \$\begingroup\$ This seems to be missing a lot of critical information: for a start, how initial board positioning works, what stops walkers going any further, how turns work (simultaneous or sequential? What's the API which a bot must implement to be invoked each turn?), and the full signatures for the methods in the controller's API. \$\endgroup\$ – Peter Taylor Oct 21 at 15:18
  • 9
    \$\begingroup\$ The question should be self-contained. If we have to reverse engineer the controller to learn how to write an answer, the question has failed to fulfil its purpose. \$\endgroup\$ – Peter Taylor Oct 21 at 16:02
  • 1
    \$\begingroup\$ @AJFaraday I'd recommend looking at past KotHs. I am biased, but Formic Functions is a good example of a relatively well-handled ranking system, though here it could be simplified significantly, since it's a series of 1v1 games. Having a livestream is unheard of. It doesn't sound like too bad of an idea initially, but considering the fact that you should mark an answer at the end really makes it suboptimal. \$\endgroup\$ – Alion Oct 21 at 21:08

23 Answers 23

12
\$\begingroup\$

Doombeam - 496367ff51c27dc62ebdc473cd14f333

Time for a tryhard entry. Sets up a massive 12-city railgun and fires it off straight at the spawn point. Even if some of the cities get destroyed before the setup is complete, it still has enough firepower to devastate everything in its path. Additionally, after the far corner is filled with its cities to the brim, it clears up any potential leftovers, as a countermeasure to entries that escape the spawn point.

const turn = api.turn();
if (turn === 0) {
    this.generator = (function* () {
        yield* [[0, 30], [1, 30]];

        for (let i = 0; i < 10; ++i) {
            yield* [[2], [0, 2]];
        }

        for (let i = 0; i < 4; ++i) {
            yield* [[3], [1, 2]];
        }

        yield* [[3], [2, 4], [1, 4]];

        while (true) {
            for (let i = 0; i < 30; ++i) {
                yield* [[3], [2, 2]];
            }

            for (let i = 0; i < 3; ++i) {
                yield [1, 42];
                yield [0, 51];
            }
        }
    })();

    this.nextCall = 0;
}
if (turn === this.nextCall) {
    const [dir, delay = 1] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

I do consent to the inclusion of this bot in the repository.

\$\endgroup\$
  • \$\begingroup\$ Wow! This is brilliant! \$\endgroup\$ – AJFaraday Oct 21 at 20:55
  • \$\begingroup\$ The "build a wall then fire diagonally" strategy seems very effective, since it attacks the enemy "base" so directly and so quickly. Nice work. \$\endgroup\$ – BradC Oct 22 at 15:38
6
\$\begingroup\$

Cage Bar Cutter - 49d7afbe8bb6d542acc871ac40d12e83

No more faraday cages!

Similar to Zerg Rush, but tuned to prevent Faraday Cages from growing at all (in either direction). In the spirit of this being a trivial bot, it makes no attempt to clean up bots that escape to the corners (but most can't manage that anyway).

const turn = api.turn();
const opening = "EEESSSEEESSEEEEEEEEEESSSEEESSSENEEENSNSSSSEEEEEEEEESSSEEESSEEEESE";
if(turn < opening.length) {
    switch (opening[turn]) {
        case 'W':
            api.awayX();
            break;
        case 'N':
            api.awayY();
            break;
        case 'E':
            api.towardsX();
            break;
        case 'S':
            api.towardsY();
            break;
    }
} else if(turn >= 120) {
    if(api.spawning_turn()) api.towardsY();
    else api.towardsX();
}

I do consent to the inclusion of this bot in the repository.

\$\endgroup\$
  • \$\begingroup\$ This is scary effective, not only against Cage-likes. \$\endgroup\$ – Alion Oct 25 at 7:29
  • \$\begingroup\$ Remarkable! Fantastic work! \$\endgroup\$ – AJFaraday Oct 25 at 8:05
  • \$\begingroup\$ Very good at what its designed to do. \$\endgroup\$ – BradC Oct 25 at 15:12
5
\$\begingroup\$

Slideout - 056b16e0dc85ee2f13cc6061cf8162ca

Builds on the Faraday Cage idea by increasing the total amount of walkers generated per 3 turns to 6.

const turn = api.turn();
if (turn === 0) {
    this.generator = (function*() {
        yield* [0, 1, 3].map(i => [i, 30]);

        while (true) {
            yield* [[2, 25], [3, 8]];
        }
    })();

    this.nextCall = 0;
}
if (turn === this.nextCall) {
    const [dir, delay] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

I do not consent to the inclusion of this bot in the repository.

\$\endgroup\$
  • 6
    \$\begingroup\$ I was wondering why all the current submissions looked so similar. Then I realized that it was all by the same user \$\endgroup\$ – Embodiment of Ignorance Oct 22 at 3:03
  • 2
    \$\begingroup\$ @EmbodimentofIgnorance Sorry, I got a bit carried away :P Hopefully others join in soon. \$\endgroup\$ – Alion Oct 22 at 7:27
  • \$\begingroup\$ I had to learn this to beat Faraday's Cage by hand. Name proposal - Davy's Cannon \$\endgroup\$ – Varad Mahashabde Oct 22 at 16:32
  • 1
    \$\begingroup\$ This bot is underrated - it is the only one consistently giving my new ideas trouble. I think it is the larger runners you build up then send around the edges. \$\endgroup\$ – BradC Oct 23 at 1:33
5
\$\begingroup\$

Zerg Rush - 1f8b3963656f9e15577f886e0125a343

Oh boy, here we go... Of course a Zerg Rush would work. Why wouldn't it, right? It makes me feel incredibly dirty, but it had to be done.

const turn = api.turn();
if (turn === 0) {
    this.generator = (function* () {
        while (true) {
            yield* [[3], [2, 2]];
        }
    })();

    this.nextCall = 0;
}
if (turn === this.nextCall) {
    const [dir, delay = 1] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

I do not consent to the inclusion of this bot in the repository.

\$\endgroup\$
  • 1
    \$\begingroup\$ Strangely, this will consistently draw against “always towards”, but the other will have a 6 behind Zerg Rushes base. \$\endgroup\$ – AJFaraday Oct 21 at 22:24
  • \$\begingroup\$ @AJFaraday what do you mean '6 behind'? \$\endgroup\$ – Varad Mahashabde Oct 22 at 16:34
  • 2
    \$\begingroup\$ @VaradMahashabde Play this bot against "All Toward" in the demo, one of the bots slips 6 runners past the other before the runners start colliding and cancelling out. \$\endgroup\$ – BradC Oct 22 at 16:41
  • \$\begingroup\$ @BradC ZergRush attacks on a more direct angle, so gets to AllTowards quickly \$\endgroup\$ – Varad Mahashabde Oct 22 at 16:52
  • 1
    \$\begingroup\$ @BradC exactly what I meant. Thanks for clarifying \$\endgroup\$ – AJFaraday Oct 22 at 16:55
5
\$\begingroup\$

Double Barrel - 7d0a88c1533fc89b2ee26484bbcafc59

Makes a second city and immediately opens fire diagonally, catches lots of bots during setup.

if (api.turn() < 29) {
   api.awayY();
} else if (api.turn() % 3 == 2) {
   api.towardsY();
} else {
   api.towardsX();
}

You can include this bot in your code if desired.

\$\endgroup\$
4
\$\begingroup\$

Intercept and Destroy - 3dcc9463f47626a217a5a51762f02fe6

An improved version of Cage Bar Cutter, intercepting creation of Faraday Cage-like structures. After attempting interception, escape to the corner and attempt to build on the opponent's side. Aggressive attackers will not target themselves, so you can build up there. Non-aggressive builders will have been reasonably interrupted by the interception attempt. After some buildup, turn around and destroy everything.

At the moment of posting, this bot achieves a win against every other posted bot in under 1000 turns. Weirdflow has the dubious distinction of lasting the most turns (808) against this strategy.

const turn = api.turn();
if (turn === 0) {
    this.generator = (function*() {
        yield* [[2, 3], [3, 3], [2, 3], [3, 2], [2, 10], [3, 3], [2, 3], [3, 3], [2, 1], [1, 1], [2, 3], [1, 1], [3, 1], [1, 1], [3, 4], [2, 9], [3, 3], [2, 3], [3, 2], [2, 4], [3, 1]];
        yield* [0, 3, 2].map(i => [i, 36]);

        while (true) {
            for(let i = 0; i < 4; i++)
            {
                yield* [[2, 25], [3, 8]];
            }
            for(let i = 0; i < 4; i++)
            {
                yield* [[0, 25], [1, 8]];
            }
            yield* [[1, 50]];
        }
    })();

    this.nextCall = 0;
}
if (turn === this.nextCall) {
    const [dir, delay] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

As another fun little thing, here's what happens when you run this bot against itself for 4492 turns:

I do consent to the inclusion of this bot in the repository.

\$\endgroup\$
  • \$\begingroup\$ Nice work. Looks very effective. \$\endgroup\$ – AJFaraday Oct 28 at 9:25
  • 1
    \$\begingroup\$ It even takes out Cage Bar Cutter itself :) \$\endgroup\$ – Avi Oct 28 at 12:58
  • \$\begingroup\$ Well done on currently being in the lead. \$\endgroup\$ – AJFaraday Oct 28 at 13:55
  • \$\begingroup\$ Now I’m trying to work out which flag it draws :p \$\endgroup\$ – AJFaraday Oct 29 at 21:28
4
\$\begingroup\$

Twin Cities - 46b9d27b1994c35a8ef214c1b2067609

Starts off with a corner start and then makes use of how attacks work to return fire before building up it's own forces. Beats most bots, loses to others.

//Twin Cities
const turn = api.turn();

if (turn < 31) {
    switch(turn % 2) {
        case 0:
            api.awayY();
            break;
        case 1:
            api.awayX();
            break;
    }
} else if (turn < 80) {
    switch(turn % 3) {
        case 0:
            api.towardsY();
            break;
        case 1:
            api.towardsX();
            break;
        case 2:
            api.towardsX();
            break;
    }
} else if (turn < 127) {
    api.towardsX();
} else if (turn < 246) {
    api.towardsY();
} else if (turn < 350) {
    api.awayX();
} else if (turn < 400) {
    api.towardsY();
} else if (turn < 500) {
    api.towardsX();
} else {
    const late = turn % 200;
    if (late < 50) {
        api.awayY();
    } else if (late < 100) {
        api.awayX();
    } else if (late < 150) {
        api.towardsY();
    } else if (late < 200) {
        api.towardsX();
    }
}

Feel free to include it in your repository.

Edited: Simpler initial phase, also dodges feint and hocus pocus now.

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to the fray! I'm at work right now, but I'll try and re-run the tournament before I head home so we can see how it does. \$\endgroup\$ – AJFaraday Oct 29 at 16:01
  • \$\begingroup\$ Very good start, joint second! If you're interested, here's it's results for every match... ajfaraday.github.io/grid_game/results/… \$\endgroup\$ – AJFaraday Oct 29 at 16:57
  • \$\begingroup\$ @AJFaraday It seems to show quad rush as a loss, but the match show differently? \$\endgroup\$ – william porter Oct 29 at 17:05
  • 1
    \$\begingroup\$ Sorry about that, for the time bring the work around is to copy-paste the code from the answer. \$\endgroup\$ – AJFaraday Oct 29 at 18:37
  • 1
    \$\begingroup\$ I've just updated the cache, it should be up to date now. \$\endgroup\$ – AJFaraday Oct 29 at 20:01
3
\$\begingroup\$

Weirdflow - 8f82f8a5fd15fc29e60b9cce4343309c

This was an attempt at a very clean bot that turned into an incredibly sloppy counter to Rushdown.

const turn = api.turn();
if (turn === 0) {
    this.generator = (function*() {
        for (let i = 0; i < 10; ++i) {
            yield* [[0], [2, 2]];
        }

        for (let i = 0; i < 5; ++i) {
            yield* [[1, 2], [0]];
        }

        yield* [[3, 2], [0, 4]];

        while (true) {
            for (let i = 0; i < 5; ++i) {
                yield* [[1], [3, 2]];
            }
            yield* [[2, 3], [3, 3], [0, 6]];
        }
    })();

    this.nextCall = 0;
}
if (turn === this.nextCall) {
    const [dir, delay = 1] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

I do not consent to the inclusion of this bot in the repository.

\$\endgroup\$
  • 1
    \$\begingroup\$ I like the look of this. If it could go on the offensive when there’s 3 or 4 rows of cities, it could be a massive offensive. (I was watching it against the Faraday Cage) \$\endgroup\$ – AJFaraday Oct 21 at 20:52
  • \$\begingroup\$ As OP said, this has potential, but Faraday's Cage just doesn't take no prisoners, and this smells of a person who farms to a lvl10 Town Hall in Clash of Clans \$\endgroup\$ – Varad Mahashabde Oct 22 at 16:29
3
\$\begingroup\$

Sweeping Endgame - 3f69bdf2be37886ff396d0c485007e80

More complex bot, with a setup phase, a sweeping mid-game strategy, and an endgame that covers all corners and directions.

//Sweeping Endgame v2
this.t = api.turn();

//initial city setup
if (this.t < 29) {
   api.awayY();
} else if (this.t < 59) {
   api.awayX();

//mid-game loop, now attempts to put cities in the two off-corners
} else if (this.t < 400) {
  if (this.t % 200 < 14) {
     api.towardsY();
  } else if (this.t % 200 > 13 && this.t % 200 < 17) {
     api.awayX();
  } else if (this.t % 200 > 100 && this.t % 200 < 122) {
     api.towardsX();
  } else if (this.t % 200 > 121 && this.t % 200 < 126) {
     api.awayY();
  } else if ((this.t % 8) % 3 == 1) {
     api.towardsY();
  } else {
     api.towardsX(); 
  }

//endgame, now sequential, not random
} else {
   if (this.t % 200 < 40) {
      api.awayY()
   } else if (this.t % 200 < 50) {
      if (this.t % 2 == 0) {
        api.towardsY();
      } else {
        api.awayX();
      }
   } else if (this.t % 200 < 90) {
     api.towardsX()
   } else if (this.t % 200 < 100) {
      if (this.t % 2 == 0) {
        api.awayY();
      } else {
        api.awayX();
      }
   } else if (this.t % 200 < 140) {
     api.towardsY()
   } else if (this.t % 200 < 150) {
      if (this.t % 2 == 0) {
        api.awayY();
      } else {
        api.towardsX();
      }
   } else if (this.t % 200 < 190) {
     api.awayX()
   } else {
      if (this.t % 2 == 0) {
        api.towardsY();
      } else {
        api.towardsX();
      }
   }
}

v2 makes the following changes:

  1. Mid-game now deliberately attempts to get a couple of cities in the off-corners. This is crucial to "get behind enemy lines" for simple bots like Quad Rush.
  2. End game is no longer random, instead it goes through a prescribed sequence of straight and diagonal moves to clean up the board.
\$\endgroup\$
  • \$\begingroup\$ Quad Rush is another bot this is losing to. \$\endgroup\$ – Num Lock Oct 23 at 10:55
  • \$\begingroup\$ @NumLock Updated to v2, now beats Quad Rush, and most others (except for Slideout, still) \$\endgroup\$ – BradC Oct 23 at 16:29
3
\$\begingroup\$

Evolvor: First Encounter - c0382c11979adc1f47773714ffc8376f

This is the first in what I hope becomes a series of bots that result from a genetic algorithm. Does some really weird things which result in tons of cities and then... usually can't convert it into a victory.

switch ("WNSNNNWSNWNWNWNWWNNWWNWNNNWWWNEENNNWWNNWWWWWNWWNWNWWSWENEENNENNESSSSWSWWSWWSWWSSWSNWSWWSWSSWWSWWSWWEESESSEESESSESSESWESSEWWESWESSSSSNNWNWWSWWNNWNWWEWWSWSEWWNWEEENEESEENEEEEEEEEEEENEEEEEEEESEENESEENEEESEEEEEEENEEEEEEEESEESEENEEEEEEEEENEEEESEEENEEEEEEEEEEEEEEEEESEENEENENEEESEEEEESENEEESENEEEEEESEENEEEENEEEEESEENEEEEEENEEEESEEEEENEEENENEEEEESEENEEEEEEEEESNEEEESEEEEEEENEENEEEEEWEEENEEEEENEWSEEEENNENEENEESEENEEWNEEEEEEEEWENSEENEESEEEEENENEEESEESEENEEENESENEESEWSNEENEWSENEEEEENSEEEENEEEEEENEESENEESNENWEENENSEEEENNNEEESWESWEESENENESNEEEENSNEEESEEEEEEESSEESEEEEEEESNENEEWENENNSEENEEWEEEEENWEESENNEESENNENSENWENEENWESENENNNNEENEWSENEENEEWWEEWENNWNNEEEEWSEEWESESESEEEENNWEWSSSENSENEEESESEENNNSEEEEESESSEEENENENEWEWNWSEESSENNNESSSENNENWEEEWNWNENSEWESESSEEEEENWSENEESEWNEEEWEWSEEWNNEEEENSENNESNNESNEENSEENWNNESESSWWWENEWENNSSENEESNSWWNNNWENWNNESEENEEENEESNEWSSENWWWNEEEESESWSSEWNNENWENNWNSESEEESESNSSESENWSESENNEWENNEENEESSNENEESSNWNESNENSESWWEENWWNEEEENESSEEESWWSWWEESWWEWSEENWEWEWNNSESSSNEESESNSEESSEEEEWSSSNSNSSSNNSESESSSESNWWEWENNENNNNWWEENWSNWWWSWNWWSEEEWEEWWEWENNSSEEEESNSESWENNNWENSWWNNENEESEWEWSEESEWEEWENSWNNSNENSWNWSENNENNNESNEWSEENSNNEWEENNSEEESSNEENWEESWEEWSEWWEWWWESESSSESEWEEWEESNNSNWWSNNENSSESWEEWNESENSEEEESEENEWENWSEEEEEWWEEESSNSWSEENWSESEWEWEESSNSNNNSWNWEWSWEESWSEWSNNWNNENNNNSESENNWEENSWWENSWNESNNSENWWWNESSSSENENWNENNEEEESWSWWNSEEWNNESENSENSWNWSNWNSSSSSSESSNESEWNESEWWNEWNENNESWSSEEWEEWNSENENESWEENESWWNESNEEWSSEWENEWEESSSENNWNNNESWEWWSESWNSSNENWEWWESSESSNEENNSSSSESNWEENSWSWEWEEWEWWSSESSNEWWEENWSSENWENSSWNSENSEEWNWENWNWENEENWWWEEWNWEWWNNNSSNWENWNENENNWNNWSESSESWNNENENWSSESWEEWEESNSWENEENSSWESEENWWEWNNEEENEESWENESNWNWEEWNWEESWWEEESWENENSSWENNWSWWNSWNSESESSNEENEWEENWENNWWWNSWWEESSWNNNSWNWESEESENEESEENWNNWWESSSSESNESWNSWWNSNEWEWEENSEWSESSENSWNENSESNNSWWSWEEESSNSESNEEEWEEWNSWNEENSENSWENESEESNNNEESWSNNSNWNSSSSEEESWSSSSNSNSESENENSNESSNWNSWNSSENESSSWEWNSWENSEWWSWNNWEEESESENSNNNSWNENNSSSNEWSSWEEWWWEWNSWNNEWWWENENENWSWWWEESEENWSWENESEESWNEWEESEWEWNESEWWNWWSWWNWSEEEWNSNNSENWSWSWSSWWNWWSESSSNEESWENNEENEEWEWNSENWSNSWNNSWSWSESWEWNNSNNNEWWWNWSNNENSNENNNNWNWESWWEEWNNWWNNEEWNSNNNNSNWSSSNEWEWWENNESNWNNNSWNWEWWSSSWSEWWESEEWSNNSESEEWEEWSNWENWWWSNWSESNENNEESENSNWWNWNNWEWSSWSSSNSEESNSNNSEEWNSSWWWEEWWNNESNWENSWNEWNSEWWEWESNWWNENWWEWNEWEESNNEEESNENESWEEWNSSNESSENWSENSWWEEWSSWWEWSNESSENWESSSSWWENSSENWNNWEESWWNNNSEEESSSENSESSNSSSSSWNWENESNWNESWNSNESSENESSSWWNEWNESSENNWNEEEEEWNSWWSWWSSNEWEESSWESENSWEESNWEWNEENSENESNNSEEEWENESENWWNSESENWWSWESNSWSESEWSENEWEWEWSENESSSENSNEEWESSNNESENEWENWEEEESWWNESNESSSNNEWNNENEESEESNENSWESNNWWSENNWNNNWWEESESNNWNWENNEWSSSNSNNENNNWSSWWSNWSNEWNNWSEEWNNWESNNNWENWNSENNWENWENSWNNWNWNENNWSNNWWWWWSESWWEEEEESEENESEENEENWWNWEENESSSWSSSNNWWENSWNWWENSESSSSSSWENSNWSWENEWENNWNWNSWWNNSWSWSWWWNWEEWNNESSSWSEEENEWSNWWEWEWENWWEENESNWWNSEWNEENNSNEWSWESESSWEWWWEWWWNWNESSNNWSENWSNNSENSSESWWWSSESESWWSESSSENSENEWESSWESSNNWNSEWWWWWNWSEWSENNESWNEEWWEENNNEESWSWSESNESWNSNNSWWSENEENENSSWWWWEEEWWNEEEWENNSWEEWNWWNSNSNWSNNEENESSWEENNNEEEENNWSSWENSSNWSSNSNWNENESEWNWWEEENEEWESNESNEES"[api.turn()]) {
    case 'W':
        api.awayX();
        break;
    case 'N':
        api.awayY();
        break;
    case 'E':
        api.towardsX();
        break;
    case 'S':
        api.towardsY();
        break;
}

I do not consent to the inclusion of this bot in the repository.

\$\endgroup\$
  • \$\begingroup\$ I fixed some obvious early inefficiency and this beat both Line Drive and Sweeping Endgame, so this bot is viable already. (It looks like it may have hit upon a more efficient way to build a line drive.) \$\endgroup\$ – Brilliand Oct 23 at 22:14
3
\$\begingroup\$

Line Drive - 54e4de5b03423cc19a1ec0e22f32a981

Attempts to occupy an entire column of the grid, then unleash an unstoppable barrage in the x-direction.

EDIT: Now biases its barrage toward one wall and changes direction more rapidly, allowing it to beat some bots that the previous version couldn't beat.

const turn = api.turn();
if (turn === 0) {
    this.generator = (function* () {
        yield* [[0, 24], [1], [0], [3], [0, 3]];

        for (let i = 0; i < 9; ++i) {
            yield* [[1], [2], [0]];
        }
        yield [1, 3];

        for (let i = 0; i < 10; ++i) {
            yield* [[3], [1, 2]];
        }

        for (let i = 0; i < 4; ++i) {
            yield* [[2], [0, 2]];
        }

        yield* [[2], [3, 4], [0, 4]];

        for (let i = 0; i < 4; ++i) {
            yield* [[2], [0, 2]];
        }

        yield* [[2], [3, 2], [0], [3, 2], [0], [3, 2], [0, 3]];

        while (true) {
            for (let i = 0; i < 60; ++i) {
                yield* [[2, 2], [1]];
            }
            for (let i = 0; i < 40; ++i) {
                yield* [[3, 2], [2]];
            }
            for (let i = 0; i < 60; ++i) {
                yield* [[0, 2], [3]];
            }
            for (let i = 0; i < 40; ++i) {
                yield* [[1, 2], [0]];
            }
        }
    })();

    this.nextCall = 0;
}
if (turn === this.nextCall) {
    const [dir, delay = 1] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

I do consent to the inclusion of this bot in the repository.

\$\endgroup\$
  • \$\begingroup\$ I'm having trouble loading this entry from its gist ID. The file is named LineDrive.js instead of bot.js. \$\endgroup\$ – Alion Oct 23 at 7:29
  • \$\begingroup\$ @Brilliand I'm afraid the name bot.js is significant. \$\endgroup\$ – AJFaraday Oct 23 at 9:01
  • \$\begingroup\$ @AJFaraday I've changed the filename. \$\endgroup\$ – Brilliand Oct 23 at 18:19
  • \$\begingroup\$ @Brilliand great! I’ll include it in the cache when i look at it next. \$\endgroup\$ – AJFaraday Oct 23 at 18:20
  • \$\begingroup\$ @Brilliand It's a bit complex, I found in early tests that it's quite easy to hit the 50 calls to the gist site and then break the app for the next hour. Not great. Use Custom for dev purposes and I'll update the cache when I can. I'm in the chat now if you want to discuss further. \$\endgroup\$ – AJFaraday Oct 24 at 10:50
3
\$\begingroup\$

Hocus Pocus(!?) - 966e8f3ad189b9535c2e1fad3ffc065a

Weird strategy that I'm unable to describe - it's probably(?!) an amalgam of Feint, Two Cities (??!) and whatever else I can't remember. At the moment of posting, (I think it?) beats everything but the Evolvors and Intercept & Destroy. Uses anti-CBC at the beginning, then hocus pocus(!?) strategy. Edit: Also loses to Backstabber

const turn = api.turn();
if (turn === 0) {
    this.generator = (function*() {
        yield* [[3, 8], [2, 16], [3], [0], [1], [0, 27]];
        while (true) {
            yield* [[3, 36], [2, 36], [1, 36], [0, 36]];
            for (let i = 0; i < 20; ++i) {
                yield* [[2, 2], [1]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[2, 2], [3]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[0, 2], [1]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[0, 2], [3]];
            }
            for (let i = 0; i < 10; ++i) {
                yield* [[1], [3, 2]];
                yield* [[2], [0, 2]];
                yield* [[3], [1, 2]];
                yield* [[0], [2, 2]];
            }
        }
    })();

    this.nextCall = 0;
}
if (turn === this.nextCall) {
    const [dir, delay = 1] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

I do consent to the inclusion of this bot in the repository.

\$\endgroup\$
  • \$\begingroup\$ Nice to see folks being honest about uncertainty :p \$\endgroup\$ – AJFaraday Oct 29 at 18:38
  • 1
    \$\begingroup\$ Likes having nice staring contests with Doombeam. They don't end well for Doombeam. \$\endgroup\$ – Alion Oct 29 at 18:48
  • \$\begingroup\$ This is really quite entertaining to watch. Close call with Doombeam, and it dances when pitted against itself. \$\endgroup\$ – AJFaraday Oct 29 at 20:09
2
\$\begingroup\$

Rushdown - 5a989c80bf1bbef32c848f248aa55dcb

Focuses on building up a bit of firepower and then rushes down what it expects to be the enemy base. Made as a counter to the Faraday Cage and similar. As a bonus, it looks like it's shuffling a deck of cards during the first phase.

const turn = api.turn();
if (turn === 0) {
    this.generator = (function*() {
        for (let i = 0; i < 5; ++i) {
            for (let j = 1; j <= 2; ++j) {
                yield* [[2, j], [0, j]];
            }
        }

        while (true) {
            yield* [[3, 34], [1, 1], [2, 16]];
        }
    })();

    this.nextCall = 0;
}
if (turn === this.nextCall) {
    const [dir, delay] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

I do not consent to the inclusion of this bot in the repository.

\$\endgroup\$
2
\$\begingroup\$

3 Base rush - 3f6d1a1461564ace3d7e22cedba08c20

A bot building three cities before launching an indirect attack and proceeding to lose.

if (api.turn() < 29) {
   api.awayX();
} else if(api.turn() < 40) {
    api.awayY();
} else if(api.turn() < 42) {
    api.awayX();
} else if(api.turn() == 42) {
    api.awayY();
} else if(api.turn() < 45) {
    api.towardsX();
} else if(api.turn()<48) {
    api.awayY();
} else if (api.turn() % 2 == 1) {
   api.towardsY();
} else {
   api.towardsX();
}

This bot is not to be included in the repository, as it is only a stepping stone to explore 3 cities openings.

\$\endgroup\$
  • \$\begingroup\$ I edited the title to match the format asked by OP and also added highlighting for your code using <!-- language-all: lang-javascript -->. \$\endgroup\$ – Night2 Oct 23 at 8:34
  • 1
    \$\begingroup\$ @Night2 I didn't know you could do that. It's pretty. \$\endgroup\$ – AJFaraday Oct 23 at 11:29
  • \$\begingroup\$ Nice start; just switching api.turn() % 2 to api.turn() % 3 makes this bot substantially more effective. \$\endgroup\$ – BradC Oct 23 at 13:50
  • \$\begingroup\$ @BradC Well, the attack part is not designed yet, but attacking only diagonally does not allow you to protect from attack on your weak side. This was a poor attempt at improving the defence. \$\endgroup\$ – AllirionX Oct 23 at 20:48
2
\$\begingroup\$

Evolvor: Overnight - 7512fcfcef33bff323d5cdaf1bb833ff

This is utilizing exactly the same evolution code as Evolvor: First Encounter, but with a significant increase to the time provided. As of the time of posting, this only loses to 4 entries - two of them mine (whoops) and all of them rushy. I hope to be able to fix this issue soon.

switch ("NEWWNSNWEWWNNEWWNNNWWWNNNNNNSWWEWNNWNWENWWNWWEWNNNNENNWWNSESSSESESSWWSNSESSSWESWNSWWENNSSESSNSWESWWSWSESWSSWSWSSSNSWEENWEWEEWWSWSSWWSWNEWWEESEESEESEESEEEENEEESEEEEEEEEEEEEENEEEEEEEENEESEEEEENEEEEEEEEEEEEEENEENEEEEEEEEEEEEEEEEENNENEEEEEEEENEEEEEEEEEEEEEENNENNENNENNNNNENEEEEENEEEEEEEEWEEEEEEEEWEENEENEEESEEWEEEESEENWESEESEENEEEEEWEEESNNNENNENNEENENEENENNEENNNNEENNENEEENNNENNEENNENNEENESEEWEEEEEEEEEEEEEENNEENESSEWSENEEWSESEESSESSESSWNNNNENNNNENNNNNENNNNNNENNENNENENNNNNENNNNNNENENNNNNNENENNENNENNNENNENENNNNNENNNNNENNNNNNENENNNWNENNNNNNENNWNENNENNNWNENNENNNNENNNSWEENWNENENNENNNWNWNNENNEWNNNWENWNNNWNEENNWWNWNSSNSNSSEESSWNWESWSSWSESESSESESSSESEESSESNESSESEESESEEESSESEESSESSNSEESEEESSSSWNEESNNNESESSSESEEESEWSSSSSESESSNSNWENESNSESSSSSSSESSSSSWSSNNWSSNESSENSSESEESEWSEENSESWSSSNWESEWENSENNENNWNSSSEWNWWSSSNSESSWSNENSEEENNNNNNENSSNWEWWSSEWSSWNEEWEENSEWNESNESWNSSWWENWSENSWNNNWNNWESESEWWNNNWNWNNEWWSNWNNSWWNWWSENWNSNSWNWSNEWNNNNNNWWWWWSNWNWSSNENWSNNNSNWSNWWNNWWNNWNNSWWNNWWNENNWWSSWWNNNSWENNWWWWWWSWSWSNWNNSSNNNNNSWENWNWWEWNWNNNNWWWNSWWENNNNWNWNSWWWNNSSWNSSNWWNENNNWNWWNNWSESNNNNWWSNNWSWSWEWWNEWWWWWWSNWNNNWWWWNNEWWSEESNSWWWNNENNWWNSNWWNNWEWSWNWEWNWWSENNNWEWWSNWENWSWWWWNNSSENWSWNSNWSWWNNNNESWWNSWNNNWNWWNSWSNNENNSSWWWENSSENWNWWSSWSWWWEWSNEWWNEWWSWWSSSNWSNWEWEEWNNSWESSEESNNWWWWNSNSSNWSSWSNNSNNWSNWNWSWWSWNWEWEEWNNWNEWNSWWWWWSWNEEWWNNNSSNWWNNWWNWSNNWWNEEWESWNNNEWWWWSWWWNNSSWWNNSWSWEWSWWNSNWNESESWWEEWESSSNWEWENWSNNWNSESEEWWWWSWNNNSWNWWNWWWESSWNWNWNWEEWENEWNWSNNSNNWWWSSNNNWNNNSWNNNWSSWEWWENWNSNENEWESWNSWNEWENENSSEWSNNSNNSNNSSWSEWESSEWWSWWNSNNNNEWNWNESEENENNWSENEWNWWSNEENNSNWNNWNNNNWWWENNNEEWWENWWNNENWNNSWNNNEEWSSSSEESWWNESWNWNSWENEESENSENNNWESSNNSNWNSESESNEEENSSWENWEWNSENEENNSNWEEWNWNNEWNENNSSWWNSWSWSENENWENNWNEWWNNWSSSSESWNESSSNSWWNEESNWNNWESWENSWWNWESSWSNEWEENWESWWWSWSEWENNNNEEESSWWWNSWSNSWNSEESSSNEEWNNSSSWSSSWSNWSSSNSWNESWENNWWENNENWSWEWSEWSNWEWWESEWEEESSNEENNSWNWWWSWESSNSSSNNEWENENWNNWSSSWWESNWWSSEWSWEWNWNWSNSNEWEWEENEEWWESSENSSNNNNESNEWSNSSWENNSNNENEWNESNWNWESSWNNSWNNSWEWESSNWEWNWENEWEWESWSNNEWSWSWNEWEWSSWNWSWNSNSWESWNNWWNWNSENWNEWSWNNWNENWNENEEWSNSSSSEWSNNESNSSESESSSWWNWSESSNSSWWWWWSNWNEWESEWNEWESSNENEESNSEEWNSNNEWWWWESESSNEWWSSSNWSSWWNSSSSEWSWWWWSSNWSNWNWEEWSEWESWSENWNSWSSSSSWNWSNEWNWSSSWEWWEWNENESNNSWSSWNWNWNWNWSSSESSSWSWSWSSWSWESWSEESWEENSNNSSNNSSSWWEWSNEWWNNEENNNWSSEWWSESSNWNSEWNWNNNWNESSSSNEEWWENNEESESSNEEWEWEWSWSEWWNEWENWNEWNWENSNNEWSENESSSEESSWENNWESESSSWNNNWWNSNWEWWWEWSWSWESSENWWSENSEWSEWNSWNEENWNWWNSEEWWSWWWWWWNESEESSWEWENNSWWSNWWNSSWWNWNWNWNEWWWSWNNEESWSWWWESSEWNWSWEEWWNSENSWSWNSWWSSEWNEWWWNSNEENEWNNWNWWNSNNSWNWSNWSNNWWEWNWWWNESESNSEWWNENNSEWWWNWWWENWWNSSSEWNWEEEENWSSESEWESWWNSSWEEEEENSNWSWSEWESESSNWNWSENSSSENWWWNWWNENSSENWNWWWEWEENEENEWEWNSENENSSSWNWWSWWSNSESENESENWSSWWEENWWWWWEWSSSWSWESNSEWSSNWSWWWSSEWWEWWWSSSNEWWWWEENNSEEWWESWSSNESEENNSNENSWNNNNEENEWWWEWSEEWWEENWNSSSSWWNNENWNEWSSNENNNENSWSESSWSNENNWSWWWSESESENSNSSENWWSEENWWNSEWSEWNNWSENSNWEWWWNSSESESWSNSSEESWNEEENEEWSNNSWSESENNNWESWSWNNWESEENWWWENWWEWSSWSESWEWENSNEEEESSNWSSWSSNEENNEEEESSWWNWENSWESEWSESNE"[api.turn()]) {
    case 'W':
        api.awayX();
        break;
    case 'N':
        api.awayY();
        break;
    case 'E':
        api.towardsX();
        break;
    case 'S':
        api.towardsY();
        break;
}

I do consent to the inclusion of this bot in the repository.

\$\endgroup\$
2
\$\begingroup\$

Quad Rush - a0a4a9f3c8b8863392f109fdfd52af00

Double barrel x2.

EDIT: Changed the cadence so we end up with a [2] runner and two [1] instead of four [1], which makes a difference in some matchups.

if (api.turn() < 29) {
   api.awayY();
} else if (api.turn() < 59) {
   api.awayX();
} else if (api.turn() % 3 == 0) {
   api.towardsY();
} else {
   api.towardsX();
}

You can include this bot in your code if desired.

\$\endgroup\$
2
\$\begingroup\$

Galeforce - 294c357b051e6e165d18657748d02cfe

Sets up 8 cities, then sprays walkers in various directions. Looks a bit like a Doombeam followed by a Line Drive (and the Galeforce vs. Doombeam matchup comes down to persistence).

const turn = api.turn();
if (turn === 0) {
    this.generator = (function* () {
        yield* [[1, 24], [0], [1], [2], [1, 3]];

        for (let i = 0; i < 9; ++i) {
            yield* [[0], [3], [1]];
        }
        yield [0, 3];

        for (let i = 0; i < 10; ++i) {
            yield* [[2], [0, 2]];
        }

        for (let i = 0; i < 20; ++i) {
            yield* [[3], [2, 2]];
        }

        while (true) {
            for (let i = 0; i < 20; ++i) {
                yield* [[3, 2], [2]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[3, 2], [0]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[2, 2], [1]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[2, 2], [3]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[1, 2], [0]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[1, 2], [2]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[0, 2], [3]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[0, 2], [1]];
            }
        }
    })();

    this.nextCall = 0;
}
if (turn === this.nextCall) {
    const [dir, delay = 1] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

I do consent to the inclusion of this bot in the repository.

\$\endgroup\$
2
\$\begingroup\$

Backstabber - 2d632fb11ea1a7b1b73788d396a6a45d

After making Galeforce, I got to wondering if anything could beat a really persistent Doombeam - one that never stopped firing. None of the existing bots seemed to be able to.

This bot can do it, though, and it beats most of the other bots too!

const turn = api.turn();
if (turn === 0) {
    this.generator = (function*() {
        yield* [[0, 24], [1], [0], [3], [0, 3]];

        for(let i = 0; i < 40; i++) {
            yield* [[1], [2, 2]];
        }

        while (true) {
            for(let i = 0; i < 40; i++) {
                yield* [[3, 2], [2]];
            }
            for(let i = 0; i < 40; i++) {
                yield* [[0, 2], [1]];
            }
            for(let i = 0; i < 40; i++) {
                yield* [[3], [0, 2]];
            }
            for(let i = 0; i < 40; i++) {
                yield* [[0, 2], [3]];
            }
            for(let i = 0; i < 40; i++) {
                yield* [[1], [0, 2]];
            }
        }
    })();

    this.nextCall = 0;
}
if (turn === this.nextCall) {
    const [dir, delay = 1] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

I do consent to the inclusion of this bot in the repository.

\$\endgroup\$
2
\$\begingroup\$

CBC Forever - 9c65942bf924d9bb09e99d22daf0d8d0

An endless loop of inverse CBC. After a while it starts cycling walkers around behind it, to clean up any enemy cities that got into its corner.

This is partly intended as a demonstration of how to do a long inverse CBC, but of course it beats a lot of stuff in its own right.

const turn = api.turn();
const opening =
    "SSSEEESSSEEEEEEEEEESSEEE"+
    "SSSEEESSSEEEEEEESSEEEEEE"+
    "SSSEEESSSEEEESSEEEEEEEEE"+
    "SSSEEESSSESSEEEEEEEEEEEE";
const pattern = "NWSSSSEEESSSWNEESSEEEEEEEEEEEE";
if(turn < opening.length) {
    switch (opening[turn]) {
        case 'W':
            api.awayX();
            break;
        case 'N':
            api.awayY();
            break;
        case 'E':
            api.towardsX();
            break;
        case 'S':
            api.towardsY();
            break;
    }
} else {
    switch (pattern[(turn-opening.length)%pattern.length]) {
        case 'W':
            api.awayX();
            break;
        case 'N':
            api.awayY();
            break;
        case 'E':
            api.towardsX();
            break;
        case 'S':
            api.towardsY();
            break;
    }
}

I do consent to the inclusion of this bot in the repository.

\$\endgroup\$
1
\$\begingroup\$

Feint - cb68f09d808b5de34daf5c45b46f2bea

Briefly dips into a reverse Cage Bar Cutter, then jumps to a corner and tries to get behind the opponent before switching to the main circling strategy.

const turn = api.turn();
if (turn === 0) {
    this.generator = (function* () {
        yield* [[3, 8], [2, 16], [3], [0], [1], [0, 27]];

        let laps = 1;
        while(true) {
            for (let i = 0; i < laps*10; ++i) {
                yield* [[3, 2], [0]];
            }
            laps++;
            for (let i = 0; i < laps*10; ++i) {
                yield* [[2, 2], [3]];
            }
            laps++;
            for (let i = 0; i < laps*10; ++i) {
                yield* [[1, 2], [2]];
            }
            laps++;
            for (let i = 0; i < laps*10; ++i) {
                yield* [[0, 2], [1]];
            }
            laps++;
        }
    })();

    this.nextCall = 0;
}
if (turn === this.nextCall) {
    const [dir, delay = 1] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

I do consent to the inclusion of this bot in the repository.

\$\endgroup\$
1
\$\begingroup\$

CBC Goes With Everything - f904da9534cf91ff2d5d399f59757ebc

Repeats the CBC pattern 5 times, then proceeds to build its own Faraday Cage and perform a stock Galeforce.

6 appears to be the maximum number before it starts losing to variants of itself for being "too persistent"; I picked 5 'cause it's a nice round number close to that.

const turn = api.turn();
const opening = "EEESSSEEESSEEEEEEEEEESSSEEESSSENEEENSNSSSSEEEEEEEEESSSEEESSEEEESE";
if(turn < opening.length*5) {
    switch (opening[turn%opening.length]) {
        case 'W':
            api.awayX();
            break;
        case 'N':
            api.awayY();
            break;
        case 'E':
            api.towardsX();
            break;
        case 'S':
            api.towardsY();
            break;
    }
}
if (turn === opening.length*5) {
    this.generator = (function* () {
        yield* [[0, 30], [1, 30], [2, 30]];

        for (let i = 0; i < 20; ++i) {
            yield* [[3], [2, 2]];
        }

        while (true) {
            for (let i = 0; i < 20; ++i) {
                yield* [[3, 2], [2]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[3, 2], [0]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[2, 2], [1]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[2, 2], [3]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[1, 2], [0]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[1, 2], [2]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[0, 2], [3]];
            }
            for (let i = 0; i < 20; ++i) {
                yield* [[0, 2], [1]];
            }
        }
    })();

    this.nextCall = turn;
}
if (turn === this.nextCall) {
    const [dir, delay = 1] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

You can include this in the repository if you want to, but it's just two of my other bots grafted together.

\$\endgroup\$
  • \$\begingroup\$ Well, it was always going to come down to bots based on other bots. We can probably keep it out of copyright court :p \$\endgroup\$ – AJFaraday Oct 28 at 20:22
1
\$\begingroup\$

Parry and Slice - 472a33460a33c1785a28190c9406e36e

Defends against CBC with a small stack of walkers, then goes for a 3-city buildup because nothing else is fast enough after spending time on shielding. It then moves into a Backstabber variant.

Lategame, it throws in an occasional buildup phase to recover from situations where one of the endless rushers almost finished it off.

const turn = api.turn();
if (turn === 0) {
    this.generator = (function*() {
        for(let i = 0; i < 5; i++) {
            yield* [[3], [1, 2]];
        }

        yield* [[0, 30]];

        for(let i = 0; i < 5; i++) {
            yield* [[1], [0, 2]];
        }

        for(let i = 0; i < 12; i++) {
            yield* [[2], [1], [2, 4]];
        }

        while (true) {
            for(let i = 0; i < 40; i++) {
                yield* [[3, 2], [2]];
            }
            for(let i = 0; i < 20; i++) {
                yield* [[1, 2], [2]];
            }
            for(let i = 0; i < 30; i++) {
                yield* [[0, 2], [1]];
            }
            for(let i = 0; i < 30; i++) {
                yield* [[3], [0, 2]];
            }
            for(let i = 0; i < 40; i++) {
                yield* [[0, 2], [3]];
            }
            for(let i = 0; i < 30; i++) {
                yield* [[1], [0, 2]];
            }
            for(let i = 0; i < 10; i++) {
                yield* [[0], [2, 2]];
            }
        }
    })();

    this.nextCall = 0;
}
if (turn === this.nextCall) {
    const [dir, delay = 1] = this.generator.next().value;
    [api.awayX, api.awayY, api.towardsX, api.towardsY][dir].bind(api)();
    this.nextCall += delay;
}

I do consent to the inclusion of this bot in the repository.

\$\endgroup\$
1
\$\begingroup\$

Orbit - 1ec7b9413c34cd8cd66d5bf28a9537ef

Just quickly threw this together on a whim but...

The concept was to have the first walker keep ringing round the first city and see what happens. Uninterrupted, it keeps a pile of quite high-value walkers floating around until they build a few cities at once. Then keeps building, gradually creeping towards the enemy.

I expect it will do very badly in the tournament. ¯\_(ツ)_/¯

if(api.turn() == 0) {
  api.towardsX()
} else if (api.turn() == 1) {
  api.towardsY()
} else {
  var dirs = ['awayX', 'awayY', 'towardsX', 'towardsY']
  if (typeof api.dir == 'undefined') {
    api.dir = 0;
  }
  if ((api.turn() + 1) % 2) {
    //next dir
    api[dirs[api.dir]]();
    api.dir += 1;
    api.dir = api.dir % 4;
  }
}

I'd like this in the repo, regardless.

\$\endgroup\$
  • \$\begingroup\$ I find it odd that it doesn't mirror itself when I run it against itself. \$\endgroup\$ – william porter Oct 30 at 19:30
  • \$\begingroup\$ Ah, I’ve fallen in to the javascript trap of using ‘this’, ever. If you change ‘this.n’ to ‘api.n’ it will mirror again. \$\endgroup\$ – AJFaraday Oct 30 at 20:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.