Assignment 8 – Running a Game

Assignment 8 – Running a Game

Due Friday 5/20 11:59pm for the code deliverables

In this assignment you must build the server infrastructure to run a game with many players, tracking the player and game states as play goes on, determining when the game is over, and reporting the winner or winners. The games will used the advanced rules from assignment 7.

Players will connect to you over the network, using the protocol from assignment 6. This time, instead of writing the code the player, you will write the code for the server.

You must arrange your code so that there is a main game loop that plays the game and does not know (or care) if the players it gets are players that play over the network or if they are local players. That is, in assignment 5 you designed a player that accepts the game state and a player state and produced another player state. The main game-playing code must be able to accept that or to accept a player that is playing over the network and it must treat the two exactly the same way. A good way to think about this is that the main game-playing loop should accept a list of players (represented as functions or as objects) and then invoke methods of them. If those methods communicate over the network to determine their move, fine. If they just calculate some interesting function to determine their move, fine. The game-playing code does not need to know and should not care. In addition to making it easier (avoiding special case the game-playing code), this also makes it easier to test the game playing code (especially in the case that it might have cheating players).

Your server must accommodate buggy players, marking them as cheaters. Once a player has cheated, it is fine to cease communication with them (indeed it is good to close the connection). Players may cheat in various ways: sending illegal moves, sending bad json, or just terminating the connection from their end.

The test cases for this assignment consist of running complete games in your server. In order to synchronize and for this to work well in CI there are three steps that your code should follow, carefully:

  1. Your code will receive, on stdin, a JSON object indicating the port that you should start the server on and the number of players you should expect to connect to the server via a JSON object matching game-config:

    game-config

     ::= 

    { "players" : natural, "port" : natural }

    Create a server on the port specified in the input and expect to play game with that many players.

  2. Once your code has started listening on port named by the natural number, your player should write the json string "started" to stdout. Do not write "started" until after your code has created the server; this is typically called something like “creating a listener”. If you write "started" before the listener is created, tests will sometimes fail and sometimes pass, as there’ll be a race condition.

  3. Once the appropriate number of players have connected, your server should play a game with them, sending JSON over the network connections.

  4. Once the game is over, your code should report the results of the match using a JSON object sent to stdout that matches results:

    results

     ::= 

    [ [ string, result ], ... ]

    result

     ::= 

    integer

     | 

    false

    where the outer list has one entry for each player in the game and each inner list has one of the player’s names and their score or false if the player cheated.

Even though players may cheat in many different ways, your server should survive them all and even deal with the case that everyone cheats.

The board game comes with a fixed set of cards, both construction cards and city plan cards. Here is JSON for the city plan cards:

[{"criteria":[1,1,1,1,1,1],"position":1,"score1":8,"score2":4},

 {"criteria":[2,2,2,2],"position":1,"score1":8,"score2":4},

 {"criteria":[3,3,3],"position":1,"score1":8,"score2":4},

 {"criteria":[4,4],"position":1,"score1":6,"score2":3},

 {"criteria":[5,5],"position":1,"score1":8,"score2":4},

 {"criteria":[6,6],"position":1,"score1":10,"score2":6},

 {"criteria":["all houses",0],"position":1,"score1":6,"score2":3},

 {"criteria":["all houses",2],"position":1,"score1":8,"score2":4},

 {"criteria":"end houses","position":1,"score1":7,"score2":4},

 {"criteria":"5 bis","position":1,"score1":8,"score2":3},

 {"criteria":"7 temps","position":1,"score1":6,"score2":3},

 {"criteria":[1,1,1,6],"position":2,"score1":11,"score2":6},

 {"criteria":[2,2,5],"position":2,"score1":10,"score2":6},

 {"criteria":[3,3,4],"position":2,"score1":12,"score2":7},

 {"criteria":[3,6],"position":2,"score1":8,"score2":4},

 {"criteria":[4,5],"position":2,"score1":9,"score2":5},

 {"criteria":[1,1,1,4],"position":2,"score1":9,"score2":5},

 {"criteria":"two streets all parks","position":2,"score1":7,"score2":4},

 {"criteria":"two streets all pools","position":2,"score1":7,"score2":4},

 {"criteria":["all pools all parks",1],"position":2,"score1":8,"score2":3},

 {"criteria":["all pools all parks",2],"position":2,"score1":10,"score2":5},

 {"criteria":"all pools all parks one roundabout","position":2,"score1":10,"score2":5},

 {"criteria":[1,2,6],"position":3,"score1":12,"score2":7},

 {"criteria":[1,4,5],"position":3,"score1":13,"score2":7},

 {"criteria":[3,4],"position":3,"score1":7,"score2":3},

 {"criteria":[2,5],"position":3,"score1":7,"score2":3},

 {"criteria":[1,2,2,3],"position":3,"score1":11,"score2":6},

 {"criteria":[2,3,5],"position":3,"score1":13,"score2":7}]

and here is the JSON for the construction cards:

[[1,"surveyor"],

 [1,"landscaper"],

 [1,"agent"],

 [2,"surveyor"],

 [2,"landscaper"],

 [2,"agent"],

 [3,"surveyor"],

 [3,"pool"],

 [3,"temp"],

 [3,"bis"],

 [4,"landscaper"],

 [4,"agent"],

 [4,"pool"],

 [4,"temp"],

 [4,"bis"],

 [5,"surveyor"],

 [5,"surveyor"],

 [5,"landscaper"],

 [5,"landscaper"],

 [5,"agent"],

 [5,"agent"],

 [6,"surveyor"],

 [6,"surveyor"],

 [6,"pool"],

 [6,"temp"],

 [6,"bis"],

 [6,"landscaper"],

 [6,"agent"],

 [7,"surveyor"],

 [7,"pool"],

 [7,"temp"],

 [7,"bis"],

 [7,"landscaper"],

 [7,"landscaper"],

 [7,"agent"],

 [7,"agent"],

 [8,"surveyor"],

 [8,"surveyor"],

 [8,"pool"],

 [8,"temp"],

 [8,"bis"],

 [8,"landscaper"],

 [8,"landscaper"],

 [8,"agent"],

 [8,"agent"],

 [9,"surveyor"],

 [9,"pool"],

 [9,"temp"],

 [9,"bis"],

 [9,"landscaper"],

 [9,"landscaper"],

 [9,"agent"],

 [9,"agent"],

 [10,"surveyor"],

 [10,"surveyor"],

 [10,"pool"],

 [10,"temp"],

 [10,"bis"],

 [10,"landscaper"],

 [10,"agent"],

 [11,"surveyor"],

 [11,"surveyor"],

 [11,"landscaper"],

 [11,"landscaper"],

 [11,"agent"],

 [11,"agent"],

 [12,"pool"],

 [12,"temp"],

 [12,"bis"],

 [12,"landscaper"],

 [12,"agent"],

 [13,"landscaper"],

 [13,"pool"],

 [13,"temp"],

 [13,"bis"],

 [14,"surveyor"],

 [14,"landscaper"],

 [14,"agent"],

 [15,"surveyor"],

 [15,"landscaper"],

 [15,"agent"]]

Code Deliverables: In your team’s GitHub repository, create a directory “Deliverables/8/8.1/” and deposit there a Makefile for your test driver. It will be invoked multiple times to run multiple games with different players by the CI.

You will receive up to 50 points for your code.