most basic best move search

This commit is contained in:
Moritz 2025-11-14 23:32:52 +01:00
parent af2178abad
commit 9d527634eb
7 changed files with 105 additions and 4 deletions

18
src/eval/basic.rs Normal file
View file

@ -0,0 +1,18 @@
use crate::board::{Board, Color, PieceType};
pub fn evaluate_board(board: &Board) -> i32 {
let mut score = 0_i32;
score += board.pieces[PieceType::Pawn as usize][Color::White as usize].count_ones() as i32 * 100;
score += board.pieces[PieceType::Knight as usize][Color::White as usize].count_ones() as i32 * 300;
score += board.pieces[PieceType::Bishop as usize][Color::White as usize].count_ones() as i32 * 300;
score += board.pieces[PieceType::Rook as usize][Color::White as usize].count_ones() as i32 * 500;
score += board.pieces[PieceType::Queen as usize][Color::White as usize].count_ones() as i32 * 900;
score += board.pieces[PieceType::King as usize][Color::White as usize].count_ones() as i32 * 10000;
score -= board.pieces[PieceType::Pawn as usize][Color::Black as usize].count_ones() as i32 * 100;
score -= board.pieces[PieceType::Knight as usize][Color::Black as usize].count_ones() as i32 * 300;
score -= board.pieces[PieceType::Bishop as usize][Color::Black as usize].count_ones() as i32 * 300;
score -= board.pieces[PieceType::Rook as usize][Color::Black as usize].count_ones() as i32 * 500;
score -= board.pieces[PieceType::Queen as usize][Color::Black as usize].count_ones() as i32 * 900;
score -= board.pieces[PieceType::King as usize][Color::Black as usize].count_ones() as i32 * 10000;
score
}

1
src/eval/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod basic;

View file

@ -2,5 +2,7 @@ pub mod board;
pub mod r#move; pub mod r#move;
pub mod square; pub mod square;
pub mod movegen; pub mod movegen;
mod display; pub mod eval;
mod parsing; pub mod display;
pub mod parsing;
pub mod search;

View file

@ -2,8 +2,15 @@ use chess_engine::board::Board;
use chess_engine::movegen::generate_pseudo_legal_moves; use chess_engine::movegen::generate_pseudo_legal_moves;
use chess_engine::movegen::legal_check::is_king_attacked; use chess_engine::movegen::legal_check::is_king_attacked;
use chess_engine::r#move::*; use chess_engine::r#move::*;
use chess_engine::search::minimax;
use chess_engine::search::minimax::minimax;
fn main() { fn main() {
let mut board = Board::from_fen("rnb1kbnr/pppppppp/8/8/8/4q3/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
let (opt_move, _) = minimax(&mut board, 5);
if let Some(mv) = opt_move {
println!("Found best move: {}", mv)
} else {
println!("No moves found")
}
} }

View file

@ -1,4 +1,5 @@
use std::slice; use std::slice;
use std::ops::{Index, IndexMut};
use crate::square::Square; use crate::square::Square;
use crate::board::PieceType; use crate::board::PieceType;
use crate::square::SQUARES; use crate::square::SQUARES;
@ -103,6 +104,22 @@ impl MoveList {
} }
} }
impl Index<usize> for MoveList {
type Output = Move;
#[inline(always)]
fn index(&self, index: usize) -> &Self::Output {
&self.moves[..self.count][index]
}
}
impl IndexMut<usize> for MoveList {
#[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.moves[..self.count][index]
}
}
pub struct UndoMove { pub struct UndoMove {
pub mv: Move, pub mv: Move,
pub captured_piece: Option<PieceType>, pub captured_piece: Option<PieceType>,

55
src/search/minimax.rs Normal file
View file

@ -0,0 +1,55 @@
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_king_attacked;
use crate::r#move::{Move, MoveList};
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 minimax(board: &mut Board, depth: u8) -> (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;
let mut legal_moves_found = false;
for mv in list.iter() {
let undo_mv = board.make_move(*mv);
let is_illegal = is_king_attacked(board);
if is_illegal {
board.undo_move(undo_mv);
continue;
}
legal_moves_found = true;
let (_, score) = minimax(board, depth - 1);
let current_score = -score;
if current_score > best_score {
best_score = current_score;
best_move = Some(*mv);
}
board.undo_move(undo_mv);
}
if !legal_moves_found {
if is_king_attacked(board) {
return (None, -i32::MAX);
} else {
return (None, 0);
}
}
(best_move, best_score)
}

1
src/search/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod minimax;