CSCI1520 Computer Principles and C++ Programming, Spring 2022/23
Assignment 4: Three Men’s Morris
File name: morrisboard.cpp morrisgame.cpp morrisboard.h
Full marks: 100
Introduction
The objective of this assignment is to practice (1) defining functions (being a callee), (2) calling functions (being a caller), and (3) representing special kind of data. You will implement a game called Three Men’s Morris. There are two players, 1 and 2, in the game. Each player has three pieces. The game is played on a 3 × 3 board in two phases. In phase 1, the players take turn to place their three pieces on the board one by one. Once the pieces are placed, the game proceeds to phase 2. Each player continues to take turn, to move one of their pieces to an empty position. A piece may move to any empty position on the board, not just an adjacent one. The player who first aligns their three pieces horizontally, vertically, or diagonally in any phase wins. Figure 1 shows a game board and some example game plays. The numbers 1 and 2 denote the players, and 0 denotes an empty space. At the end of Figure 1, player 2 forms a horizontal line at the bottom row and wins the game.
Phase 1:
0-0-0 ||/| 0-0-0 |/|| 0-0-0
Player 1 places a piece →
0-0-0 ||/| 0-1-0 |/|| 0-0-0
Phase 2:
2-0-2 ||/| 2-1-1 |/|| 1-0-0
Player 1 moves a piece →
2-1-2 ||/| 2-1-0 |/|| 1-0-0
More turns →…→
2-0-2 ||/| 2-1-1 |/|| 1-0-0
(End of phase 1)
More turns →…→
1-0-0 ||/| 0-1-1 |/|| 2-2-2
(Player 2 wins)
Figure 1: An Example Three Men’s Morris Game Play
Program Specification
This section describes the requirements, game board representation, some necessary functions, and program flow.
Basic Requirements
- You cannot declare any global variables (variables declared outside any functions) in all files.
- You cannot use any functions in the \
library. - You cannot use any arrays nor vectors.
Game Board Representation
There are nine possible positions in a game board. Therefore, we use integers 1–9 to denote these board positions, as illustrated in Figure 2. The positions are basically ordered top-to-bottom, left-toright.
2-0-2 ||/| 2-1-1 |/|| 1-0-0 Figure 2: Position Numbers for Board Positions
To encode the whole game board, we use a 9-digit integer ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 . Each digit ?? is either 0, 1, or 2. Values 1 or 2 mean that position ? is a piece of players 1 or 2 respectively. Value 0 means that position ? is empty. E.g., the last board in Figure 1 is encoded as 100011222. Using this representation, the initial board (with all positions empty) is encoded as 000000000. (Note: in C++, integer constants should NOT contain leading zeroes, otherwise, they will be treated as octal numbers. Therefore, the initial board is actually 0 rather than 000000000.) The data type int in C++ is typically 32-bit It has a range of −2147483648 … 2147483647, which is wide enough to store any 9-digit integer. Therefore, we can simply use one int variable to store the game board configuration of a game.
Provided and Required Functions (morrisboard.cpp and morrisboard.h)
Your program must contain the following functions. Some of them are written for you already (Provided) and you shall not modify their contents. The others will be written by you (Required). These functions shall be implemented in the source file morrisboard.cpp with the function prototypes in the header file morrisboard.h. These functions shall be called somewhere in your program. You must not modify the prototypes of all these functions. You can design extra functions if you find necessary.
In the functions below, you can assume that (a) the parameter board is always a proper encoding of a game board (9-digit integer; each shall be 0–2); (b) the parameters pos, from, and to are always 1–9; and (c) the parameter p is always either 1 or 2.
Besides, all the required functions below will be graded individually. That is, we shall connect your morrisboard.cpp with another source file with our testing code to call the functions one by one for grading. So your code for each function shall implement the description of that function only. You shall not write any code in a function that is beyond that function’s description. (Provided) int boardState(int board, int pos)
Returns the state of position pos of the game board. That is, returns 0 when the position is empty; returns 1 when player 1’s piece is in the position; and returns 2 when player 2’s piece is in the position.
(Provided) void printBoard(int board) Prints the board to the screen using the format in Figure 1. (Required) void placePiece(int &board, int pos, int p) This function shall update the posth digit of the reference parameter board to digit p. The other digits of board remain unchanged. The following shows some sample function calls and the expected results.
The underlying meaning of this function is actually to perform the task of player p placing a piece to position pos of board. At the end of this function, the value of board shall become the new board configuration after the piece placement. Besides, you shall not print anything using cout in this function.
(Required) void movePiece(int &board, int from, int to, int p) This function shall update the fromth digit of the reference parameter board to 0, and the toth digit of board to digit p. The other digits of board remain unchanged. The following shows some sample function calls and the expected results.
The underlying meaning of this function is actually to perform the task of player p moving a piece from position from to position to of board in phase 2 of the game. At the end of this function, the value of board shall become the new board configuration after the piece movement. When writing this function, calling the boardState() and placePiece() functions would be useful. Besides, you shall not print anything using cout in this function.
(Required) int formLine(int board) This function shall check if any player has formed a line horizontally, vertically, or diagonally in board. If so, the function shall return either 1 or 2, meaning the player of the line. Otherwise, the function shall return 0, meaning that no line is formed. E.g., the call formLine(202211100) shall return 0, formLine(102010221) shall return 1, and formLine(100011222) shall return 2. When writing this function, calling the boardState() function would be useful.
Program Flow (morrisgame.cpp)
The program flow of the game is described as follows and shall be implemented in the source file morrisgame.cpp. You shall call the functions above to aid your implementation. You can assume that all user input are always integers.
- The game starts with an empty board (0). Player 1 takes the first turn in phase 1.
Phase 1
- Then, prompt the current player to enter a position that s/he wants to place a piece.
- A user input is in phase 1 is invalid if (a) the input position is not 1–9, or (b) the position is not empty. In case it is invalid, display a warning message and go back to Step 2.
- Update the board by placing a piece to the input position.
- Repeat steps 2–4 with alternate players 1 and 2, until each player has placed three pieces or one player has formed a line horizontally, vertically, or diagonally. Then phase 2 shall start. However, phase 2 will be skipped if a player has already formed a line in phase 1.
Phase 2
- Prompt the current player to enter two integers to specify a piece movement from a source position to a destination position.
- A user input in phase 2 is invalid if (a) two input positions are not 1–9, (b) the source position is not occupied by the current player, or (c) the destination position is not empty. In case it is invalid, display a warning message and go back to Step 6.
- Update the board by moving the source piece to the destination.
- Repeat steps 6–8 with alternate players 1 and 2, until a player has formed a line vertically, horizontally, or diagonally. End game
- Once the game is finished, display the message “Player 1 wins!” or “Player 2 wins!” accordingly. Note that there is no draw game; the two players will be asked to move indefinitely as long as there is no winner.
Functions and Files Organization
The file morrisboard.cpp must contain the implementation of the provided and required functions. There must be no main() function in the file. You may write extra functions in this file if you find necessary.
The header file morrisboard.h must contain the prototypes of the provided and required functions. You may put in extra function prototypes if you have written extra functions in morrisboard.cpp.
The file morrisgame.cpp must contain the main() function for the program flow. You may write extra functions in this file if you find necessary.
Sample Run
The following shows a sample run. The blue text is user input and the other text is the program printout. You can try the provided sample program for other input. Your program output should be exactly the same as the sample program (same text, symbols, letter case, spacings, etc.). Note that there is a space after ‘:’ in the printout. 0-0-0 ||/| 0-0-0 |/|| 0-0-0 Player 1 0-0-0 ||/| 0-1-0 |/|| 0-0-0 Player 2 Invalid. Player 2 Invalid. Try again! Invalid. Player 2 2-0-0 ||/| 0-1-0 |/|| 0-0-0 Player 1 2-0-0 ||/| 0-1-1 |/|| 0-0-0 Player 2 2-0-0 ||/| 2-1-1 |/|| 0-0-0 Player 1 2-0-0 ||/| 2-1-1 |/|| 1-0-0 Player 2 2-0-2 ||/| 2-1-1 |/|| 1-0-0 Player 1 Invalid. Player 1 Invalid. Player 1 2-1-2 ||/| 2-1-0 |/|| 1-0-0 Player 2 0-1-2 ||/| 2-1-0 |/|| 1-2-0 Player 1
0-1-2 ||/| 2-1-0 |/|| 0-2-1 Player 2 (from to): 4 7 0-1-2 ||/| 0-1-0 |/|| 2-2-1 Player 1 (from to): 2 1 1-0-2 ||/| 0-1-0 |/|| 2-2-1 Player 1 wins!
Submission and Marking
➢ Your program file name should be morrisboard.cpp, morrisgame.cpp, and do not submit the .h, we shall assume that it is the same as the provided one. ➢ Insert your name, student ID, and e-mail as comments at the beginning of all your files. ➢ You can submit your assignment multiple times. Only the latest submission counts. ➢ Your program should be free of compilation errors and warnings. ➢ Your program should include suitable comments as documentation.