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