Ver Fonte

Added checkers

Vsevolod Levitan há 11 meses atrás
pai
commit
7fb2d4fed5

+ 31 - 0
Checkers/Checkers.sln

@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.11.34909.67
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Checkers", "Checkers\Checkers.vcxproj", "{6CF13D28-AE3B-4D11-A64C-546D175B34CE}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{6CF13D28-AE3B-4D11-A64C-546D175B34CE}.Debug|x64.ActiveCfg = Debug|x64
+		{6CF13D28-AE3B-4D11-A64C-546D175B34CE}.Debug|x64.Build.0 = Debug|x64
+		{6CF13D28-AE3B-4D11-A64C-546D175B34CE}.Debug|x86.ActiveCfg = Debug|Win32
+		{6CF13D28-AE3B-4D11-A64C-546D175B34CE}.Debug|x86.Build.0 = Debug|Win32
+		{6CF13D28-AE3B-4D11-A64C-546D175B34CE}.Release|x64.ActiveCfg = Release|x64
+		{6CF13D28-AE3B-4D11-A64C-546D175B34CE}.Release|x64.Build.0 = Release|x64
+		{6CF13D28-AE3B-4D11-A64C-546D175B34CE}.Release|x86.ActiveCfg = Release|Win32
+		{6CF13D28-AE3B-4D11-A64C-546D175B34CE}.Release|x86.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {34A18C7F-47F4-4B97-8617-942B13547D37}
+	EndGlobalSection
+EndGlobal

+ 1 - 0
Checkers/Checkers/Checker.h

@@ -0,0 +1 @@
+#pragma once

+ 204 - 0
Checkers/Checkers/CheckerBoard.cpp

@@ -0,0 +1,204 @@
+#include "CheckerBoard.h"
+
+
+void CheckerBoard::placeChecker(CheckerPosition position, CheckerPiece checker) {
+    board[position.y][position.x] = checker;
+}
+
+CheckerBoard::CheckerBoard() {}
+
+CheckerBoard CheckerBoard::loadFromFile(string filename) {
+    CheckerBoard board = CheckerBoard();
+
+    ifstream file(filename);
+    string line;
+
+    int color = WHITE;
+
+    while (getline(file, line)) {
+        if (line.find("White:") != string::npos) {
+            color = WHITE;
+        }
+
+        else if (line.find("Black:") != string::npos) {
+            color = BLACK;
+        }
+
+        else if (!line.empty()) {
+            if (line[0] == 'M') board.placeChecker(CheckerPosition(line.substr(1, 2)), color == WHITE ? CheckerPiece::WHITE_KING : CheckerPiece::BLACK_KING);
+            else board.placeChecker(CheckerPosition(line), color == WHITE ? CheckerPiece::WHITE : CheckerPiece::BLACK);
+        }
+    }
+    file.close();
+
+    return board;
+}
+
+int CheckerBoard::getCheckerAt(CheckerPosition pos) const {
+    if (!pos.isValid()) return 0;
+
+    return board[pos.y][pos.x];
+}
+
+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;
+}
+
+void CheckerBoard::print() const
+{
+    wcout << "--------------------------------" << endl;
+    for (int y = BOARD_SIZE-1; y >= 0; y--)
+    {
+        for (int x = 0; x < BOARD_SIZE; x++)
+        {
+            wcout << '|';
+            switch (board[y][x])
+            {
+            case CheckerPiece::BLACK:
+                wcout << L" ⬤ ";
+                break;
+            case CheckerPiece::WHITE:
+                wcout << L" ◯ ";
+                break;
+            case CheckerPiece::BLACK_KING:
+                wcout << L" ◆ ";
+                break;
+            case CheckerPiece::WHITE_KING:
+                wcout << L" ◇ ";
+                break;
+            default:
+                wcout << L"   ";
+                break;
+            }
+        }
+
+        wcout << '|' << endl << "--------------------------------" << endl;
+    }
+}
+
+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))) {
+                generateMovesForPiece(CheckerPosition(i, j), moves);
+            }
+        }
+    }
+
+    return moves;
+}
+
+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];
+        }
+    }
+}
+
+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;
+        }
+    }
+    return score;
+}
+
+bool CheckerBoard::isGameOver() const {
+    bool whiteExists = false, blackExists = false;
+    for (int i = 0; i < BOARD_SIZE; ++i) {
+        for (int j = 0; j < BOARD_SIZE; ++j) {
+            if (board[i][j] == WHITE || board[i][j] == WHITE_KING) whiteExists = true;
+            if (board[i][j] == BLACK || board[i][j] == BLACK_KING) blackExists = true;
+        }
+    }
+    return !whiteExists || !blackExists;
+}
+
+void CheckerBoard::generateMovesForPiece(CheckerPosition pos, std::vector<CheckerBoard>& moves) const {
+    CheckerPiece piece = board[pos.y][pos.x];
+    int directions[4][2] = { {1, 1}, {1, -1}, {-1, 1}, {-1, -1} };
+
+    for (auto& dir : directions) {
+        CheckerPosition newpos(pos.x + dir[0], pos.y + dir[1]);
+
+        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;
+
+            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;
+            }
+
+            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;
+                }
+
+                moves.push_back(newBoard);
+                generateAdditionalCaptures(cpos, newBoard, moves);
+            }
+        }
+    }
+}
+
+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;
+    return true;
+}
+
+void CheckerBoard::generateAdditionalCaptures(CheckerPosition pos, CheckerBoard& currentBoard, std::vector<CheckerBoard>& moves) const {
+    CheckerPiece piece = currentBoard.board[pos.y][pos.x];
+    int directions[4][2] = { {1, 1}, {1, -1}, {-1, 1}, {-1, -1} };
+
+    for (auto& dir : directions) {
+        CheckerPosition npos(pos.x + dir[0], pos.y + dir[1]);
+        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;
+            }
+
+            moves.push_back(newBoard);
+            generateAdditionalCaptures(cpos, newBoard, moves);
+        }
+    }
+}
+
+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;
+    if ((piece == WHITE_KING || piece == BLACK_KING) && abs(cpos.y - pos.y) == 2 && abs(cpos.x - pos.x) == 2) return true;
+
+    return false;
+}

