Project: Builders game (final project)
Write a class called BuildersGame for a two-player game on a 5x5 grid. Each
player has two builders. The builders move around the board and add levels to
towers. The first player to move a builder on top of a 3-story tower wins.
The rules. Player A is 'x' and player B is 'o'. Player A places two
builders on the board, then player B places two. No two builders can ever share a square. After that, player A moves one
builder to an adjacent square (one step in any direction, including diagonals).
A builder can move down any number of levels but can move up at most 1 level. It
can also stay at the same level. A builder always ends up on top of the tower on
its new square.
After moving, the builder must add a level to an adjacent square. A level cannot be added to a square with a builder on it. Once a tower has a 4th level, it is complete: no more levels can be added and no builder can move onto it. Players then alternate moving and building. A player wins by moving a builder on top of a 3-story tower, or when the opponent has no legal move.
The class. It has these private data members: a representation of the board; the current state, which is "playerA_WON", "playerB_WON" or "UNFINISHED"; and something that tracks whose turn it is.
__init__sets up an empty board, sets the state to "UNFINISHED", and sets up the other data members. A list of lists works well for the board: five lists, each holding five numbers. Each number is the tower level on that square, and 0 means no tower yet. Keep track of where the builders are separately.get_current_statereturns the current state.initial_placementtakes five parameters: the row and column of each of the player's two builders, and'x'or'o'to say which player is placing them. Rows and columns are integers from 0 to 4. For example,initial_placement(0,1,4,2,'o')puts o's builders at row 0, column 1 and row 4, column 2. ReturnFalseif a chosen square is occupied, if the player placing is not the player whose turn it is, or if that player has already placed their builders. Otherwise update the board and whose turn it is, and returnTrue.make_movetakes six parameters: the row and column of the builder to move, the row and column it moves to, and the row and column where it builds. For example,make_move(2,0,3,1,3,0)moves the builder at row 2, column 0 to row 3, column 1, then builds a level at row 3, column 0. ReturnFalseif the game is over, if the move is invalid, if the builder does not belong to the player whose turn it is, or if either player has not made their initial placement yet. Otherwise record the move, update the state and whose turn it is, and returnTrue. To update the state, check whether the move put a builder on a 3-story tower, or left the opponent with no legal move.
It is not required, but a method that prints the board helps a lot when testing
and debugging. Whether you index the board as [row][column] or [column][row]
does not matter as long as you are consistent.
Here is a simple example of how the class could be used:
board = BuildersGame()
board.initial_placement(2,2,1,2,'x')
board.initial_placement(0,1,4,2,'o')
board.make_move(2,2,1,1,1,0)
board.make_move(0,1,1,0,2,0)
board.get_current_state()
Save the file as BuildersGame.py.
Show a solution
Try the project on your own first. This is one working solution, followed by its tests. Press Run to run the tests. Read them to see what thorough testing looks like, then change the solution and run again to watch a test fail. The testing tools used here (classes and unittest) are not part of the course yet, so do not worry about how they work.
Projects run on your own computer, so you tell us when you are done.