#include <bits/stdc++.h> using namespace std; class Piece { private: virtual bool AreSquaresLegal(int srcRow, int srcCol, int destRow, int destCol, Piece *GameBoard[8][8]) = 0; char mPieceColor; public: Piece(char PieceColor) : mPieceColor(PieceColor) {} ~Piece() {} virtual char GetPiece() = 0; char GetColor() { return mPieceColor; } bool IsLegalMove(int srcRow, int srcCol, int destRow, int destCol, Piece *GameBoard[8][8]) { Piece *destPiece = GameBoard[destRow][destCol]; if ((destPiece == 0) || (mPieceColor != destPiece->GetColor())) { return AreSquaresLegal(srcRow, srcCol, destRow, destCol, GameBoard); } return false; } }; class PawnPiece : public Piece { public: PawnPiece(char PieceColor) : Piece(PieceColor) {} ~PawnPiece() {} private: virtual char GetPiece() { return 'P'; } bool AreSquaresLegal(int srcRow, int srcCol, int destRow, int destCol, Piece *GameBoard[8][8]) { Piece *destPiece = GameBoard[destRow][destCol]; if (destPiece == 0) { // Destination square is unoccupied if (srcCol == destCol) { if (GetColor() == 'W') { if (destRow == srcRow + 1) { return true; } } else { if (destRow == srcRow - 1) { return true; } } } } else { // Dest holds piece of opposite color if ((srcCol == destCol + 1) || (srcCol == destCol - 1)) { if (GetColor() == 'W') { if (destRow == srcRow + 1) { return true; } } else { if (destRow == srcRow - 1) { return true; } } } } return false; } }; class KnightPiece : public Piece { public: KnightPiece(char PieceColor) : Piece(PieceColor) {} ~KnightPiece() {} private: virtual char GetPiece() { return 'N'; } bool AreSquaresLegal(int srcRow, int srcCol, int destRow, int destCol, Piece *GameBoard[8][8]) { // Destination square is unoccupied or occupied by opposite color if ((srcCol == destCol + 1) || (srcCol == destCol - 1)) { if ((srcRow == destRow + 2) || (srcRow == destRow - 2)) { return true; } } if ((srcCol == destCol + 2) || (srcCol == destCol - 2)) { if ((srcRow == destRow + 1) || (srcRow == destRow - 1)) { return true; } } return false; } }; class BishopPiece : public Piece { public: BishopPiece(char PieceColor) : Piece(PieceColor) {} ~BishopPiece() {} private: virtual char GetPiece() { return 'B'; } bool AreSquaresLegal(int srcRow, int srcCol, int destRow, int destCol, Piece *GameBoard[8][8]) { if ((destCol - srcCol == destRow - srcRow) || (destCol - srcCol == srcRow - destRow)) { // Make sure that all invervening squares are empty int iRowOffset = (destRow - srcRow > 0) ? 1 : -1; int iColOffset = (destCol - srcCol > 0) ? 1 : -1; int iCheckRow; int iCheckCol; for (iCheckRow = srcRow + iRowOffset, iCheckCol = srcCol + iColOffset; iCheckRow != destRow; iCheckRow = iCheckRow + iRowOffset, iCheckCol = iCheckCol + iColOffset) { if (GameBoard[iCheckRow][iCheckCol] != 0) { return false; } } return true; } return false; } }; class RookPiece : public Piece { public: RookPiece(char PieceColor) : Piece(PieceColor) {} ~RookPiece() {} private: virtual char GetPiece() { return 'R'; } bool AreSquaresLegal(int srcRow, int srcCol, int destRow, int destCol, Piece *GameBoard[8][8]) { if (srcRow == destRow) { // Make sure that all invervening squares are empty int iColOffset = (destCol - srcCol > 0) ? 1 : -1; for (int iCheckCol = srcCol + iColOffset; iCheckCol != destCol; iCheckCol = iCheckCol + iColOffset) { if (GameBoard[srcRow][iCheckCol] != 0) { return false; } } return true; } else if (destCol == srcCol) { // Make sure that all invervening squares are empty int iRowOffset = (destRow - srcRow > 0) ? 1 : -1; for (int iCheckRow = srcRow + iRowOffset; iCheckRow != destRow; iCheckRow = iCheckRow + iRowOffset) { if (GameBoard[iCheckRow][srcCol] != 0) { return false; } } return true; } return false; } }; class QueenPiece : public Piece { public: QueenPiece(char PieceColor) : Piece(PieceColor) {} ~QueenPiece() {} private: virtual char GetPiece() { return 'Q'; } bool AreSquaresLegal(int srcRow, int srcCol, int destRow, int destCol, Piece *GameBoard[8][8]) { if (srcRow == destRow) { // Make sure that all invervening squares are empty int iColOffset = (destCol - srcCol > 0) ? 1 : -1; for (int iCheckCol = srcCol + iColOffset; iCheckCol != destCol; iCheckCol = iCheckCol + iColOffset) { if (GameBoard[srcRow][iCheckCol] != 0) { return false; } } return true; } else if (destCol == srcCol) { // Make sure that all invervening squares are empty int iRowOffset = (destRow - srcRow > 0) ? 1 : -1; for (int iCheckRow = srcRow + iRowOffset; iCheckRow != destRow; iCheckRow = iCheckRow + iRowOffset) { if (GameBoard[iCheckRow][srcCol] != 0) { return false; } } return true; } else if ((destCol - srcCol == destRow - srcRow) || (destCol - srcCol == srcRow - destRow)) { // Make sure that all invervening squares are empty int iRowOffset = (destRow - srcRow > 0) ? 1 : -1; int iColOffset = (destCol - srcCol > 0) ? 1 : -1; int iCheckRow; int iCheckCol; for (iCheckRow = srcRow + iRowOffset, iCheckCol = srcCol + iColOffset; iCheckRow != destRow; iCheckRow = iCheckRow + iRowOffset, iCheckCol = iCheckCol + iColOffset) { if (GameBoard[iCheckRow][iCheckCol] != 0) { return false; } } return true; } return false; } }; class KingPiece : public Piece { public: KingPiece(char PieceColor) : Piece(PieceColor) {} ~KingPiece() {} private: virtual char GetPiece() { return 'K'; } bool AreSquaresLegal(int srcRow, int srcCol, int destRow, int destCol, Piece *GameBoard[8][8]) { int iRowDelta = destRow - srcRow; int iColDelta = destCol - srcCol; if (((iRowDelta >= -1) && (iRowDelta <= 1)) && ((iColDelta >= -1) && (iColDelta <= 1))) { return true; } return false; } }; class ChessBoard { public: Piece *MainGameBoard[8][8]; ChessBoard() { for (int iRow = 0; iRow < 8; ++iRow) { for (int iCol = 0; iCol < 8; ++iCol) { MainGameBoard[iRow][iCol] = 0; } } // Allocate and place black pieces for (int iCol = 0; iCol < 8; ++iCol) { MainGameBoard[6][iCol] = new PawnPiece('B'); } MainGameBoard[7][0] = new RookPiece('B'); MainGameBoard[7][1] = new KnightPiece('B'); MainGameBoard[7][2] = new BishopPiece('B'); MainGameBoard[7][3] = new KingPiece('B'); MainGameBoard[7][4] = new QueenPiece('B'); MainGameBoard[7][5] = new BishopPiece('B'); MainGameBoard[7][6] = new KnightPiece('B'); MainGameBoard[7][7] = new RookPiece('B'); // Allocate and place white pieces for (int iCol = 0; iCol < 8; ++iCol) { MainGameBoard[1][iCol] = new PawnPiece('W'); } MainGameBoard[0][0] = new RookPiece('W'); MainGameBoard[0][1] = new KnightPiece('W'); MainGameBoard[0][2] = new BishopPiece('W'); MainGameBoard[0][3] = new KingPiece('W'); MainGameBoard[0][4] = new QueenPiece('W'); MainGameBoard[0][5] = new BishopPiece('W'); MainGameBoard[0][6] = new KnightPiece('W'); MainGameBoard[0][7] = new RookPiece('W'); } ~ChessBoard() { for (int iRow = 0; iRow < 8; ++iRow) { for (int iCol = 0; iCol < 8; ++iCol) { delete MainGameBoard[iRow][iCol]; MainGameBoard[iRow][iCol] = 0; } } } void Print() { const int kiSquareWidth = 4; const int kiSquareHeight = 3; for (int iRow = 0; iRow < 8 * kiSquareHeight; ++iRow) { int iSquareRow = iRow / kiSquareHeight; // Print side border with numbering if (iRow % 3 == 1) { cout << '-' << (char)('1' + 7 - iSquareRow) << '-'; } else { cout << "---"; } // Print the chess board for (int iCol = 0; iCol < 8 * kiSquareWidth; ++iCol) { int iSquareCol = iCol / kiSquareWidth; if (((iRow % 3) == 1) && ((iCol % 4) == 1 || (iCol % 4) == 2) && MainGameBoard[7 - iSquareRow][iSquareCol] != 0) { if ((iCol % 4) == 1) { cout << MainGameBoard[7 - iSquareRow][iSquareCol]->GetColor(); } else { cout << MainGameBoard[7 - iSquareRow][iSquareCol]->GetPiece(); } } else { if ((iSquareRow + iSquareCol) % 2 == 1) { cout << '*'; } else { cout << ' '; } } } cout << endl; } // Print the bottom border with numbers for (int iRow = 0; iRow < kiSquareHeight; ++iRow) { if (iRow % 3 == 1) { cout << "---"; for (int iCol = 0; iCol < 8 * kiSquareWidth; ++iCol) { int iSquareCol = iCol / kiSquareWidth; if ((iCol % 4) == 1) { cout << (iSquareCol + 1); } else { cout << '-'; } } cout << endl; } else { for (int iCol = 1; iCol < 9 * kiSquareWidth; ++iCol) { cout << '-'; } cout << endl; } } } bool IsInCheck(char PieceColor) { // Find the king int iKingRow; int iKingCol; for (int iRow = 0; iRow < 8; ++iRow) { for (int iCol = 0; iCol < 8; ++iCol) { if (MainGameBoard[iRow][iCol] != 0) { if (MainGameBoard[iRow][iCol]->GetColor() == PieceColor) { if (MainGameBoard[iRow][iCol]->GetPiece() == 'K') { iKingRow = iRow; iKingCol = iCol; } } } } } // Run through the opponent's pieces and see if any can take the king for (int iRow = 0; iRow < 8; ++iRow) { for (int iCol = 0; iCol < 8; ++iCol) { if (MainGameBoard[iRow][iCol] != 0) { if (MainGameBoard[iRow][iCol]->GetColor() != PieceColor) { if (MainGameBoard[iRow][iCol]->IsLegalMove(iRow, iCol, iKingRow, iKingCol, MainGameBoard)) { return true; } } } } } return false; } bool CanMove(char PieceColor) { // Run through all pieces for (int iRow = 0; iRow < 8; ++iRow) { for (int iCol = 0; iCol < 8; ++iCol) { if (MainGameBoard[iRow][iCol] != 0) { // If it is a piece of the current player, see if it has a legal move if (MainGameBoard[iRow][iCol]->GetColor() == PieceColor) { for (int iMoveRow = 0; iMoveRow < 8; ++iMoveRow) { for (int iMoveCol = 0; iMoveCol < 8; ++iMoveCol) { if (MainGameBoard[iRow][iCol]->IsLegalMove(iRow, iCol, iMoveRow, iMoveCol, MainGameBoard)) { // Make move and check whether king is in check Piece *tempPiece = MainGameBoard[iMoveRow][iMoveCol]; MainGameBoard[iMoveRow][iMoveCol] = MainGameBoard[iRow][iCol]; MainGameBoard[iRow][iCol] = 0; bool moreMoves = !IsInCheck(PieceColor); // Undo the move MainGameBoard[iRow][iCol] = MainGameBoard[iMoveRow][iMoveCol]; MainGameBoard[iMoveRow][iMoveCol] = tempPiece; if (moreMoves) { return true; } } } } } } } } return false; } }; class Game { private: ChessBoard board; char currentPlayer; public: Game() : currentPlayer('W') {} ~Game() {} void Start() { do { GetNextMove(board.MainGameBoard); changeTurn(); } while (!IsGameOver()); board.Print(); } void GetNextMove(Piece *GameBoard[8][8]) { bool isValidMove = false; do { system("clear"); board.Print(); // Get input and convert to coordinates cout << currentPlayer << "'s Move: "; int startMove; cin >> startMove; int startRow = (startMove / 10) - 1; int startCol = (startMove % 10) - 1; cout << "To: "; int endMove; cin >> endMove; int iEndRow = (endMove / 10) - 1; int iEndCol = (endMove % 10) - 1; // Check that the indices are in range // and that the source and destination are different if ((startRow >= 0 && startRow <= 7) && (startCol >= 0 && startCol <= 7) && (iEndRow >= 0 && iEndRow <= 7) && (iEndCol >= 0 && iEndCol <= 7)) { // Additional checks in here Piece *currentPiece = GameBoard[startRow][startCol]; // Check that the piece is the correct color if ((currentPiece != nullptr) && (currentPiece->GetColor() == currentPlayer)) { // Check that the destination is a valid destination if (currentPiece->IsLegalMove(startRow, startCol, iEndRow, iEndCol, GameBoard)) { // Make the move Piece *tempPiece = GameBoard[iEndRow][iEndCol]; GameBoard[iEndRow][iEndCol] = GameBoard[startRow][startCol]; GameBoard[startRow][startCol] = 0; // Make sure that the current player is not in check if (!board.IsInCheck(currentPlayer)) { delete tempPiece; isValidMove = true; } else { // Undo the last move GameBoard[startRow][startCol] = GameBoard[iEndRow][iEndCol]; GameBoard[iEndRow][iEndCol] = tempPiece; } } } } if (!isValidMove) { cout << "Invalid Move!" << endl; } } while (!isValidMove); } void changeTurn() { currentPlayer = (currentPlayer == 'W') ? 'B' : 'W'; } bool IsGameOver() { // Check that the current player can move // If not, we have a stalemate or checkmate bool moreMoves(false); moreMoves = board.CanMove(currentPlayer); if (!moreMoves) { if (board.IsInCheck(currentPlayer)) { changeTurn(); std::cout << "Checkmate, " << currentPlayer << " Wins!" << std::endl; } else { std::cout << "Draw!" << std::endl; } } return !moreMoves; } }; int main() { Game game; game.Start(); return 0; }
Preview:
downloadDownload PNG
downloadDownload JPEG
downloadDownload SVG
Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!
Click to optimize width for Twitter