+ 117 - 0
Checkers/Checkers/CheckerBoard.h

@@ -0,0 +1,117 @@
+#ifndef CHECKERBOARD_H
+#define CHECKERBOARD_H
+
+#include <vector>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include "CheckerPiece.h"
+#include "CheckerPosition.h"
+
+using namespace std;
+
+const int BOARD_SIZE = 8;
+
+/// <summary>
+/// Represents a standard checker board
+/// </summary>
+class CheckerBoard {
+public:
+    CheckerPiece board[BOARD_SIZE][BOARD_SIZE];
+
+    CheckerBoard();
+
+    /// <summary>
+    /// Place a checker on the board
+    /// </summary>
+    /// <param name="checker">Checker instance</param>
+    /// <param name="color">Color of the checker (black or white)</param>
+    void placeChecker(CheckerPosition position, CheckerPiece checker);
+
+    /// <summary>
+    /// Load checkerboard from file
+    /// </summary>
+    /// <param name="filename">Path to the file</param>
+    static CheckerBoard loadFromFile(string filename);
+
+    /// <summary>
+    /// Move the checker from one position to another
+    /// </summary>
+    /// <param name="from">Old position of the checker</param>
+    /// <param name="to">New position of the checker</param>
+    void moveChecker(CheckerPosition from, CheckerPosition to);
+
+    /// <summary>
+    /// Get the color of the checker at the given position
+    /// </summary>
+    /// <param name="pos">The position of the checker</param>
+    /// <returns>Color of the checker (BLACK or WHITE)</returns>
+    int getCheckerAt(CheckerPosition pos) const;
+
+    /// <summary>
+    /// Print the checker board into the console
+    /// </summary>
+    void print() const;
+
+    /// <summary>
+    /// Generate all possible moves for the player
+    /// </summary>
+    /// <param name="isWhite">Whether the player plays white or not</param>
+    /// <returns>A vector of all possible future board branches</returns>
+    std::vector<CheckerBoard> generateLegalMoves(bool isWhite) const;
+
+    /// <summary>
+    /// Apply the future branch of the board
+    /// </summary>
+    /// <param name="move">A board copy representing a possible branch in the future</param>
+    void applyMove(const CheckerBoard& move);
+
+    /// <summary>
+    /// Evaluate the board
+    /// </summary>
+    /// <returns>The score of the board</returns>
+    int evaluate() const;
+
+    /// <summary>
+    /// Checks if the game is over
+    /// </summary>
+    /// <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>
+    /// <param name="oldPos">Previous position of the checker</param>
+    /// <param name="newPos">New position of the checker</param>
+    /// <param name="piece">Type of the checker</param>
+    /// <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>
+    /// <param name="pos">The old position of the checker</param>
+    /// <param name="newpos">The new position of the checker</param>
+    /// <param name="cpos">The position of the checker to be captured</param>
+    /// <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;
+};
+
+#endif

+ 8 - 0
Checkers/Checkers/CheckerConsts.h

@@ -0,0 +1,8 @@
+#pragma once
+#ifndef CHECKERCONSTS_H
+
+#define CHECKERCONSTS_H
+
+const int BOARD_SIZE = 8;
+
+#endif CHECKERCONSTS_H

+ 13 - 0
Checkers/Checkers/CheckerPiece.h

@@ -0,0 +1,13 @@
+#pragma once
+
+/// <summary>
+/// Represents a standard checker piece
+/// </summary>
+enum CheckerPiece
+{
+    NONE,
+    WHITE,
+    WHITE_KING,
+    BLACK,
+    BLACK_KING
+};

+ 17 - 0
Checkers/Checkers/CheckerPosition.cpp

@@ -0,0 +1,17 @@
+#include "CheckerPosition.h"
+#include "CheckerConsts.h"
+
+CheckerPosition::CheckerPosition(int x, int y) : x(x), y(y) {}
+
+CheckerPosition::CheckerPosition(std::string pos) {
+    x = pos[0] - 'A';
+    y = pos[1] - '1';
+}
+
+std::string CheckerPosition::to_string() const {
+    return std::string(1, 'A' + x) + std::to_string(y + 1);
+}
+
+bool CheckerPosition::isValid() const {
+    return x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE;
+}

+ 35 - 0
Checkers/Checkers/CheckerPosition.h

@@ -0,0 +1,35 @@
+#pragma once
+#include <string>
+
+/// <summary>
+/// Describes a checker board position
+/// </summary>
+class CheckerPosition {
+public:
+    int x, y;
+
+    /// <summary>
+    /// Create the position by its X and Y coordinates
+    /// </summary>
+    /// <param name="x">X coordinate</param>
+    /// <param name="y">Y coordinate</param>
+    CheckerPosition(int x, int y);
+
+    /// <summary>
+    /// Create the position by its text representation (eg "A1")
+    /// </summary>
+    /// <param name="pos">The position's text representation</param>
+    CheckerPosition(std::string pos);
+
+    /// <summary>
+    /// Get the text representation of the current position
+    /// </summary>
+    /// <returns>Text representation of the position</returns>
+    std::string to_string() const;
+
+    /// <summary>
+    /// Whether or not the given position is a valid checker position
+    /// </summary>
+    /// <returns>True if the position is valid</returns>
+    bool isValid() const;
+};

+ 145 - 0
Checkers/Checkers/Checkers.vcxproj

@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>17.0</VCProjectVersion>
+    <Keyword>Win32Proj</Keyword>
+    <ProjectGuid>{6cf13d28-ae3b-4d11-a64c-546d175b34ce}</ProjectGuid>
+    <RootNamespace>Checkers</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="CheckerPosition.cpp" />
+    <ClCompile Include="CheckerBoard.cpp" />
+    <ClCompile Include="CheckersAI.cpp" />
+    <ClCompile Include="main.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="CheckerConsts.h" />
+    <ClInclude Include="CheckerPiece.h" />
+    <ClInclude Include="CheckerPosition.h" />
+    <ClInclude Include="CheckerBoard.h" />
+    <ClInclude Include="CheckersAI.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 48 - 0
Checkers/Checkers/Checkers.vcxproj.filters

