Browse Source

Updated checkers

Vsevolod Levitan 10 tháng trước cách đây
mục cha
commit
a890814782

+ 107 - 52
Checkers/Checkers/CheckerBoard.cpp

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

+ 27 - 17
Checkers/Checkers/CheckerBoard.h

@@ -17,6 +17,9 @@ const int BOARD_SIZE = 8;
 /// </summary>
 class CheckerBoard {
 public:
+    std::string move = "";
+    CheckerPosition moveOldPos = CheckerPosition(-1, -1);
+    CheckerPosition moveNewPos = CheckerPosition(-1, -1);
     CheckerPiece board[BOARD_SIZE][BOARD_SIZE];
 
     CheckerBoard();
@@ -46,7 +49,14 @@ public:
     /// </summary>
     /// <param name="pos">The position of the checker</param>
     /// <returns>Color of the checker (BLACK or WHITE)</returns>
-    int getCheckerAt(CheckerPosition pos) const;
+    CheckerPiece getCheckerAt(CheckerPosition pos) const;
+
+    /// <summary>
+    /// Set checker at a given position
+    /// </summary>
+    /// <param name="pos">The position to place the checker to</param>
+    /// <param name="checker">The type of the checker</param>
+    void setCheckerAt(CheckerPosition pos, CheckerPiece checker);
 
     /// <summary>
     /// Print the checker board into the console
@@ -78,14 +88,6 @@ public:
     /// <returns>True if the game is over</returns>
     bool isGameOver() const;
 
-private:
-    /// <summary>
-    /// Generate all possible moves for a piece
-    /// </summary>
-    /// <param name="position">The position of the piece</param>
-    /// <param name="moves">A vector of possible alternative future boards</param>
-    void generateMovesForPiece(CheckerPosition position, std::vector<CheckerBoard>& moves) const;
-
     /// <summary>
     /// Check if the move is valid
     /// </summary>
@@ -95,14 +97,6 @@ private:
     /// <returns>True if the move is valid</returns>
     bool isValidMove(CheckerPosition oldPos, CheckerPosition newPos, CheckerPiece piece) const;
 
-    /// <summary>
-    /// Generate combination captures (>1 per move)
-    /// </summary>
-    /// <param name="position">The position of the checker</param>
-    /// <param name="currentBoard">Current board</param>
-    /// <param name="moves">Possible future moves</param>
-    void generateAdditionalCaptures(CheckerPosition position, CheckerBoard& currentBoard, std::vector<CheckerBoard>& moves) const;
-
     /// <summary>
     /// Whether the move is considered a valid capture
     /// </summary>
@@ -112,6 +106,22 @@ private:
     /// <param name="piece">Current checker piece</param>
     /// <returns>True if the move is a valid capture</returns>
     bool isValidCapture(CheckerPosition pos, CheckerPosition newpos, CheckerPosition cpos, CheckerPiece piece) const;
+
+private:
+    /// <summary>
+    /// Generate all possible moves for a piece
+    /// </summary>
+    /// <param name="position">The position of the piece</param>
+    /// <param name="moves">A vector of possible alternative future boards</param>
+    void generateMovesForPiece(CheckerPosition position, std::vector<CheckerBoard>& moves) const;
+
+    /// <summary>
+    /// Generate combination captures (>1 per move)
+    /// </summary>
+    /// <param name="position">The position of the checker</param>
+    /// <param name="currentBoard">Current board</param>
+    /// <param name="moves">Possible future moves</param>
+    void generateAdditionalCaptures(CheckerPosition position, CheckerBoard& currentBoard, std::vector<CheckerBoard>& moves) const;
 };
 
 #endif

+ 6 - 0
Checkers/Checkers/CheckerPosition.cpp

@@ -1,5 +1,6 @@
 #include "CheckerPosition.h"
 #include "CheckerConsts.h"
+#include <iostream>
 
 CheckerPosition::CheckerPosition(int x, int y) : x(x), y(y) {}
 
