implemented move ordering to improve on alpha_beta
pruning
This commit is contained in:
parent
10de9828be
commit
377e5dfdcc
@ -24,8 +24,9 @@ int main(int argc, char* argv[]) {
|
||||
Board b = Board::setup_fen_position(pos);
|
||||
|
||||
ai::v0_random p1(true, std::chrono::milliseconds(1000));
|
||||
// ai::v1_pure_minimax p2(false, std::chrono::milliseconds(150000));
|
||||
ai::v2_alpha_beta p2(false, std::chrono::milliseconds(150000));
|
||||
// ai::v1_pure_minimax p2(false, std::chrono::milliseconds(20000));
|
||||
// ai::v2_alpha_beta p2(false, std::chrono::milliseconds(20000));
|
||||
ai::v3_AB_ordering p2(false, std::chrono::milliseconds(20000));
|
||||
|
||||
NoOpView gui;
|
||||
AIvsAIController manual(b, gui, p1, p2);
|
||||
|
@ -54,4 +54,15 @@ namespace ai {
|
||||
Move _search(const Board&) override;
|
||||
int eval(const Board&) override;
|
||||
};
|
||||
|
||||
class v3_AB_ordering : public AI {
|
||||
// looks two moves ahead, with alpha-beta pruning, with move ordering
|
||||
int _search(const Board&, int, int, int);
|
||||
|
||||
public:
|
||||
v3_AB_ordering(bool w, std::chrono::milliseconds tt): AI(w, tt) {}
|
||||
|
||||
Move _search(const Board&) override;
|
||||
int eval(const Board&) override;
|
||||
};
|
||||
} // namespace ai
|
||||
|
99
cpp/src/model/ais/v3_AB_ordering.cpp
Normal file
99
cpp/src/model/ais/v3_AB_ordering.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include "../pieces/piece.hpp"
|
||||
#include "../utils/threadpool.hpp"
|
||||
#include "../utils/utils.hpp"
|
||||
#include "ai.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#define MULTITHREADED 1
|
||||
|
||||
|
||||
static int position_counter;
|
||||
|
||||
Move ai::v3_AB_ordering::_search(const Board& b) {
|
||||
position_counter = 0;
|
||||
std::vector<Move> moves = b.all_legal_moves();
|
||||
|
||||
Move best_move;
|
||||
int best_eval = -INFINITY;
|
||||
#if MULTITHREADED
|
||||
ThreadPool pool(std::thread::hardware_concurrency());
|
||||
|
||||
std::cout << "Have to look at " << moves.size() << " moves" << std::endl;
|
||||
|
||||
std::map<Move, std::future<int>> futures;
|
||||
for (const Move& move : moves) {
|
||||
Board tmp_board = b.make_move(move);
|
||||
futures.insert({move, pool.enqueue([&, tmp_board]() {
|
||||
return _search(tmp_board, 3, -INFINITY, INFINITY);
|
||||
})});
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
for (auto& [move, future] : futures) {
|
||||
int eval = future.get();
|
||||
counter++;
|
||||
if (!am_white)
|
||||
eval *= -1;
|
||||
if (eval > best_eval) {
|
||||
best_eval = eval;
|
||||
best_move = move;
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (const Move& move : moves) {
|
||||
Board tmp_board = b.make_move(move);
|
||||
std::cout << "Looking at " << move << std::endl;
|
||||
int eval = _search(tmp_board, 3);
|
||||
if (!am_white)
|
||||
eval *= -1;
|
||||
if (eval > best_eval) {
|
||||
best_eval = eval;
|
||||
best_move = move;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
std::cout << "Looked at " << position_counter << " positions" << std::endl;
|
||||
return best_move;
|
||||
}
|
||||
|
||||
int ai::v3_AB_ordering::_search(
|
||||
const Board& b, int depth, int alpha, int beta
|
||||
) {
|
||||
if (depth == 0 || stop_computation)
|
||||
return eval(b);
|
||||
|
||||
if (b.no_legal_moves()) {
|
||||
if (b.is_check())
|
||||
return -INFINITY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<Move> moves = b.all_legal_moves();
|
||||
std::sort(moves.begin(), moves.end(), [&](Move& m1, Move& m2) {
|
||||
return m1.score_guess(b) > m2.score_guess(b);
|
||||
});
|
||||
|
||||
Move best_move;
|
||||
for (const Move& move : moves) {
|
||||
Board tmp_board = b.make_move(move);
|
||||
int tmp_eval = -_search(tmp_board, depth - 1, -beta, -alpha);
|
||||
if (tmp_eval >= beta)
|
||||
return beta;
|
||||
alpha = std::max(alpha, tmp_eval);
|
||||
}
|
||||
return alpha;
|
||||
}
|
||||
|
||||
int ai::v3_AB_ordering::eval(const Board& b) {
|
||||
position_counter++;
|
||||
int white_eval = count_material(b, Colour::White);
|
||||
int black_eval = count_material(b, Colour::Black);
|
||||
|
||||
int evaluation = white_eval - black_eval;
|
||||
|
||||
int perspective = b.white_to_play ? 1 : -1;
|
||||
|
||||
return perspective * evaluation;
|
||||
}
|
@ -19,7 +19,7 @@ std::vector<Move> pawn_moves(const Board& b, const Coords xy) {
|
||||
ret.push_back(Move{
|
||||
xy.to_index(),
|
||||
left.to_index(),
|
||||
(int8_t) (my_colour | piece)
|
||||
(Piece) (my_colour | piece)
|
||||
});
|
||||
else
|
||||
ret.push_back(Move{xy.to_index(), left.to_index()});
|
||||
@ -39,7 +39,7 @@ std::vector<Move> pawn_moves(const Board& b, const Coords xy) {
|
||||
ret.push_back(Move{
|
||||
xy.to_index(),
|
||||
right.to_index(),
|
||||
(int8_t) (my_colour | piece)
|
||||
(Piece) (my_colour | piece)
|
||||
});
|
||||
else
|
||||
ret.push_back(Move{xy.to_index(), right.to_index()});
|
||||
@ -68,7 +68,7 @@ std::vector<Move> pawn_moves(const Board& b, const Coords xy) {
|
||||
ret.push_back(Move{
|
||||
xy.to_index(),
|
||||
new_xy.to_index(),
|
||||
.promoting_to = (int8_t) (my_colour | piece)
|
||||
(Piece) (my_colour | piece)
|
||||
});
|
||||
else
|
||||
ret.push_back(Move{
|
||||
|
@ -9,7 +9,6 @@ keep_only_blocking(const std::vector<Move> candidates, const Board& board) {
|
||||
if (candidates.size() == 0)
|
||||
return {};
|
||||
|
||||
Colour my_colour = board.colour_at(candidates[0].source_square);
|
||||
std::vector<Move> ret;
|
||||
for (Move move : candidates) {
|
||||
Board board_after_move = board.make_move(move, false);
|
||||
|
19
cpp/src/model/utils/move.cpp
Normal file
19
cpp/src/model/utils/move.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include "move.hpp"
|
||||
|
||||
#include "../board/board.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
int Move::score_guess(const Board& b) const {
|
||||
int ret = 0;
|
||||
|
||||
Piece me_piece = b.piece_at(source_square);
|
||||
Piece captured_piece = b.piece_at(target_square);
|
||||
|
||||
if (captured_piece != Piece::None)
|
||||
ret += 10 * piece_value(captured_piece) - piece_value(me_piece);
|
||||
|
||||
if (promoting_to != Piece::None)
|
||||
ret += piece_value(promoting_to);
|
||||
|
||||
return ret;
|
||||
}
|
@ -11,7 +11,9 @@ struct Move {
|
||||
int8_t source_square;
|
||||
int8_t target_square;
|
||||
|
||||
int8_t promoting_to = Piece::None;
|
||||
Piece promoting_to = Piece::None;
|
||||
|
||||
int score_guess(const Board&) const;
|
||||
|
||||
std::string to_string() const {
|
||||
std::stringstream ss;
|
||||
|
@ -9,30 +9,27 @@ std::vector<int8_t> to_target_square(std::vector<Move> moves) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int piece_value(Piece p) {
|
||||
switch (p) {
|
||||
case Piece::Pawn:
|
||||
return PawnValue;
|
||||
case Piece::Knigt:
|
||||
return KnightValue;
|
||||
case Piece::Bishop:
|
||||
return BishopValue;
|
||||
case Piece::Rook:
|
||||
return RookValue;
|
||||
case Piece::Queen:
|
||||
return QueenValue;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int count_material(const Board& b, int8_t colour) {
|
||||
int ret = 0;
|
||||
for (int i = 0; i < 64; i++) {
|
||||
for (int i = 0; i < 64; i++)
|
||||
if (b.colour_at(i) == colour)
|
||||
switch (b.piece_at(i)) {
|
||||
case Piece::Pawn:
|
||||
ret += PawnValue;
|
||||
break;
|
||||
case Piece::Knigt:
|
||||
ret += KnightValue;
|
||||
break;
|
||||
case Piece::Bishop:
|
||||
ret += BishopValue;
|
||||
break;
|
||||
case Piece::Rook:
|
||||
ret += RookValue;
|
||||
break;
|
||||
case Piece::Queen:
|
||||
ret += QueenValue;
|
||||
break;
|
||||
case Piece::King:
|
||||
case Piece::None:
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret += piece_value(b.piece_at(i));
|
||||
return ret;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
std::vector<int8_t> to_target_square(std::vector<Move>);
|
||||
int count_material(const Board&, int8_t);
|
||||
int piece_value(Piece);
|
||||
|
||||
const int INFINITY = std::numeric_limits<int>::max();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user