Race some Robots
Based on RoboRally, but uses some different/simplified rules
In this KoTH, you will be coding a Python bot that attempts to race around a factory, reaching two specific places before the other bots, who are doing the same thing. The way you'll reach these places - the "checkpoints" - is by sending instructions to the bot, telling it where to move.
The Factory
The factory is represented by a \$13 \times 10\$ 2D list, where each cell has a different component, each represented by a 2 character long string. The factory will be constant for the KoTH, and is the following 2D list (coordinates are shown around for reference):
0 1 2 3 4 5 6 7 8 9 10 11 12
0 [[' ', ' ', '> ', ' ', 'vv', 'C2', ' ', ' ', ' ', ' ', '^^', ' ', ' ' ],
1 [' ', ' ', ' ', ' ', 'vv', ' ', 'lv', '< ', 'l<', ' ', 'R^', '<<', '<<'],
2 [' ', ' ', ' ', '<<', 'R<', ' ', 'v ', ' ', '^ ', ' ', ' ', ' ', '*v'],
3 [' ', ' ', ' ', ' ', ' ', 'lv', 'r<', ' ', 'r^', '< ', '< ', 'l<', ' '],
4 ['PA', ' ', ' ', ' ', 'lv', 'r<', ' ', ' ', ' ', ' ', ' ', '^ ', ' '],
5 [' ', ' ', ' ', ' ', 'v ', ' ', ' ', ' ', ' ', ' ', 'r>', 'l^', ' '],
6 [' ', ' ', ' ', ' ', 'l>', '> ', '> ', 'rv', ' ', 'r>', 'l^', ' ', ' '],
7 [' ', ' ', ' ', ' ', ' ', ' ', ' ', 'v ', ' ', '^ ', ' ', 'R>', '>>'],
8 [' ', ' ', ' ', '>>', '>>', 'Rv', ' ', 'l>', '> ', 'r^', ' ', '^^', ' '],
9 [' ', ' ', '> ', ' ', ' ', 'vv', ' ', ' ', ' ', ' ', 'C1', '^^', ' ']]
We will use compass directions in the explanations to refer to the direction a bot is facing, with "North" being the top of the factory (so \$(0, 0)\$ is the North-West corner).
This is fairly complicated, so we'll go over what each string means:
: This is just a blank square. Nothing special happens.
C1
/C2
: Checkpoints 1 and 2. You must visit Checkpoint 1 first, then Checkpoint 2. The first bot to do both wins.
>
/<
/v
/^
: These are conveyer belts. At the end of each "register" (explained below), they move any robot on them one square in the corresponding direction.
- For example, if a bot is on \$(5, 6)\$ at the end of a register, it is moved to \$(6, 6)\$.
r>
/r<
/rv
/r^
/l>
/l<
/lv
/l^
: These are corner conveyer belts. If pushed onto these squares by a conveyer belt, the bot is rotated 90 degrees clockwise (rX
) or counter clockwise (lX
). At the end of each register, any bot on them (not bots that were just moved onto them) is moved one square in the corresponding direction.
- For example, if a bot is moved from \$(6, 6)\$ to \$(7, 6)\$ while facing North, it is rotated 90\${}^\circ\$ clockwise and now faces East.
- If this same bot then doesn't move during the next register, then it is pushed South to \$(7, 7)\$, facing East.
>>
/<<
/vv
/^^
: These are double conveyer belts. If a bot is on one of these at the end of a register, it is moved once in the corresponding direction, and the conveyer square it lands on then moves it a second time
R>
/R<
/Rv
/R^
: These are corner double conveyer belts, specifically right turn corners. As with normal right corner conveyer belts, they rotate a bot 90\${}^\circ\$ clockwise when pushed on to, but they then immediately move the bot in the corresponding direction.
- For example, a bot facing South who ends a register on \$(11, 1)\$ would be pushed once to \$(10, 1)\$, rotated to face West, then pushed to \$(10, 0)\$.
*v
: This is the Reboot square. If a bot moves off the board, it is "rebooted": it receives 2 Spam cards, is placed on this square and all remaining instructions are ignored for this round. The bot is now facing South, and, if another bot is rebooted while a bot is on this square, the first bot is pushed one square to the South.
PA
: This is the Priority Antenna. It cannot be moved, you cannot move into the square, and is used to determine who acts first each round.
Gameplay
Gameplay is very simple. The game is broken into rounds, and one round is structured as follows:
- First, play order is determined. Bots act in inverse order to their Manhattan distance to the Priority Antenna, with ties broken by the bot with the most "horizontal" (East-West) distance going first.
- Then, each bot is dealt 9 "programming cards" from their hand (initially 20, but it can grow). Each "programming card" contains a single instruction for the bot (e.g. Move 1, Left Turn, etc.). The bots then simultaneously* each choose 5 cards, discard the other 4, and order the 5 chosen from 1st to 5th.
- There are now 5 registers, one for each chosen card. A register proceeds as follows:
- The card for each robot for that register is revealed, and the instructions are executed in play order.
- Once all instructions are resolved, the conveyer belts all activate, potentially moving any bots.
- Then, each bot fires a laser, in a straight line in front of it, until it either hits another bot, a wall, the Priority Antenna or misses all other bots.
- If a bot is hit by a laser, it receives a Spam instruction, which is added to its "programming cards".
- If a bot is on Checkpoint 1, it is now able to visit Checkpoint 2 to win. If it is on Checkpoint 2, it wins.
- The next register begins, and the process is repeated.
- After all 5 registers are completed, and everything is resolved, each deck of programming cards are reshuffled with all programming cards, and the next round begins.
If a bot moves into the same square as another bot, that bot is pushed back one square in the direction the first bot is moving. For example, if Bot 1, facing East, moves from \$(7, 4)\$ to \$(8, 4)\$, and Bot 2 is already in \$(8, 4)\$, then Bot 2 is pushed to \$(9, 4)\$. Note that, if pushing a bot would push it into the space of another bot, both are pushed.
*: For the purposes of the KoTH, each bot will be given their cards, and will return their chosen instructions in some arbitrary order.
Programming Cards
Each bot has a deck of programming cards, initially 20. The decks are all identical, and consist of:
- 3 Move 1 cards: the bot moves forward one square
- 2 Move 2 cards: the bot moves forward exactly two squares
- 2 Move 3 card: the bot moves forward exactly three squares
- 3 Right Turn cards: the bot stays in place, and rotates 90 degrees clockwise
- 3 Left Turn cards: the bot stays in place, and rotates 90 degrees counter clockwise
- 3 U-Turn cards: the bot stays in place and rotates 180 degrees
- 2 Move Back cards: the bot moves moves backwards one square, without rotating
- 2 Again cards: the bot repeats the previous instruction
- Note that these don't "stack": playing an instruction, followed by 2 Agains does the instruction a total of 3 times, not 4
Additionally, bots can increase the number of cards in their deck by taking damage from lasers, or by rebooting. In this case, they receive Spam cards, which are added to their deck:
- Spam cards: a random card from the bot's programming deck is chosen, and that is the instruction carried out this register. At the end of the round, the Spam card is removed from your programming deck.
- Note that this does stack: if the drawn card is a Spam card, you repeat until a non-Spam card is drawn. All drawn Spam cards are removed from your deck.
Starting positions
Finally, we come to the start. At the very beginning of the game, the 6 players are placed on the 6 starting positions, in a random order. The positions are \$(1, 1)\$, \$(0, 3)\$, \$(1, 4)\$, \$(1, 5)\$, \$(0, 6)\$ and \$(1, 8)\$. Each bot may choose which direction they begin facing.
Challenge
You are to write a function in Python 3 that takes the following arguments:
round
: an integer, beginning at 0
, counting what round the game is on
order
: an integer from 1
to 6
, indicating the bot's order of play, with 1
being first and 6
being last
position
: a 3-tuple (x, y, d)
consisting of your zero-indexed coordinates in the factory, and a character, one of NESW
, indicating the direction you're facing
score
: a boolean, indicating whether you have landed on Checkpoint 1 yet.
cards
: a list of 9 two character strings, indicating the cards you've been dealt
M1
/M2
/M3
/MB
indicate Move 1, 2, 3 and Back respectively
RT
/LT
/UT
are Right, Left and U-Turn
Ag
/Sp
are Again and Spam
bots
: a list of 3-tuples (x, y, d)
of the coords and directions of all other bots
factory
: the factory matrix above.
It should then return the following:
- If
round
is 0
, it should return one of N
/E
/S
/W
to indicate its starting direction
- Otherwise, it should return a list of up to 5 of the strings from
cards
, indicating its registers. Note that the first element of this list will be the first register, the second the second and so on. If you return fewer than 5 strings, the list will be filled with randomly drawn cards from your programming deck that weren't in cards
until there are 5 elements.
Once the first bot finishes a register on Checkpoint 2, after its score
is True
, the game is finished, and the winner receives 1 point.
Scoring
Every combination of 6 bots will play 3 games together. The winner of a game receives 1 point, and the bot with the most number of points after all the games wins.
Example Bots
Sandbox note: once I've written the controller, I'll add in a couple basic example bots
random_bot
A completely random bot, it shuffles the cards dealt and returns the first 5:
import random
def random_bot(round, order, position, score, cards, bots, factory):
if round == 0:
return random.choice('NESW')
random.shuffle(cards)
while cards[0] == 'Ag': random.shuffle(cards)
return cards[:5]
Example round
*to be added*
Sandbox
- Thoughts?
- Is this clear enough?
- The original game of RoboRally is super dynamic. I worry that bots may not be able to handle that without being super complex. Thoughts?
- Is this a dupe?
- Tags are king-of-the-hill, board-game, grid, random and python. Suggestions?
- Any further feedback?