@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="CheckerBoard.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="CheckersAI.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="CheckerPosition.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="CheckerBoard.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="CheckersAI.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="CheckerPiece.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="CheckerPosition.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="CheckerConsts.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>

+ 58 - 0
Checkers/Checkers/CheckersAI.cpp

@@ -0,0 +1,58 @@
+#include "CheckersAI.h"
+
+
+CheckerBoard CheckersAI::findBestMove(const CheckerBoard& board, int depth) {
+    int alpha = std::numeric_limits<int>::min();
+    int beta = std::numeric_limits<int>::max();
+    int bestValue = isWhite ? std::numeric_limits<int>::min() : std::numeric_limits<int>::max();
+    CheckerBoard bestMove;
+
+    std::vector<CheckerBoard> moves = board.generateLegalMoves(isWhite);
+
+    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;
+            bestMove = move;
+            alpha = std::max(alpha, bestValue);
+        }
+        else if (!isWhite && value < bestValue) {
+            bestValue = value;
+            bestMove = move;
+            beta = std::min(beta, bestValue);
+        }
+        if (alpha >= beta) break;
+    }
+    return bestMove;
+}
+
+int CheckersAI::minimax(CheckerBoard board, int depth, int alpha, int beta, bool isMaximizing) {
+    if (depth == 0 || board.isGameOver()) {
+        return board.evaluate();
+    }
+
+    std::vector<CheckerBoard> moves = board.generateLegalMoves(isMaximizing);
+
+    if (isMaximizing) {
+        int maxEval = std::numeric_limits<int>::min();
+        for (const auto& move : moves) {
+            int eval = minimax(move, depth - 1, alpha, beta, false);
+            maxEval = std::max(maxEval, eval);
+            alpha = std::max(alpha, eval);
+            if (beta <= alpha) break;
+        }
+        return maxEval;
+    }
+    else {
+        int minEval = std::numeric_limits<int>::max();
+        for (const auto& move : moves) {
+            int eval = minimax(move, depth - 1, alpha, beta, true);
+            minEval = std::min(minEval, eval);
+            beta = std::min(beta, eval);
+            if (beta <= alpha) break;
+        }
+        return minEval;
+    }
+}

+ 15 - 0
Checkers/Checkers/CheckersAI.h

@@ -0,0 +1,15 @@
+#pragma once
+#include "CheckerBoard.h"
+
+
+class CheckersAI {
+public:
+    CheckersAI(bool isWhite) : isWhite(isWhite) {}
+
+    CheckerBoard findBestMove(const CheckerBoard& board, int depth);
+
+private:
+    bool isWhite;
+
+    int minimax(CheckerBoard board, int depth, int alpha, int beta, bool isMaximizing);
+};

+ 13 - 0
Checkers/Checkers/board.checkers

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

+ 39 - 0
Checkers/Checkers/main.cpp

@@ -0,0 +1,39 @@
+#include <iostream>
+#include "CheckerBoard.h"
+#include "CheckersAI.h"
+#include <io.h>
+#include <fcntl.h>
+
+int main()
+{
+    _setmode(_fileno(stdout), _O_U16TEXT);
+    _setmode(_fileno(stdin), _O_U16TEXT);
+    _setmode(_fileno(stderr), _O_U16TEXT);
+
+    CheckerBoard board = CheckerBoard::loadFromFile("board.checkers");
+
+    board.print();
+
+    wcout << "\n\n-----------\n\n";
+
+    CheckersAI whiteAI(true);
+    CheckersAI blackAI(false);
+
+    bool whiteTurn = true;
+    while (!board.isGameOver()) {
+        wcout << L"\n\n";
+
+        if (whiteTurn) {
+            CheckerBoard bestMove = whiteAI.findBestMove(board, 5);
+            board.applyMove(bestMove);
+        }
+        else {
+            CheckerBoard bestMove = blackAI.findBestMove(board, 5);
+            board.applyMove(bestMove);
+        }
+        whiteTurn = !whiteTurn;
+        board.print();
+    }
+
+    wcout << L"Game over!\n";
+}