alpha beta pruning
This commit is contained in:
parent
96ea7fd2c9
commit
eb19606360
6 changed files with 86 additions and 4 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
/target
|
/target
|
||||||
/.idea
|
/.idea
|
||||||
/Cargo.lock
|
/Cargo.lock
|
||||||
|
progress_tracking/~$progress.xlsx
|
||||||
BIN
progress_tracking/progress.xlsx
Normal file
BIN
progress_tracking/progress.xlsx
Normal file
Binary file not shown.
|
|
@ -40,7 +40,7 @@ fn main() {
|
||||||
// Record start time
|
// Record start time
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
|
|
||||||
let result = engine.search(4);
|
let result = engine.search(5);
|
||||||
|
|
||||||
// Calculate duration
|
// Calculate duration
|
||||||
let duration = start_time.elapsed();
|
let duration = start_time.elapsed();
|
||||||
|
|
@ -57,6 +57,8 @@ fn main() {
|
||||||
if result == *bm {
|
if result == *bm {
|
||||||
correct_tests += 1.0;
|
correct_tests += 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println!("{}%", (total_tests / (sts.len() as f32 / 100.0)) as u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", correct_tests / (total_tests / 100.0));
|
println!("{}", correct_tests / (total_tests / 100.0));
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// ... (your use statements)
|
// ... (your use statements)
|
||||||
use crate::board::Board;
|
use crate::board::Board;
|
||||||
use crate::r#move::Move;
|
use crate::r#move::Move;
|
||||||
use crate::search::minimax::minimax;
|
use crate::search::alpha_beta::alpha_beta;
|
||||||
|
|
||||||
pub struct Engine {
|
pub struct Engine {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
@ -33,7 +33,7 @@ impl Engine {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn search(&mut self, depth: u8) -> String {
|
pub fn search(&mut self, depth: u8) -> String {
|
||||||
let (opt_move, _score) = minimax(&mut self.board, depth, 0);
|
let (opt_move, _score) = alpha_beta(&mut self.board, depth, 0, -i32::MAX, i32::MAX);
|
||||||
|
|
||||||
if let Some(mv) = opt_move {
|
if let Some(mv) = opt_move {
|
||||||
mv.to_algebraic()
|
mv.to_algebraic()
|
||||||
|
|
|
||||||
78
src/search/alpha_beta.rs
Normal file
78
src/search/alpha_beta.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
use crate::board::{Board, Color}; // <-- Assuming you have a Color enum (e.g., Color::White, Color::Black)
|
||||||
|
use crate::eval::basic::evaluate_board;
|
||||||
|
use crate::movegen::generate_pseudo_legal_moves;
|
||||||
|
use crate::movegen::legal_check::is_other_king_attacked;
|
||||||
|
use crate::r#move::{Move, MoveList};
|
||||||
|
|
||||||
|
// A score high enough to be > any material eval, but low enough to not overflow when adding ply
|
||||||
|
const MATE_SCORE: i32 = 1_000_000;
|
||||||
|
|
||||||
|
fn evaluate_board_relative(board: &Board) -> i32 {
|
||||||
|
let static_eval = evaluate_board(board);
|
||||||
|
match board.side_to_move {
|
||||||
|
Color::White => static_eval,
|
||||||
|
Color::Black => -static_eval,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alpha_beta(
|
||||||
|
board: &mut Board,
|
||||||
|
depth: u8,
|
||||||
|
ply: u8,
|
||||||
|
mut alpha: i32,
|
||||||
|
beta: i32,
|
||||||
|
) -> (Option<Move>, i32) {
|
||||||
|
if depth == 0 {
|
||||||
|
return (None, evaluate_board_relative(board));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut list = MoveList::new();
|
||||||
|
generate_pseudo_legal_moves(board, &mut list);
|
||||||
|
let mut best_move: Option<Move> = None;
|
||||||
|
let mut best_score: i32 = -i32::MAX; // This is our local "worst case"
|
||||||
|
let mut legal_moves_found = false;
|
||||||
|
|
||||||
|
for mv in list.iter() {
|
||||||
|
let undo_mv = board.make_move(*mv);
|
||||||
|
let is_illegal = is_other_king_attacked(board);
|
||||||
|
if is_illegal {
|
||||||
|
board.undo_move(undo_mv);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
legal_moves_found = true;
|
||||||
|
|
||||||
|
// Recursive call with negated and swapped alpha/beta
|
||||||
|
let (_, score) = alpha_beta(board, depth - 1, ply + 1, -beta, -alpha);
|
||||||
|
let current_score = -score;
|
||||||
|
|
||||||
|
if current_score > best_score {
|
||||||
|
best_score = current_score;
|
||||||
|
best_move = Some(*mv);
|
||||||
|
}
|
||||||
|
|
||||||
|
board.undo_move(undo_mv);
|
||||||
|
|
||||||
|
// Alpha-Beta Pruning logic
|
||||||
|
if best_score > alpha {
|
||||||
|
alpha = best_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
if alpha >= beta {
|
||||||
|
break; // Beta cutoff (Pruning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !legal_moves_found {
|
||||||
|
if is_other_king_attacked(board) {
|
||||||
|
// Checkmate
|
||||||
|
// The score is *less* negative the *longer* it takes to be mated (higher ply)
|
||||||
|
// This translates to a *higher* score for the winner for a *faster* mate
|
||||||
|
return (None, -MATE_SCORE + (ply as i32));
|
||||||
|
} else {
|
||||||
|
// Stalemate
|
||||||
|
return (None, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(best_move, best_score)
|
||||||
|
}
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
pub mod minimax;
|
pub mod minimax;
|
||||||
|
pub mod alpha_beta;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue