Hide

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;
  }

Please log in to submit a solution to this problem

Log in