Added threading, optimizations
This commit is contained in:
parent
cbdf377c86
commit
66195867eb
|
@ -46,6 +46,9 @@
|
||||||
"stdexcept": "cpp",
|
"stdexcept": "cpp",
|
||||||
"streambuf": "cpp",
|
"streambuf": "cpp",
|
||||||
"cinttypes": "cpp",
|
"cinttypes": "cpp",
|
||||||
"typeinfo": "cpp"
|
"typeinfo": "cpp",
|
||||||
|
"thread": "cpp",
|
||||||
|
"condition_variable": "cpp",
|
||||||
|
"mutex": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,7 +25,7 @@
|
||||||
],
|
],
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": false
|
"isDefault": true
|
||||||
},
|
},
|
||||||
"detail": "Task generated by Debugger."
|
"detail": "Task generated by Debugger."
|
||||||
},
|
},
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
],
|
],
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": true
|
"isDefault": false
|
||||||
},
|
},
|
||||||
"detail": ""
|
"detail": ""
|
||||||
}
|
}
|
||||||
|
|
157
board.cpp
157
board.cpp
|
@ -559,7 +559,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||||
|
|
||||||
if (KING == piece_type)
|
if (KING == piece_type)
|
||||||
{
|
{
|
||||||
int king_offsets[8][2] = {{-1,-1},{0,-1},{1,-1},{-1,0},{1,0},{1,-1},{1,0},{1,1}};
|
int king_offsets[8][2] = {{-1,-1},{0,-1},{1,-1},{-1,0},{1,0},{-1,1},{0,1},{1,1}};
|
||||||
for(int i = 0; i < 8; i++)
|
for(int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
int x1 = x+king_offsets[i][0];
|
int x1 = x+king_offsets[i][0];
|
||||||
|
@ -794,13 +794,26 @@ void Board::do_move(int space_from, int space_to, bool holding_k)
|
||||||
|
|
||||||
if (castling)
|
if (castling)
|
||||||
{
|
{
|
||||||
|
game_board[xt][yt] = Piece();
|
||||||
|
game_board[xf][yf] = Piece();
|
||||||
|
if (xt == 7)
|
||||||
|
{
|
||||||
|
xt = 6;
|
||||||
|
xf = 5;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xt = 2;
|
||||||
|
xf = 3;
|
||||||
|
}
|
||||||
game_board[xf][yf] = target_piece;
|
game_board[xf][yf] = target_piece;
|
||||||
|
game_board[xt][yt] = cur_piece;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
game_board[xf][yf] = Piece();
|
game_board[xf][yf] = Piece();
|
||||||
|
game_board[xt][yt] = cur_piece;
|
||||||
}
|
}
|
||||||
game_board[xt][yt] = cur_piece;
|
|
||||||
|
|
||||||
if(is_check(enemy_team))
|
if(is_check(enemy_team))
|
||||||
{
|
{
|
||||||
|
@ -813,6 +826,144 @@ void Board::do_move(int space_from, int space_to, bool holding_k)
|
||||||
selected_space = -1;
|
selected_space = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Board::get_attackers_for_space(int space_to)
|
||||||
|
{
|
||||||
|
int xt=space_to%BOARD_SIZE,yt=space_to/BOARD_SIZE;
|
||||||
|
|
||||||
|
if (space_to < 0 || space_to > BOARD_SIZE*BOARD_SIZE || game_board[xt][yt].get_team() == NO_TEAM)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_attackers = 0;
|
||||||
|
|
||||||
|
Team enemy_team = (game_board[xt][yt].get_team() == WHITE)?BLACK:WHITE;
|
||||||
|
|
||||||
|
int forward_direction = (game_board[xt][yt].get_team() == WHITE)?-1:1;
|
||||||
|
|
||||||
|
if (game_board[xt][yt].get_type() == PAWN && en_passant == xt+(yt-forward_direction)*BOARD_SIZE)
|
||||||
|
{
|
||||||
|
int en_passent_offsets[2][2] = {{-1,0},{1,0}};
|
||||||
|
|
||||||
|
for(int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
int xf = xt+en_passent_offsets[i][0], yf = yt+en_passent_offsets[i][1];
|
||||||
|
|
||||||
|
if (xf < 0 || xf >= BOARD_SIZE || yf < 0 || yf >= BOARD_SIZE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game_board[xf][yf].get_team() != enemy_team || game_board[xf][yf].get_type() != PAWN)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_attackers++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pawn_offsets[2][2] = {{-1, -1*forward_direction},{1, -1*forward_direction}};
|
||||||
|
for(int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
int xf = xt+pawn_offsets[i][0], yf = yt+pawn_offsets[i][1];
|
||||||
|
|
||||||
|
if (xf < 0 || xf >= BOARD_SIZE || yf < 0 || yf >= BOARD_SIZE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game_board[xf][yf].get_team() != enemy_team || game_board[xf][yf].get_type() != PAWN)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_attackers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int king_offsets[8][2] = {{-1,-1},{0,-1},{1,-1},{-1,0},{1,0},{1,-1},{1,0},{1,1}};
|
||||||
|
|
||||||
|
for(int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
int xf = xt+king_offsets[i][0], yf = yt+king_offsets[i][1];
|
||||||
|
|
||||||
|
if (xf < 0 || xf >= BOARD_SIZE || yf < 0 || yf >= BOARD_SIZE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game_board[xf][yf].get_team() != enemy_team || (game_board[xf][yf].get_type() != KING && game_board[xf][yf].get_vis() != HIDDEN))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_attackers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int knight_offsets[8][2] = {{-1,2},{1,2},{-1,-2},{1,-2},{-2,1},{2,1},{-2,-1},{2,-1}};
|
||||||
|
for(int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
int xf = xt+knight_offsets[i][0], yf = yt+knight_offsets[i][1];
|
||||||
|
|
||||||
|
if (xf < 0 || xf >= BOARD_SIZE || yf < 0 || yf >= BOARD_SIZE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game_board[xf][yf].get_team() != enemy_team || game_board[xf][yf].get_type() != KNIGHT)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_attackers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int queen_bishop_offsets[28][2] = {{1,1},{2,2},{3,3},{4,4},{5,5},{6,6},{7,7},
|
||||||
|
{-1,1},{-2,2},{-3,3},{-4,4},{-5,5},{-6,6},{-7,7},
|
||||||
|
{1,-1},{2,-2},{3,-3},{4,-4},{5,-5},{6,-6},{7,-7},
|
||||||
|
{-1,-1},{-2,-2},{-3,-3},{-4,-4},{-5,-5},{-6,-6},{-7,-7}};
|
||||||
|
for(int i = 0; i < 28; i++)
|
||||||
|
{
|
||||||
|
int xf = xt+queen_bishop_offsets[i][0], yf = yt+queen_bishop_offsets[i][1];
|
||||||
|
|
||||||
|
if (xf < 0 || xf >= BOARD_SIZE || yf < 0 || yf >= BOARD_SIZE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game_board[xf][yf].get_team() != enemy_team || (game_board[xf][yf].get_type() != QUEEN && game_board[xf][yf].get_type() != BISHOP && game_board[xf][yf].get_vis() != SHOWN))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_attackers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int queen_rook_offsets[28][2] = {{1,0},{2,0},{3,0},{4,0},{5,0},{6,0},{7,0},
|
||||||
|
{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},
|
||||||
|
{-1,0},{-2,0},{-3,0},{-4,0},{-5,0},{-6,0},{-7,0},
|
||||||
|
{0,-1},{0,-2},{0,-3},{0,-4},{0,-5},{0,-6},{0,-7}};
|
||||||
|
|
||||||
|
for(int i = 0; i < 28; i++)
|
||||||
|
{
|
||||||
|
int xf = xt+queen_rook_offsets[i][0], yf = yt+queen_rook_offsets[i][1];
|
||||||
|
|
||||||
|
if (xf < 0 || xf >= BOARD_SIZE || yf < 0 || yf >= BOARD_SIZE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game_board[xf][yf].get_team() != enemy_team || (game_board[xf][yf].get_type() != QUEEN && game_board[xf][yf].get_type() != ROOK && game_board[xf][yf].get_vis() != SHOWN))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_attackers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_attackers;
|
||||||
|
}
|
||||||
|
|
||||||
MoveType Board::can_move(int space_from, int space_to)
|
MoveType Board::can_move(int space_from, int space_to)
|
||||||
{
|
{
|
||||||
if (space_from < 0 || space_to < 0 || space_from >= BOARD_SIZE*BOARD_SIZE || space_to >= BOARD_SIZE*BOARD_SIZE)
|
if (space_from < 0 || space_to < 0 || space_from >= BOARD_SIZE*BOARD_SIZE || space_to >= BOARD_SIZE*BOARD_SIZE)
|
||||||
|
@ -862,7 +1013,7 @@ MoveType Board::can_move(int space_from, int space_to)
|
||||||
|
|
||||||
bool Board::does_move_solve_check(int space_from, int space_to)
|
bool Board::does_move_solve_check(int space_from, int space_to)
|
||||||
{
|
{
|
||||||
Board test_board(make_FEN());
|
Board test_board(*this);
|
||||||
test_board.do_move(space_from, space_to, false);
|
test_board.do_move(space_from, space_to, false);
|
||||||
return !test_board.is_check(game_board[space_from%BOARD_SIZE][space_from/BOARD_SIZE].get_team());
|
return !test_board.is_check(game_board[space_from%BOARD_SIZE][space_from/BOARD_SIZE].get_team());
|
||||||
}
|
}
|
|
@ -39,6 +39,8 @@ public:
|
||||||
bool is_mate(Team team);
|
bool is_mate(Team team);
|
||||||
|
|
||||||
void do_move(int space_from, int space_to, bool holding_k);
|
void do_move(int space_from, int space_to, bool holding_k);
|
||||||
|
|
||||||
|
int get_attackers_for_space(int space_to);
|
||||||
private:
|
private:
|
||||||
Piece game_board[BOARD_SIZE][BOARD_SIZE];
|
Piece game_board[BOARD_SIZE][BOARD_SIZE];
|
||||||
Team active_color;
|
Team active_color;
|
||||||
|
|
357
game.cpp
357
game.cpp
|
@ -5,6 +5,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
uint64_t time_milli() {
|
uint64_t time_milli() {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
@ -71,6 +72,8 @@ void Game::tick()
|
||||||
x/=SPRITE_SIZE;
|
x/=SPRITE_SIZE;
|
||||||
y/=SPRITE_SIZE;
|
y/=SPRITE_SIZE;
|
||||||
process_click(x,y);
|
process_click(x,y);
|
||||||
|
|
||||||
|
draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,10 +118,16 @@ void Game::process_click(int x, int y)
|
||||||
|
|
||||||
void Game::do_ai_move()
|
void Game::do_ai_move()
|
||||||
{
|
{
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
std::mutex mut_result_check;
|
||||||
int best_move_weight = std::numeric_limits<int>::min();
|
int best_move_weight = std::numeric_limits<int>::min();
|
||||||
int best_move_from = -1;
|
int best_move_from = -1;
|
||||||
int best_move_to = -1;
|
int best_move_to = -1;
|
||||||
bool best_move_makes_queen = false;
|
bool best_move_makes_queen = false;
|
||||||
|
int a = std::numeric_limits<int>::min();
|
||||||
|
|
||||||
|
Board board_copy = Board(board);
|
||||||
|
|
||||||
for(int x = 0; x < BOARD_SIZE; x++)
|
for(int x = 0; x < BOARD_SIZE; x++)
|
||||||
{
|
{
|
||||||
for(int y = 0; y < BOARD_SIZE; y++)
|
for(int y = 0; y < BOARD_SIZE; y++)
|
||||||
|
@ -126,178 +135,239 @@ void Game::do_ai_move()
|
||||||
Piece cur_piece = board.get_piece(x,y);
|
Piece cur_piece = board.get_piece(x,y);
|
||||||
if (cur_piece.get_team() == BLACK)
|
if (cur_piece.get_team() == BLACK)
|
||||||
{
|
{
|
||||||
std::vector<int> piece_moves = board.get_moves_for_space(x,y, true);
|
threads.push_back(std::thread([&mut_result_check, &best_move_weight, &best_move_from, &best_move_to, &best_move_makes_queen, &a, x, y, &board_copy](){
|
||||||
for (unsigned int i = 0; i < piece_moves.size(); i++)
|
std::vector<int> piece_moves = board_copy.get_moves_for_space(x,y, true);
|
||||||
{
|
Piece cur_piece = board_copy.get_piece(x,y);
|
||||||
Board test_board(board.make_FEN());
|
|
||||||
test_board.do_move(x+y*BOARD_SIZE, piece_moves[i], false);
|
|
||||||
|
|
||||||
int board_value = minimax(test_board, 3, std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), false);
|
|
||||||
|
|
||||||
if (board_value > best_move_weight)
|
|
||||||
{
|
|
||||||
best_move_weight = board_value;
|
|
||||||
best_move_from = x+y*BOARD_SIZE;
|
|
||||||
best_move_to = piece_moves[i];
|
|
||||||
best_move_makes_queen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cur_piece.get_type() == PAWN || (piece_moves[i]/BOARD_SIZE) == 7)
|
|
||||||
{
|
|
||||||
Board test_board1 = Board(board.make_FEN());
|
|
||||||
test_board1.do_move(x+y*BOARD_SIZE, piece_moves[i], true);
|
|
||||||
|
|
||||||
if (test_board1.make_FEN().compare(test_board.make_FEN()) != 0)
|
|
||||||
{
|
|
||||||
board_value = minimax(test_board1, 3, std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), false);
|
|
||||||
|
|
||||||
if (board_value > best_move_weight)
|
|
||||||
{
|
|
||||||
best_move_weight = board_value;
|
|
||||||
best_move_from = x+y*BOARD_SIZE;
|
|
||||||
best_move_to = piece_moves[i];
|
|
||||||
best_move_makes_queen = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
board.do_move(best_move_from, best_move_to, best_move_makes_queen);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Game::minimax(Board current_board, int depth, int a, int b, bool maximizing)
|
|
||||||
{
|
|
||||||
if (depth == 0 || current_board.is_mate(current_board.get_active_color()))
|
|
||||||
{
|
|
||||||
return board_heuristic(current_board);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maximizing)
|
|
||||||
{
|
|
||||||
int best_move_weight = std::numeric_limits<int>::min();
|
|
||||||
for(int x = 0; x < BOARD_SIZE; x++)
|
|
||||||
{
|
|
||||||
for(int y = 0; y < BOARD_SIZE; y++)
|
|
||||||
{
|
|
||||||
Piece cur_piece = current_board.get_piece(x,y);
|
|
||||||
if (cur_piece.get_team() == BLACK)
|
|
||||||
{
|
|
||||||
std::vector<int> piece_moves = current_board.get_moves_for_space(x,y, true);
|
|
||||||
for (unsigned int i = 0; i < piece_moves.size(); i++)
|
for (unsigned int i = 0; i < piece_moves.size(); i++)
|
||||||
{
|
{
|
||||||
Board test_board(current_board.make_FEN());
|
Board test_board(board_copy);
|
||||||
test_board.do_move(x+y*BOARD_SIZE, piece_moves[i], false);
|
test_board.do_move(x+y*BOARD_SIZE, piece_moves[i], false);
|
||||||
|
|
||||||
int board_value = minimax(test_board, depth-1, a, b, false);
|
int board_value = minimax(test_board, 4, 5, a, std::numeric_limits<int>::max(), false);
|
||||||
|
|
||||||
|
mut_result_check.lock();
|
||||||
if (board_value > best_move_weight)
|
if (board_value > best_move_weight)
|
||||||
{
|
{
|
||||||
best_move_weight = board_value;
|
best_move_weight = board_value;
|
||||||
}
|
best_move_from = x+y*BOARD_SIZE;
|
||||||
|
best_move_to = piece_moves[i];
|
||||||
if (best_move_weight >= b)
|
best_move_makes_queen = false;
|
||||||
{
|
|
||||||
return best_move_weight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (best_move_weight > a)
|
if (best_move_weight > a)
|
||||||
{
|
{
|
||||||
a = best_move_weight;
|
a = best_move_weight;
|
||||||
}
|
}
|
||||||
|
mut_result_check.unlock();
|
||||||
|
|
||||||
if (cur_piece.get_type() == PAWN || (piece_moves[i]/BOARD_SIZE) == 7)
|
if (cur_piece.get_type() == PAWN || (piece_moves[i]/BOARD_SIZE) == 7)
|
||||||
{
|
{
|
||||||
test_board = Board(current_board.make_FEN());
|
Board test_board1 = Board(board_copy);
|
||||||
test_board.do_move(x+y*BOARD_SIZE, piece_moves[i], true);
|
test_board1.do_move(x+y*BOARD_SIZE, piece_moves[i], true);
|
||||||
|
|
||||||
board_value = minimax(test_board, depth-1, a, b, false);
|
if (test_board1.make_FEN().compare(board_copy.make_FEN()) != 0)
|
||||||
|
|
||||||
if (board_value > best_move_weight)
|
|
||||||
{
|
{
|
||||||
best_move_weight = board_value;
|
board_value = minimax(test_board1, 4, 5, a, std::numeric_limits<int>::max(), false);
|
||||||
}
|
|
||||||
|
|
||||||
if (best_move_weight >= b)
|
mut_result_check.lock();
|
||||||
{
|
if (board_value > best_move_weight)
|
||||||
return best_move_weight;
|
{
|
||||||
}
|
best_move_weight = board_value;
|
||||||
|
best_move_from = x+y*BOARD_SIZE;
|
||||||
|
best_move_to = piece_moves[i];
|
||||||
|
best_move_makes_queen = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (best_move_weight > a)
|
if (best_move_weight > a)
|
||||||
{
|
{
|
||||||
a = best_move_weight;
|
a = best_move_weight;
|
||||||
|
}
|
||||||
|
mut_result_check.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::thread& cur_thread : threads)
|
||||||
|
{
|
||||||
|
cur_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
board.do_move(best_move_from, best_move_to, best_move_makes_queen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Game::minimax(Board current_board, int depth, int max_depth, int a, int b, bool maximizing)
|
||||||
|
{
|
||||||
|
if (depth == 0 || current_board.is_mate(current_board.get_active_color()))
|
||||||
|
{
|
||||||
|
return board_heuristic(current_board);
|
||||||
|
}
|
||||||
|
|
||||||
|
int best_move_weight = maximizing?std::numeric_limits<int>::min():std::numeric_limits<int>::max();
|
||||||
|
bool a_eject = false, b_eject = false;
|
||||||
|
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
std::mutex mut_result_check;
|
||||||
|
int finished_threads = 0;
|
||||||
|
std::mutex mut_finished_threads;
|
||||||
|
|
||||||
|
for(int x = 0; x < BOARD_SIZE && !a_eject && !b_eject; x++)
|
||||||
|
{
|
||||||
|
for(int y = 0; y < BOARD_SIZE && !a_eject && !b_eject; y++)
|
||||||
|
{
|
||||||
|
if (current_board.get_piece(x,y).get_team() == (maximizing?BLACK:WHITE))
|
||||||
|
{
|
||||||
|
if (depth == max_depth-1)
|
||||||
|
{
|
||||||
|
if (threads.size()-finished_threads <= 4)
|
||||||
|
{
|
||||||
|
threads.push_back(std::thread([&finished_threads, &mut_finished_threads, &mut_result_check, current_board, x, y, depth, max_depth, &best_move_weight, &a, &b, &a_eject, &b_eject, maximizing](){
|
||||||
|
minimax_evaluate(mut_result_check, current_board, x, y, depth, max_depth, best_move_weight, a, b, a_eject, b_eject, maximizing);
|
||||||
|
mut_finished_threads.lock();
|
||||||
|
finished_threads++;
|
||||||
|
mut_finished_threads.unlock();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
minimax_evaluate(mut_result_check, current_board, x, y, depth, max_depth, best_move_weight, a, b, a_eject, b_eject, maximizing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
minimax_evaluate(mut_result_check, current_board, x, y, depth, max_depth, best_move_weight, a, b, a_eject, b_eject, maximizing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return best_move_weight;
|
for (std::thread& cur_thread : threads)
|
||||||
|
{
|
||||||
|
cur_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
return best_move_weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::minimax_evaluate(std::mutex& mut_result_check, Board current_board, int x, int y, int depth, int max_depth, int& best_move_weight, int& a, int& b, bool& a_eject, bool& b_eject, bool maximizing)
|
||||||
|
{
|
||||||
|
Piece cur_piece = current_board.get_piece(x,y);
|
||||||
|
std::vector<int> piece_moves = current_board.get_moves_for_space(x,y, true);
|
||||||
|
|
||||||
|
if (maximizing)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < piece_moves.size(); i++)
|
||||||
|
{
|
||||||
|
Board test_board(current_board);
|
||||||
|
test_board.do_move(x+y*BOARD_SIZE, piece_moves[i], false);
|
||||||
|
|
||||||
|
int board_value = minimax(test_board, depth-1, max_depth, a, b, false);
|
||||||
|
|
||||||
|
mut_result_check.lock();
|
||||||
|
if (board_value > best_move_weight)
|
||||||
|
{
|
||||||
|
best_move_weight = board_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best_move_weight >= b)
|
||||||
|
{
|
||||||
|
b_eject = true;
|
||||||
|
mut_result_check.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best_move_weight > a)
|
||||||
|
{
|
||||||
|
a = best_move_weight;
|
||||||
|
}
|
||||||
|
mut_result_check.unlock();
|
||||||
|
|
||||||
|
if (cur_piece.get_type() == PAWN || (piece_moves[i]/BOARD_SIZE) == (maximizing?7:0))
|
||||||
|
{
|
||||||
|
test_board = Board(current_board);
|
||||||
|
test_board.do_move(x+y*BOARD_SIZE, piece_moves[i], true);
|
||||||
|
|
||||||
|
board_value = minimax(test_board, depth-1, max_depth, a, b, false);
|
||||||
|
|
||||||
|
mut_result_check.lock();
|
||||||
|
if (board_value > best_move_weight)
|
||||||
|
{
|
||||||
|
best_move_weight = board_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best_move_weight >= b)
|
||||||
|
{
|
||||||
|
b_eject = true;
|
||||||
|
mut_result_check.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best_move_weight > a)
|
||||||
|
{
|
||||||
|
a = best_move_weight;
|
||||||
|
}
|
||||||
|
mut_result_check.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int best_move_weight = std::numeric_limits<int>::max();
|
for (unsigned int i = 0; i < piece_moves.size(); i++)
|
||||||
for(int x = 0; x < BOARD_SIZE; x++)
|
|
||||||
{
|
{
|
||||||
for(int y = 0; y < BOARD_SIZE; y++)
|
Board test_board(current_board);
|
||||||
|
test_board.do_move(x+y*BOARD_SIZE, piece_moves[i], false);
|
||||||
|
|
||||||
|
int board_value = minimax(test_board, depth-1, max_depth, a, b, true);
|
||||||
|
|
||||||
|
mut_result_check.lock();
|
||||||
|
if (board_value < best_move_weight)
|
||||||
{
|
{
|
||||||
Piece cur_piece = current_board.get_piece(x,y);
|
best_move_weight = board_value;
|
||||||
if (cur_piece.get_team() == WHITE)
|
}
|
||||||
|
|
||||||
|
if (best_move_weight <= a)
|
||||||
|
{
|
||||||
|
a_eject = true;
|
||||||
|
mut_result_check.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best_move_weight < b)
|
||||||
|
{
|
||||||
|
b = best_move_weight;
|
||||||
|
}
|
||||||
|
mut_result_check.unlock();
|
||||||
|
|
||||||
|
if (cur_piece.get_type() == PAWN || (piece_moves[i]/BOARD_SIZE) == (maximizing?7:0))
|
||||||
|
{
|
||||||
|
test_board = Board(current_board);
|
||||||
|
test_board.do_move(x+y*BOARD_SIZE, piece_moves[i], true);
|
||||||
|
|
||||||
|
board_value = minimax(test_board, depth-1, max_depth, a, b, true);
|
||||||
|
|
||||||
|
mut_result_check.lock();
|
||||||
|
if (board_value < best_move_weight)
|
||||||
{
|
{
|
||||||
std::vector<int> piece_moves = current_board.get_moves_for_space(x,y, true);
|
best_move_weight = board_value;
|
||||||
for (unsigned int i = 0; i < piece_moves.size(); i++)
|
|
||||||
{
|
|
||||||
Board test_board(current_board.make_FEN());
|
|
||||||
test_board.do_move(x+y*BOARD_SIZE, piece_moves[i], false);
|
|
||||||
|
|
||||||
int board_value = minimax(test_board, depth-1, a, b, true);
|
|
||||||
|
|
||||||
if (board_value < best_move_weight)
|
|
||||||
{
|
|
||||||
best_move_weight = board_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (best_move_weight <= a)
|
|
||||||
{
|
|
||||||
return best_move_weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (best_move_weight < b)
|
|
||||||
{
|
|
||||||
b = best_move_weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cur_piece.get_type() == PAWN || (piece_moves[i]/BOARD_SIZE) == 0)
|
|
||||||
{
|
|
||||||
test_board = Board(current_board.make_FEN());
|
|
||||||
test_board.do_move(x+y*BOARD_SIZE, piece_moves[i], true);
|
|
||||||
|
|
||||||
board_value = minimax(test_board, depth-1, a, b, true);
|
|
||||||
|
|
||||||
if (board_value < best_move_weight)
|
|
||||||
{
|
|
||||||
best_move_weight = board_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (best_move_weight <= a)
|
|
||||||
{
|
|
||||||
return best_move_weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (best_move_weight < b)
|
|
||||||
{
|
|
||||||
b = best_move_weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (best_move_weight <= a)
|
||||||
|
{
|
||||||
|
a_eject = true;
|
||||||
|
mut_result_check.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best_move_weight < b)
|
||||||
|
{
|
||||||
|
b = best_move_weight;
|
||||||
|
}
|
||||||
|
mut_result_check.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return best_move_weight;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +375,12 @@ int Game::board_heuristic(Board current_board)
|
||||||
{
|
{
|
||||||
int heuristic = 0;
|
int heuristic = 0;
|
||||||
int piece_weights[2][7] = {{-900, -90, -30, -30, -50, -10, 0}, {900, 90, 30, 30, 50, 10, 0}};
|
int piece_weights[2][7] = {{-900, -90, -30, -30, -50, -10, 0}, {900, 90, 30, 30, 50, 10, 0}};
|
||||||
|
|
||||||
|
///Calculate the weight of an unknown piece for both teams
|
||||||
|
//The weight of an unknown piece is 2 times the average of the remaining unrevealed pieces
|
||||||
|
//The weight is 2 times so that the AI understands that the hidden pieces are valuable hidden, otherwise the average
|
||||||
|
//is less than that of Rooks, making the AI always reveal its rooks.
|
||||||
|
//In order to still sometimes prefer revealing, the number of vulnerabilities will be considered later into a pieces weight.
|
||||||
int unknown_white_count = 0;
|
int unknown_white_count = 0;
|
||||||
int unknown_black_count = 0;
|
int unknown_black_count = 0;
|
||||||
for(int x = 0; x < BOARD_SIZE; x++)
|
for(int x = 0; x < BOARD_SIZE; x++)
|
||||||
|
@ -323,12 +398,12 @@ int Game::board_heuristic(Board current_board)
|
||||||
{
|
{
|
||||||
if (cur_piece.get_team() == WHITE)
|
if (cur_piece.get_team() == WHITE)
|
||||||
{
|
{
|
||||||
piece_weights[WHITE][UNKNOWN] += piece_weights[WHITE][cur_piece.get_type()];
|
piece_weights[WHITE][UNKNOWN] += 2*piece_weights[WHITE][cur_piece.get_type()];
|
||||||
unknown_white_count++;
|
unknown_white_count++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
piece_weights[BLACK][UNKNOWN] += piece_weights[BLACK][cur_piece.get_type()];
|
piece_weights[BLACK][UNKNOWN] += 2*piece_weights[BLACK][cur_piece.get_type()];
|
||||||
unknown_black_count++;
|
unknown_black_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,7 +435,11 @@ int Game::board_heuristic(Board current_board)
|
||||||
cur_piece = Piece(UNKNOWN, cur_piece.get_team(), SHOWN);
|
cur_piece = Piece(UNKNOWN, cur_piece.get_team(), SHOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
heuristic += piece_weights[cur_piece.get_team()][cur_piece.get_type()];
|
int adden = piece_weights[cur_piece.get_team()][cur_piece.get_type()];
|
||||||
|
|
||||||
|
int found_attackers = current_board.get_attackers_for_space(x+y*BOARD_SIZE);
|
||||||
|
|
||||||
|
heuristic += adden/((found_attackers!=0)?2:1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
game.hpp
7
game.hpp
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "SDL2/SDL.h"
|
#include "SDL2/SDL.h"
|
||||||
|
|
||||||
#include "board.hpp"
|
#include "board.hpp"
|
||||||
|
@ -18,8 +20,9 @@ private:
|
||||||
void process_click(int x, int y);
|
void process_click(int x, int y);
|
||||||
|
|
||||||
void do_ai_move();
|
void do_ai_move();
|
||||||
int minimax(Board current_board, int depth, int a, int b, bool maximizing);
|
static int minimax(Board current_board, int depth, int max_depth, int a, int b, bool maximizing);
|
||||||
int board_heuristic(Board current_board);
|
static void minimax_evaluate(std::mutex& mut_result_check, Board current_board, int x, int y, int depth, int max_depth, int& best_move_weight, int& a, int& b, bool& a_eject, bool& b_eject, bool maximizing);
|
||||||
|
static int board_heuristic(Board current_board);
|
||||||
|
|
||||||
SDL_Window* window;
|
SDL_Window* window;
|
||||||
SDL_Surface* surface;
|
SDL_Surface* surface;
|
||||||
|
|
Loading…
Reference in New Issue