Problem A
Chess
Implement classes for Knight, Pawn, Rook, Bishop, Queen and King. Each of these classes should inherit from class Chesspiece
If you are unsure about the rules, please read up on them on Wikipedia. For the purposes of this lab, you can skip castling ("Rockad" in Swedish), en passant and moves that place the king in check.
Code templates
Code templates are provided to you under DD1388/labblydelser/2022/lab_04/. To download them it’s recommended to just clone the labblydelser-repo and copy the lab 4 files to your own personal repository at cprog22/[your KTH-id]_labbar/04/.
It is a requirement that your classes have their own .h/.cpp-pairs, except classes that don’t need a .cpp-file for method definitions, such as the ChessMove-class below. These code templates will serve as a good guide to solving this lab by explicitly specifying the relationship between different modules and header-files for you. As you have seen already in lab 1, classes can have circular dependencies. One way to solve them is by using forward declarations rather than #include preprocessor directives whenever possible. If the full definition of a forward-declared class is needed, you can have the required #includes in the .cpp-files. This is precisely what we’ve done in the code templates for this lab.
You shall upload your implementations of all the chess pieces, as well as the Chesspiece, ChessMove and ChessBoard .h and/or .cpp (if needed) files. You may also want to include any other files (such as the Matrix from lab 2), but you should not include the main.cpp.
Using matrix and smart pointers
You must use your Matrix class from lab 2 to represent the chess board. You should use shared_ptr for your chesspieces.
Example:
Matrix< std::shared\_ptr<ChessPiece> > chessboard(8); // private member of chess board std::shared\_ptr<ChessPiece> a\_king = std::make\_shared<King>(/* constructor arguments */); //
or
std::vector< std::shared\_ptr<ChessPiece> > white\_pieces(16); // or 32 for all pieces std::shared\_ptr<ChessPiece> a\_king = std::make\_shared<King>(/* constructor arguments */); //
You can still have raw pointers in the Matrix or ChessMove pointing to the pieces in the vector of shared pointers.
To delete a piece, assign the shared_ptr to null_ptr. You do need to check for memory leaks in this assignment.
std
Use the namespace std in this assignement
using namespace std;
Chesspiece
class ChessPiece { friend void ChessBoard::move\_piece(ChessMove p); protected: // protected will cause problems int m\_x, m\_y; bool m\_is\_white; ChessBoard * m\_board; /** * Returns 0 if target square is unreachable. * Returns 1 if target square is reachable and empty. * Returns 2 if move captures a piece. */ virtual int validMove(int to\_x, int to\_y); virtual char32\_t utfRepresentation(); // may be implemented as string virtual char latin1Representation(); public: // Constructor ChessPiece( int x, int y, bool is\_white, ChessBoard * board); /** * Checks if this move is valid for this piece and captures * a piece of the opposite color. */ bool capturingMove(int to\_x, int to\_y); /** * Checks if this move is valid but does not capture a piece. */ bool nonCapturingMove(int to\_x, int to\_y); virtual vector<ChessMove> capturingMoves(); virtual vector<ChessMove> nonCapturingMoves(); /** * For testing multiple inheritance */ int unnecessary\_int; };
-
capturingMove and nonCapturingMove call the protected function validMove.
-
capturingMoves returns a vector with ChessMoves that captures a piece of the opposing color.
-
nonCapturingMoves returns a vector with ChessMoves that moves to an empty space.
You may add private or protected functions to the design of ChessPiece class
The access specifier protected will cause problems that you have to solve. You can solve them by adding public accessor functions or by using friend or by changing the protected access specifier to something else. Describe your solution in the corresponding question in the inquiry file.
Constructors
The derived classes may use the base constructor instead of implementing their own. Use the following syntax (requires c++11)
using ChessPiece::ChessPiece;
King
Let $\Delta $x be abs(x1-x2) and $\Delta $y be abs(y1-y2)
Then either $\Delta $x * $\Delta $y is one or $\Delta $x + $\Delta $y is one
Knight
A possible implementation to check valid moves for knights is to check if $\Delta $x2 + $\Delta $y2 is 5.
Pawn
You may skip en passant move.
An implementation for capturingmove is to check y+1, x+1 and x-1 and for the other color; y-1, x+1 and x-1.
The non-capturing move needs to check if there is a blocking piece at y+1/y-1.
If the pawn is at starting position (second row) it may move 1 or 2 squares ahead
If the pawn is one row from last, the pawn till transform to another piece.
Bishop and Rook
Implement two classes for Rook and Bishop that implements ChessPiece.
Queen
Implement a Queen class that inherits from both Bishop and Rook. This will create a diamond inheritance which is generally considered dangerous and one of the reasons many programming languages do not allow multiple inheritance.
Board encoding
Your test program will accept text input in the form of chessboard states. The states will be encoded according to these rules.
R = Rook ("Torn" in Swedish) N = kNight [sic] ("Springare" or "Häst" in Swedish) B = Bishop ("Löpare" in Swedish) Q = Queen K = King P = Pawn . = Empty square
White pieces are denoted with uppercase letters and black pieces are denoted with lowercase letters. Every line has 8 symbols and ends with a newline. Every board consists of 8 lines.
Each class that inherits from ChessPiece should implement an utf8-representation that uses the utf8-representation of chess pieces AND a latin1-representation according to the table above (R,n,Q... etc.)
-
utfRepresentation
-
latin1Representation
Chess move
A chess move is defined as
struct ChessMove { int from\_x; int from\_y; int to\_x; int to\_y; ChessPiece* piece; // you can change the position of the chess piece with this pointer. };
Chess board
Implement a chess board class that contains your chess pieces. You must use your Matris class from lab2 to represent the chess board. You may add additional functions or members (public constructors or vectors with white and black pieces) to the ChessBoard class.
using std::vector; using std::istream; using std::string; class ChessBoard { // add additional members or functions of your choice private: Matrix<ChessPiece *> m\_state; // Matrix from lab 2 vector<shared\_ptr<ChessPiece>> m\_white\_pieces; vector<shared\_ptr<ChessPiece>> m\_black\_pieces; public: void move\_piece(ChessMove chess\_move); vector<ChessMove> capturingMoves(bool is\_white); vector<ChessMove> nonCapturingMoves(bool is\_white); }; ChessBoard & operator>>(istream & is, ChessBoard & cb); ChessBoard & operator<<(ostream & os, ChessBoard & cb);
Sample program
using std::vector; using std::stringstream; using std::cout; using std::endl; //... ChessBoard chess; stringstream s; s << ".....Q.." << endl; s << "...q...." << endl; s << "......Q." << endl; s << "q......." << endl; s << ".......Q" << endl; s << ".q......" << endl; s << "....Q..." << endl; s << "..q....."; s >> chess; vector<ChessMove> v = chess.capturingMoves(true); if (v.size() != 0) { cout << "capturingMoves FAILED, expected 0 moves but got " << v.size() << " moves" << endl; } else { cout << "capturingMoves PASSED, expected 0 moves and got " << v.size() << " moves" << endl; }