@@ -14,4 +15,9 @@ std::string CheckerPosition::to_string() const {
 
 bool CheckerPosition::isValid() const {
     return x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE;
+}
+
+std::string CheckerPosition::to_num_string() const
+{
+    return "(" + std::to_string(x) + ", " + std::to_string(y) + ")";
 }

+ 6 - 0
Checkers/Checkers/CheckerPosition.h

@@ -27,6 +27,12 @@ public:
     /// <returns>Text representation of the position</returns>
     std::string to_string() const;
 
+    /// <summary>
+    /// Get the number representation of the current position
+    /// </summary>
+    /// <returns>Number representation of the position</returns>
+    std::string to_num_string() const;
+
     /// <summary>
     /// Whether or not the given position is a valid checker position
     /// </summary>

+ 4 - 2
Checkers/Checkers/CheckersAI.cpp

@@ -9,9 +9,9 @@ CheckerBoard CheckersAI::findBestMove(const CheckerBoard& board, int depth) {
 
     std::vector<CheckerBoard> moves = board.generateLegalMoves(isWhite);
 
+    if (moves.size() == 0) throw exception();
+
     for (const auto& move : moves) {
-        std::wcout << "Move: \n";
-        move.print();
         int value = minimax(move, depth - 1, alpha, beta, !isWhite);
         if (isWhite && value > bestValue) {
             bestValue = value;
@@ -25,6 +25,8 @@ CheckerBoard CheckersAI::findBestMove(const CheckerBoard& board, int depth) {
         }
         if (alpha >= beta) break;
     }
+    wcout << "Best move: " << bestMove.move.c_str() << endl;
+
     return bestMove;
 }
 

+ 13 - 0
Checkers/Checkers/board - Copy.checkers

@@ -0,0 +1,13 @@
+White: 3
+F2
+G3
+H2
+Black: 8
+A7
+B8
+D8
+E7
+ME1
+MG7
+G5
+H8

+ 2 - 11
Checkers/Checkers/board.checkers

@@ -1,13 +1,4 @@
 White: 3
-F2
-G3
-H2
+C6
 Black: 8
-A7
-B8
-D8
-E7
-ME1
-MG7
-G5
-H8
+B5

+ 30 - 6
Checkers/Checkers/main.cpp

@@ -7,10 +7,8 @@
 int main()
 {
     _setmode(_fileno(stdout), _O_U16TEXT);
-    _setmode(_fileno(stdin), _O_U16TEXT);
-    _setmode(_fileno(stderr), _O_U16TEXT);
 
-    CheckerBoard board = CheckerBoard::loadFromFile("board.checkers");
+    CheckerBoard board = CheckerBoard::loadFromFile("board - Copy.checkers");
 
     board.print();
 
@@ -24,15 +22,41 @@ int main()
         wcout << L"\n\n";
 
         if (whiteTurn) {
-            CheckerBoard bestMove = whiteAI.findBestMove(board, 5);
+            wcout << "White: ";
+            CheckerBoard bestMove = whiteAI.findBestMove(board, 7);
             board.applyMove(bestMove);
         }
-        else {
-            CheckerBoard bestMove = blackAI.findBestMove(board, 5);
+        /*else {
+            wcout << "Black: ";
+            CheckerBoard bestMove = blackAI.findBestMove(board, 7);
             board.applyMove(bestMove);
+        }*/
+        else
+        {
+            wcout << "Old pos: ";
+            std::string inp;
+            cin >> inp;
+            CheckerPosition pos(inp);
+
+            wcout << "New pos: ";
+            std::string inp2;
+            cin >> inp2;
+            CheckerPosition newPos(inp2);
+
+            auto& b = board;
+
+            int dx = newPos.x - pos.x;
+            int dy = newPos.y - pos.y;
+            int cx = newPos.x + dx;
+            int cy = newPos.y + dy;
+
+            if (!b.isValidMove(pos, newPos, b.getCheckerAt(pos)) && !b.isValidCapture(pos, newPos, CheckerPosition(cx, cy), b.getCheckerAt(pos))) return -1;
+
+            board.moveChecker(pos, newPos);
         }
         whiteTurn = !whiteTurn;
         board.print();
+        //return 0;
     }
 
     wcout << L"Game over!\n";