|
@@ -1,8 +1,9 @@
|
|
|
#include "CheckerBoard.h"
|
|
|
+#include <iostream>
|
|
|
|
|
|
|
|
|
void CheckerBoard::placeChecker(CheckerPosition position, CheckerPiece checker) {
|
|
|
- board[position.y][position.x] = checker;
|
|
|
+ board[position.x][position.y] = checker;
|
|
|
}
|
|
|
|
|
|
CheckerBoard::CheckerBoard() {}
|
|
@@ -31,30 +32,45 @@ CheckerBoard CheckerBoard::loadFromFile(string filename) {
|
|
|
}
|
|
|
file.close();
|
|
|
|
|
|
+ for (int i = 0; i < BOARD_SIZE; i++)
|
|
|
+ {
|
|
|
+ for (int j = 0; j < BOARD_SIZE; j++)
|
|
|
+ {
|
|
|
+ CheckerPosition pos(i, j);
|
|
|
+ CheckerPiece piece = board.getCheckerAt(pos);
|
|
|
+ if (piece != WHITE && piece != WHITE_KING && piece != BLACK && piece != BLACK_KING) board.setCheckerAt(pos, CheckerPiece::NONE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
return board;
|
|
|
}
|
|
|
|
|
|
-int CheckerBoard::getCheckerAt(CheckerPosition pos) const {
|
|
|
- if (!pos.isValid()) return 0;
|
|
|
+CheckerPiece CheckerBoard::getCheckerAt(CheckerPosition pos) const {
|
|
|
+ if (!pos.isValid()) return CheckerPiece::NONE;
|
|
|
|
|
|
- return board[pos.y][pos.x];
|
|
|
+ return board[pos.x][pos.y];
|
|
|
+}
|
|
|
+
|
|
|
+void CheckerBoard::setCheckerAt(CheckerPosition pos, CheckerPiece checker)
|
|
|
+{
|
|
|
+ board[pos.x][pos.y] = checker;
|
|
|
}
|
|
|
|
|
|
void CheckerBoard::moveChecker(CheckerPosition from, CheckerPosition to) {
|
|
|
- CheckerPiece checker = board[from.y][from.x];
|
|
|
- board[from.y][from.x] = CheckerPiece::NONE;
|
|
|
- board[to.y][to.x] = checker;
|
|
|
+ CheckerPiece checker = getCheckerAt(from);
|
|
|
+ setCheckerAt(from, CheckerPiece::NONE);
|
|
|
+ setCheckerAt(to, checker);
|
|
|
}
|
|
|
|
|
|
void CheckerBoard::print() const
|
|
|
{
|
|
|
- wcout << "--------------------------------" << endl;
|
|
|
- for (int y = BOARD_SIZE-1; y >= 0; y--)
|
|
|
+ wcout << "--A---B---C---D---E---F---G---H---" << endl;
|
|
|
+ for (int y = BOARD_SIZE - 1; y >= 0; y--)
|
|
|
{
|
|
|
for (int x = 0; x < BOARD_SIZE; x++)
|
|
|
{
|
|
|
wcout << '|';
|
|
|
- switch (board[y][x])
|
|
|
+ switch (board[x][y])
|
|
|
{
|
|
|
case CheckerPiece::BLACK:
|
|
|
wcout << L" ⬤ ";
|
|
@@ -68,13 +84,13 @@ void CheckerBoard::print() const
|
|
|
case CheckerPiece::WHITE_KING:
|
|
|
wcout << L" ◇ ";
|
|
|
break;
|
|
|
- default:
|
|
|
+ case CheckerPiece::NONE:
|
|
|
wcout << L" ";
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- wcout << '|' << endl << "--------------------------------" << endl;
|
|
|
+ wcout << "| " << y+1 << endl << "-------------------------------- " << endl;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -82,8 +98,9 @@ std::vector<CheckerBoard> CheckerBoard::generateLegalMoves(bool isWhite) const {
|
|
|
std::vector<CheckerBoard> moves;
|
|
|
for (int i = 0; i < BOARD_SIZE; ++i) {
|
|
|
for (int j = 0; j < BOARD_SIZE; ++j) {
|
|
|
- if ((isWhite && (board[i][j] == WHITE || board[i][j] == WHITE_KING)) ||
|
|
|
- (!isWhite && (board[i][j] == BLACK || board[i][j] == BLACK_KING))) {
|
|
|
+ CheckerPiece checker = getCheckerAt(CheckerPosition(i, j));
|
|
|
+ if ((isWhite && (checker == WHITE || checker == WHITE_KING)) ||
|
|
|
+ (!isWhite && (checker == BLACK || checker == BLACK_KING))) {
|
|
|
generateMovesForPiece(CheckerPosition(i, j), moves);
|
|
|
}
|
|
|
}
|
|
@@ -95,7 +112,7 @@ std::vector<CheckerBoard> CheckerBoard::generateLegalMoves(bool isWhite) const {
|
|
|
void CheckerBoard::applyMove(const CheckerBoard& move) {
|
|
|
for (int i = 0; i < BOARD_SIZE; ++i) {
|
|
|
for (int j = 0; j < BOARD_SIZE; ++j) {
|
|
|
- board[i][j] = move.board[i][j];
|
|
|
+ setCheckerAt(CheckerPosition(i, j), move.getCheckerAt(CheckerPosition(i, j)));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -104,10 +121,11 @@ int CheckerBoard::evaluate() const {
|
|
|
int score = 0;
|
|
|
for (int i = 0; i < BOARD_SIZE; ++i) {
|
|
|
for (int j = 0; j < BOARD_SIZE; ++j) {
|
|
|
- if (board[i][j] == WHITE) score += 1;
|
|
|
- else if (board[i][j] == WHITE_KING) score += 3;
|
|
|
- else if (board[i][j] == BLACK) score -= 1;
|
|
|
- else if (board[i][j] == BLACK_KING) score -= 3;
|
|
|
+ CheckerPiece checker = getCheckerAt(CheckerPosition(i, j));
|
|
|
+ if (checker == WHITE) score += 1;
|
|
|
+ else if (checker == WHITE_KING) score += 3;
|
|
|
+ else if (checker == BLACK) score -= 1;
|
|
|
+ else if (checker == BLACK_KING) score -= 3;
|
|
|
}
|
|
|
}
|
|
|
return score;
|
|
@@ -125,7 +143,7 @@ bool CheckerBoard::isGameOver() const {
|
|
|
}
|
|
|
|
|
|
void CheckerBoard::generateMovesForPiece(CheckerPosition pos, std::vector<CheckerBoard>& moves) const {
|
|
|
- CheckerPiece piece = board[pos.y][pos.x];
|
|
|
+ CheckerPiece piece = getCheckerAt(pos);
|
|
|
int directions[4][2] = { {1, 1}, {1, -1}, {-1, 1}, {-1, -1} };
|
|
|
|
|
|
for (auto& dir : directions) {
|
|
@@ -133,43 +151,71 @@ void CheckerBoard::generateMovesForPiece(CheckerPosition pos, std::vector<Checke
|
|
|
|
|
|
if (isValidMove(pos, newpos, piece)) {
|
|
|
CheckerBoard newBoard = *this;
|
|
|
- newBoard.board[newpos.y][newpos.x] = newBoard.board[pos.y][pos.x];
|
|
|
- newBoard.board[pos.y][pos.x] = CheckerPiece::NONE;
|
|
|
+ newBoard.moveChecker(pos, newpos);
|
|
|
+ newBoard.move = pos.to_num_string() + " -> " + newpos.to_num_string();
|
|
|
+ newBoard.moveOldPos = pos;
|
|
|
+ newBoard.moveNewPos = newpos;
|
|
|
|
|
|
- if ((piece == WHITE && newpos.y == 0) || (piece == BLACK && newpos.y == BOARD_SIZE - 1)) {
|
|
|
- newBoard.board[newpos.y][newpos.x] = (piece == WHITE) ? WHITE_KING : BLACK_KING;
|
|
|
+ if ((piece == WHITE && newpos.y == BOARD_SIZE - 1) || (piece == BLACK && newpos.y == 0)) {
|
|
|
+ newBoard.setCheckerAt(newpos, (piece == WHITE) ? WHITE_KING : BLACK_KING);
|
|
|
}
|
|
|
|
|
|
moves.push_back(newBoard);
|
|
|
+ }
|
|
|
|
|
|
- CheckerPosition cpos(pos.x + 2 * dir[0], pos.y + 2 * dir[1]);
|
|
|
- if (isValidCapture(pos, newpos, cpos, piece)) {
|
|
|
- CheckerBoard newBoard = *this;
|
|
|
- newBoard.board[cpos.y][cpos.x] = newBoard.board[pos.y][pos.x];
|
|
|
- newBoard.board[pos.y][pos.x] = CheckerPiece::NONE;
|
|
|
- newBoard.board[newpos.y][newpos.x] = CheckerPiece::NONE;
|
|
|
-
|
|
|
- if ((piece == WHITE && cpos.y == 0) || (piece == BLACK && cpos.y == BOARD_SIZE - 1)) {
|
|
|
- newBoard.board[cpos.y][cpos.x] = (piece == WHITE) ? WHITE_KING : BLACK_KING;
|
|
|
- }
|
|
|
+ CheckerPosition cpos(pos.x + 2 * dir[0], pos.y + 2 * dir[1]);
|
|
|
+ if (isValidCapture(pos, newpos, cpos, piece)) {
|
|
|
+ CheckerBoard newBoard = *this;
|
|
|
+ CheckerPiece checker = newBoard.getCheckerAt(pos);
|
|
|
+ newBoard.setCheckerAt(newpos, CheckerPiece::NONE);
|
|
|
+ newBoard.setCheckerAt(pos, CheckerPiece::NONE);
|
|
|
+ newBoard.setCheckerAt(cpos, checker);
|
|
|
|
|
|
- moves.push_back(newBoard);
|
|
|
- generateAdditionalCaptures(cpos, newBoard, moves);
|
|
|
+ if ((piece == WHITE && newpos.y == BOARD_SIZE-1) || (piece == BLACK && cpos.y == 0)) {
|
|
|
+ newBoard.setCheckerAt(cpos, (piece == WHITE) ? WHITE_KING : BLACK_KING);
|
|
|
}
|
|
|
+
|
|
|
+ moves.push_back(newBoard);
|
|
|
+ //generateAdditionalCaptures(cpos, newBoard, moves);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /*for (auto& move : moves)
|
|
|
+ {
|
|
|
+ wcout << "Move: \n";
|
|
|
+ move.print();
|
|
|
+ }*/
|
|
|
}
|
|
|
|
|
|
bool CheckerBoard::isValidMove(CheckerPosition oldPos, CheckerPosition newPos, CheckerPiece piece) const {
|
|
|
- if (newPos.x < 0 || newPos.x >= BOARD_SIZE || newPos.y < 0 || newPos.y >= BOARD_SIZE) return false;
|
|
|
- if (board[newPos.y][newPos.x] != CheckerPiece::NONE) return false;
|
|
|
- if (piece == WHITE && newPos.y <= oldPos.y) return false;
|
|
|
- if (piece == BLACK && newPos.y >= oldPos.y) return false;
|
|
|
+ //wcout << "Old: " << oldPos.x << ", " << oldPos.y << "; New: " << newPos.x << ", " << newPos.y << "; Piece: " << piece << "; NPiece: " << getCheckerAt(newPos) << endl;
|
|
|
+ //wcout << "New Pos: " << newPos.to_num_string().c_str() << "; MoveOldPos: " << moveOldPos.to_num_string().c_str() << endl;
|
|
|
+ if (piece == CheckerPiece::WHITE_KING || piece == CheckerPiece::BLACK_KING)
|
|
|
+ {
|
|
|
+ if (oldPos.x == newPos.x || oldPos.y == newPos.y) return false;
|
|
|
+ bool isWhite = piece == CheckerPiece::WHITE_KING;
|
|
|
+
|
|
|
+ int cx = newPos.x > oldPos.x ? 1 : -1;
|
|
|
+ int cy = newPos.y > oldPos.y ? 1 : -1;
|
|
|
+ for (int x = oldPos.x + cx; x != newPos.x; x += cx)
|
|
|
+ {
|
|
|
+ for (int y = oldPos.y + cy; y != newPos.y; y += cy)
|
|
|
+ {
|
|
|
+ CheckerPiece other = getCheckerAt(CheckerPosition(x, y));
|
|
|
+ if (isWhite && (other == CheckerPiece::WHITE || other == CheckerPiece::WHITE_KING)) return false;
|
|
|
+ else if (!isWhite && (other == CheckerPiece::BLACK || other == CheckerPiece::BLACK_KING)) return false;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (!newPos.isValid()) return false;
|
|
|
+ if (getCheckerAt(newPos) != CheckerPiece::NONE) return false;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void CheckerBoard::generateAdditionalCaptures(CheckerPosition pos, CheckerBoard& currentBoard, std::vector<CheckerBoard>& moves) const {
|
|
|
- CheckerPiece piece = currentBoard.board[pos.y][pos.x];
|
|
|
+ CheckerPiece piece = currentBoard.getCheckerAt(pos);
|
|
|
int directions[4][2] = { {1, 1}, {1, -1}, {-1, 1}, {-1, -1} };
|
|
|
|
|
|
for (auto& dir : directions) {
|
|
@@ -177,14 +223,21 @@ void CheckerBoard::generateAdditionalCaptures(CheckerPosition pos, CheckerBoard&
|
|
|
CheckerPosition cpos(pos.x + 2 * dir[0], pos.y + 2 * dir[0]);
|
|
|
if (isValidCapture(pos, npos, cpos, piece)) {
|
|
|
CheckerBoard newBoard = currentBoard;
|
|
|
- newBoard.board[cpos.y][cpos.x] = newBoard.board[pos.y][pos.x];
|
|
|
- newBoard.board[pos.y][pos.x] = CheckerPiece::NONE;
|
|
|
- newBoard.board[npos.y][npos.x] = CheckerPiece::NONE;
|
|
|
|
|
|
- if ((piece == WHITE && cpos.y == 0) || (piece == BLACK && cpos.y == BOARD_SIZE - 1)) {
|
|
|
- newBoard.board[cpos.y][cpos.x] = (piece == WHITE) ? WHITE_KING : BLACK_KING;
|
|
|
+ wcout << "OldBoard: " << endl;
|
|
|
+ newBoard.print();
|
|
|
+
|
|
|
+ newBoard.setCheckerAt(cpos, newBoard.getCheckerAt(pos));
|
|
|
+ newBoard.setCheckerAt(pos, CheckerPiece::NONE);
|
|
|
+ newBoard.setCheckerAt(npos, CheckerPiece::NONE);
|
|
|
+
|
|
|
+ if ((piece == WHITE && cpos.x == BOARD_SIZE-1) || (piece == BLACK && cpos.x == 0)) {
|
|
|
+ newBoard.setCheckerAt(cpos, (piece == WHITE) ? WHITE_KING : BLACK_KING);
|
|
|
}
|
|
|
|
|
|
+ wcout << "NewBoard: " << endl;
|
|
|
+ newBoard.print();
|
|
|
+
|
|
|
moves.push_back(newBoard);
|
|
|
generateAdditionalCaptures(cpos, newBoard, moves);
|
|
|
}
|
|
@@ -192,12 +245,14 @@ void CheckerBoard::generateAdditionalCaptures(CheckerPosition pos, CheckerBoard&
|
|
|
}
|
|
|
|
|
|
bool CheckerBoard::isValidCapture(CheckerPosition pos, CheckerPosition newPos, CheckerPosition cpos, CheckerPiece piece) const {
|
|
|
- if (cpos.y < 0 || cpos.y >= BOARD_SIZE || cpos.x < 0 || cpos.x >= BOARD_SIZE) return false;
|
|
|
- if (board[cpos.y][cpos.x] != CheckerPiece::NONE) return false;
|
|
|
- if (board[newPos.y][newPos.x] == CheckerPiece::NONE) return false;
|
|
|
-
|
|
|
- if (piece == WHITE && (board[newPos.y][newPos.x] == BLACK || board[newPos.y][newPos.x] == BLACK_KING)) return true;
|
|
|
- if (piece == BLACK && (board[newPos.y][newPos.x] == WHITE || board[newPos.y][newPos.x] == WHITE_KING)) return true;
|
|
|
+ CheckerPiece oldC = getCheckerAt(pos);
|
|
|
+ CheckerPiece newC = getCheckerAt(newPos);
|
|
|
+ CheckerPiece cC = getCheckerAt(cpos);
|
|
|
+ if (!cpos.isValid()) return false;
|
|
|
+ if (newC == CheckerPiece::NONE) return false;
|
|
|
+
|
|
|
+ if (piece == WHITE && (newC == BLACK || newC == BLACK_KING)) return true;
|
|
|
+ if (piece == BLACK && (newC == WHITE || newC == WHITE_KING)) return true;
|
|
|
if ((piece == WHITE_KING || piece == BLACK_KING) && abs(cpos.y - pos.y) == 2 && abs(cpos.x - pos.x) == 2) return true;
|
|
|
|
|
|
return false;
|