首页 > > 详细

C++程序语言调试、programming辅导、C/C++编程设计辅导讲解R语言编程|辅导R语言编程

Due: 23:59, Sun 13 Dec 2020 Full marks: 100
Introduction
The objective of this project is to let you apply the OOP concepts learned, including inheritance and
polymorphism, to programming through developing a game application – Chess – in C++. Chess is a twoplayer
strategy board game played on a checkered board with 64 cells arranged in an 8×8 grid. The initial
board configuration is shown in Figure 1. In a text console environment, we use the letters listed in Table 1
to denote the six types of chess pieces on the board. To denote a position on the board, we use a
coordinate system like a spreadsheet program, e.g. "A2" refers to the cell in the first column and the second
row. Suppose that a C++ array board is used to represent the checkerboard, cell address "A2" will be
mapped to board[1][0]. The original chess game has many complicated rules. We will simplify the game by
relaxing some rules in this project. In our modified version of chess, each piece is assigned a specific score
as shown in Table 1. The scores will be useful for determining the player who wins the game in some cases
The two players, namely "Black" and "White" make moves in turns. In convention, White plays the first
move. Each type of piece has its own way of moving. In Figure 2, the white dots mark the cells to which the
piece can move into if there are no intervening piece(s) of either color (except the knight, which leaps over
any intervening pieces).
Summary of the rules of moving each piece:
• The king moves one cell in any of the eight directions as long as no piece of its own color occupies
the target cell. If the target cell is occupied by an opponent piece, the king can capture it.
• A rook can move any number of cells along a row (rank) or column (file) but cannot leap over
other pieces.
• A bishop can move any number of cells diagonally but cannot leap over other pieces.
• The queen combines the power of a rook and bishop and can move any number of squares along
a row, column or diagonal, but cannot leap over other pieces.
• A knight moves to any of the closest cells that are not on the same row, column or diagonal. Thus,
the move forms an L-shape: two cells vertically and one cell horizontally, or two cells horizontally
and one cell vertically. The knight is the only piece that can leap over other pieces.
• A pawn can move forward to the unoccupied cell immediately in front of it on the same column,
or on its first move it can advance two cells along the same column, provided both cells are
unoccupied (white dots in the diagram); or the pawn can capture an opponent's piece on cell
diagonally in front of it on an adjacent column, by moving to that cell (black "x"s).
For simplicity, special moves known as (1) castling, (2) en passant, and (3) promotion of a pawn (when it
advances to the eighth rank) will also be skipped in this project. Please make sure not to implement these
to let our grading be consistent. The objective of the game is to checkmate the opponent's king by placing
it under an inescapable threat of capture. To achieve that, a player's pieces are used to attack and capture
the opponent's pieces, while supporting or protecting one another
Game-over conditions:
The game is over when either of the kings is captured by an opponent’s piece. Let’s say Black’s king
is captured successfully by a white piece, then the White player wins. It is possible for the game to
draw. In the original chess design, there are complicated rules about how to arrive at a draw game
including stalemate, threefold repetition rule, fifty-move rule, mutual agreement, and impossibility of
checkmate. Again, we will skip them all and use a custom way to define a draw game as follows.
We extend the original chess game with two features: per-piece score and an ad hoc way to stop the
game. Each piece is assigned a specific score as shown in Table 1. For example, the queen is much
more worthy than other pieces but incomparable with the king – losing the king (worth 1000 points)
will surely lead to losing the game. During a game run, either player can enter a special imaginary
move, namely "Z0 Z0" (from cell "Z0" to cell "Z0" which are both invalid positions). The program will
detect this input to stop the game. While both kings are not yet captured, the player with a higher
total score of his/her pieces that are still alive (not yet captured) will win the game. If both players
have the same score, the game will draw. This ad hoc halt mimics the draw by agreement (when the
game becomes too long and boring) although our version of handling makes poor sense in that the
stop is triggered by a single player alone rather than having “mutual agreement”.
Program Specification You have to write the program composed of a total of 25 files (C++ header and
source files) listed in the following tables. We have provided a zip file of starter source code to assist your
design of this sizeable program. Basically, you need not design but implement the game.
Note the Remarks column of the above tables:
(1) “Provided”: all these source files need no changes and should be kept unmodified.
(2) “To fill in TODO parts”: in these files, some code segments are missing. Please look for all TODO
comments in them for instructions about what to do and fill in the missing code to finish the
implementation of each class.
(3) “To be created”: such files are not provided and are to be created by you.
Game Flow
The main() function in main.cpp creates a Game object and calls its run() method to start a chess
game. The Game() constructor accepts a game mode parameter which can be one of the following:
• Value 1 means “Human vs. Human”, i.e. two human players enter moves via console;
• Value 2 means “Human vs. Machine”, i.e. one human player enters moves via console and the
opponent player is the computer (which makes random moves on the game board);
• Value 3 means “Machine vs. Machine”, two computer players make random moves in turns
without human attention.
(The Mode enum in game.h has defined these three constant values.)
When the Game object is being created, the constructor will create two Player objects of type
(Human / Machine) according to the above mode setting, set game state as RUNNING (0) and create
the Board object. The Board constructor will call Board::configure() method to set up the initial
game board by filling the cells array with pointers to King, Queen, Bishop, … objects that are being
created in the method. The created pieces will be added to each player's list of pieces as well.
The Game object’s run() is the main loop of the program, which repeats calling the current player’s
makeMove(board) function and printing the board. The current player is flipped in each iteration.
For a Human player, its makeMove() will prompt the user for two cell addresses, e.g. A7 B8, with the
former denoting the source cell and the latter denoting the destination cell on the board. These textbased
cell addresses will be translated to array indexes to access the Board object’s cells array.
Reminder: As mentioned earlier, if a human player enters "Z0 Z0" as the input for his/her turn, this
signals that the player wants to stop the game and print the final message about who wins.
For a Machine player, its makeMove() will make a random but valid move. To do so, first, pick a piece
randomly from the player's pieces vector and get its position (y1, x1). (This part has been done for you in
the provided source machine.cpp). Then, generate a random target position (y2, x2) and try moving the
piece from (y1, x1) to (y2, x2). If the move is invalid, repeat these steps until a valid move is resulted.
Class Hierarchy
The basic structure of this complicated program can be broken down as follows.
Abstract base classes
There are two abstract base classes in this program:
Class Piece (piece.h and piece.cpp)
• It serves as the base or parent class of all game pieces like King, Queen, etc.
• Each Piece object has a label (‘K’ for King, ‘Q’ for Queen, etc.), color (BLACK or WHITE), score, and
position (y, x) on the board, and a back link (a pointer) to the Board object. (Through that back
link, the Piece object can reach and call methods of Board and Game when necessary.)
• It has a move(int y, int x) function for making a move. (We have provided the basic actions
needed by a move, e.g. capturing the opponent piece if the target position has been occupied by
an opponent piece.)
• It has a pure virtual function of signature isMoveValid(int y, int x)
Class Player (player.h and player.cpp)
• It serves as the base or parent class of Human and Machine classes.
• Each Player object has a name (in string, “Black” or “White”) and a color (in Color enum, BLACK or
WHITE). (note: Color enum is defined in piece.h.)
• It has a pure virtual function of signature makeMove(Board* board). This method must be
implemented by the concrete classes Human and Machine.
• It keeps a list of pieces that are still alive and on the game board. (The list is implemented using a
vector storing pointers to the Piece objects.)
• It provides methods to retrieve the count of pieces in the list, get a piece from the list, add a
piece to or delete a piece from the list.
Concrete classes
Subclasses of Piece
We have provided the following two classes that inherit from Piece as examples of how to complete
the implementation of a working game piece:
• Class King (king.h and king.cpp)
• Class Pawn (pawn.h and pawn.cpp)
They have implemented their own isMoveValid(int y, int x). In particular, the Pawn class has a
special need to override the move(int y, int x) function to reduce the steps it can move from 2
to 1 after making the first move (this is a chess game rule).
One of your main tasks is to add the following subclasses that inherit from Piece, each of which must
implement the pure virtual function isMoveValid(int y, int x) according to the rules governing
the moves of each piece type. Follow our provided examples (King and Pawn classes) and remember
to add “include guard” compiler directives in all header files.
• Class Queen (queen.h and queen.cpp)
• Class Bishop (bishop.h and bishop.cpp)
• Class Knight (knight.h and knight.cpp)
• Class Rook (rook.h and rook.cpp)
Subclasses of Player
• Class Human (human.h and machine.cpp)
o It implements makeMove(Board* board) to repeatedly prompt the current human player to
enter two cell addresses of a move until a valid move is obtained. The ad hoc move "Z0 Z0" is
detected here and if received, the game state is set to STOPPED and the method returns at
once. In the loop body, it calls the move() method of the board object, which will validate
the move and update the board if the move is confirmed valid.
• Class Machine (machine.h and machine.cpp)
o It implements makeMove(Board* board) to make a random valid move on the board by a
nested loop. First, pick a piece randomly from the player's pieces vector and get its position
(y1, x1). Then generate a random position (y2, x2) and try moving the piece from (y1, x1) to
(y2, x2). If the trial move is found invalid, repeat the second step until reaching a valid move
or a maximum bound of trials (preset as 4096). If it happens that a valid move cannot be
found within the maximum trials bound, pick a piece from the player’s pieces list randomly
again to redo the random search process. The maximum times of the repeated piece picking
is 10 x piece count in the vector. In case that the program cannot find any valid move within
the trials bound for all piece pickings, the move is regarded forfeited – the turn finishes with
no actual move (no update of the board), and the turn is passed to the opponent player.
o Note that ad hoc move "Z0 Z0" is NOT generated by a machine player. There is no premature
termination of the game and no draw game for the machine vs. machine mode.
The Board-level move() includes validation against illegal cases like accessing out-of-bound positions
or moving a piece that belongs to the opponent. Read the TODO comments in board.cpp for more
details.
The Piece-level move() includes capturing the opponent piece and is called only if calling piece->
isMoveValid(y2, x2) returns true, i.e. passed validation against the moving rules of the specific
piece type, e.g. Bishop can move only diagonally.
Assumptions
• The board size is always 8x8. Still, we use two global constants H and W to represent the board’s
height (number of rows) and width (number of columns). They are both set to 8.
• We assume that cell address inputs always follow the format of one letter (A-Z or a-z) plus one
integer (1-26). Lowercase inputs like "a1", "h10", etc. will be accepted as normal. Except for "Z0"
(case-sensitive) which is treated as a sentinel for game stop, you need NOT handle weird inputs
like "AA1", "A01", "abc", "A3.14", "#a2", … for cell addresses and inputs like "-1", "6.28",
"#$@", … for the number of pits. The behavior upon receiving these is unspecified, probably
running into forever loop or program crash.
Restrictions
• You cannot declare any global variables (i.e. variables declared outside any functions). But global
constants or arrays of constants are allowed.
• Your final program should contain a total of 25 files (the C++ header and source files listed
above). Note your spelling - do not modify any file names.
o For class names, use camel case (e.g. Knight); for file names, use lower case for all letters
(e.g. knight.h, knight.cpp).
• You should not modify the provided code (unless specified otherwise).
Sample Runs
In the following sample runs, 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 the ‘:’ in the program printout.
Sample run in Human vs. Human mode:


There are too many combinations
of possible inputs. Please check
your program correctness against
the results produced by our sample
program executable posted on
Blackboard.

联系我们 - QQ: 99515681 微信:codinghelp
程序辅导网!