Due: March 7
For this part, you must produce both a player program and a turn-checking program.
A token’s move can optionally swap places with an adjacent opponent token, as long as the token would be able to move to the opponent’s space if the opponent token were not there; otherwise, the move must be to an unoccupied space as usual.
The moved token can optionally move a second time (i.e., the same token), as long as the first move doesn’t win, and as long as the second move doesn’t return to the original space.
The build phase can build a space currently at level 0, 1, 2 to make it level 4, instead of building to exactly one more than the space’s current level.
The moved token can optionally build a second time, but not on the same space as the first build within a turn.
The moved token can optionally build a second time, but only on the same space as the first build within a turn, and only if the second build does not reach level 4.
A token’s move can optionally enter the space of an opponent’s token, but only if the token can be pushed back to an unoccupied space, and only as long as the token would be able to move to the opponent’s space if the opponent token were not there. The unoccupied space where the opponent’s token is pushed can be at any level less than 4. Note that the opponent does not win by having a token forced to level 3; furthermore, such a token will have to move back down before it can move to level 3 for a win.
A token can optionally build before moving, but then the move is constrained to the same level or lower (i.e., the level of the token’s new space can be no larger than the level of the token’s old space). The moved token must still build after moving.
Note that these choices keep two aspects of the game the same: none of the cards require information about the game history, and all cards only extend the set of possible moves for a player (i.e., they don’t disallow moves that would be allowed without a card). Then again, since a token can be forced by Minotaur to level 3 without winning, checking for a winning board now depends on the immediately preceding board.
In a game, each player will have a distinct card, and a player’s turn is affected only by the player’s own card.
To accommodate player cards, we redefine players from Board Representation, and we define two new terms:
A player is a dictionary with two keys:
"tokens" mapped to an array of 2 spaces, where the order of the spaces in the array does not matter
"card" mapped to a card, where the players of a board have distinct values for "card"
A card is one of the strings "Apollo" "Artemis", "Atlas", "Demeter", "Hephastus", "Minotaur", or "Prometheus", with exactly those letters and case
A pre-player is a dictionary that has one key:
"card" mapped to a card
All other definitions are the same modulo references to the revised term player.
For example, it player 1 has the Artemis card and player 2 has the Prometheus card, the JSON representation of
To accommodate player cards in the Game Protocol, we change the setup phase. Your Santorini player program will first receive a JSON array of one of the following shapes:
An array with 2 pre-players: Your program is the first pre-player, and its card is the one in the array’s first pre-player. Your program should return an array containing the second pre-player followed by a player to represent the starting placement of your program’s tokens (still with the same card). The cards of the given pre-players will be distinct.
An array with one pre-player followed by one player: Your program is the second player, the pre-player in the array specifies the card for your player, and the player in the array represents the opponent’s card and tokens. Your program should return an array of 2 players. The first player in that result array must be the same as the provided one (which was second in the provided array), and the second player in the result array represents the starting placement of your program’s tokens (still with the same card). The cards of the given pre-player and player will be distinct.
For example, to start a where player 1 has the Artemis card and player 2 has the Prometheus card, the player 1 program will receive
A suitable response could be the following, which is sent on to the player 2 program:
If so, the player 2 program might reply like this:
Besides updating your player program to work with cards, write a turn-checking program. The turn-checking program should loop through the following steps until the attempt to read a string in the first step produces an end-of-file:
read a JSON string, which is a brief description of the test case;
read a JSON board, which corresponds to the board state before a turn;
read a second JSON board, which is a candidate board state after a turn; and
print the JSON string back out for the test-case description;
- print the JSON string "ok" if the second board is a valid result from a player program that is given the first board, or print the JSON string "invalid" otherwise.
Ignore whether it is actually possible to get to the first board’s state on the turn indicated by the board’s turn number. The second board can be valid only when its turn number is one more than the first board’s turn number, but the turn numbers don’t matter otherwise.
The same as for the player protocol, we’ll try your turn checking with JSON inputs that each fit on a single, newline-terminated input line.
As a class, we will collect a shared database of tests here:
Please don’t upload lots of automatically generated tests. Instead, add hand-crafted tests for interesting cases. Note that your name is associated to any test that you upload (using a password that has been mailed to you), so we’ll all know whether you’re contributing reasonably, over-contributing, or just taking advantage of everyone else’s contributions.
As usual, email the instructor an archive or a pointer to an archive (such as a link to Google Drive) that contains your source and a compiled version of your player and turn-checker programs. The compiled version should run on the CADE lab1-X.eng.utah.edu machines. Include a "README.txt" file that describes the path within your archive for the player and turn-checker executables.