feat: basic basic search

This commit is contained in:
dogeystamp 2024-10-26 19:53:20 -04:00
parent 5751215ffa
commit 7d0d81905e
5 changed files with 74 additions and 4 deletions

View File

@ -15,6 +15,7 @@ Copyright © 2024 dogeystamp <dogeystamp@disroot.org>
use chess_inator::fen::FromFen;
use chess_inator::movegen::{FromUCIAlgebraic, Move, MoveGen, MoveGenType, ToUCIAlgebraic};
use chess_inator::search::best_move;
use chess_inator::Board;
use std::io;
@ -87,8 +88,7 @@ fn cmd_position(mut tokens: std::str::SplitWhitespace<'_>) -> Board {
/// Play the game.
fn cmd_go(mut _tokens: std::str::SplitWhitespace<'_>, board: &mut Board) {
let mvs: Vec<_> = board.gen_moves(MoveGenType::Legal).into_iter().collect();
let chosen = mvs.first();
let chosen = best_move(board);
match chosen {
Some(mv) => println!("bestmove {}", mv.to_uci_algebraic()),
None => println!("bestmove 0000"),

View File

@ -18,7 +18,7 @@ use crate::{Board, Color, N_PIECES};
/// Signed centipawn type.
///
/// Positive is good for White, negative good for Black.
type EvalInt = i16;
pub type EvalInt = i16;
pub trait Eval {
/// Evaluate a position and assign it a score.

View File

@ -19,6 +19,7 @@ use std::str::FromStr;
pub mod eval;
pub mod fen;
pub mod movegen;
pub mod search;
use crate::fen::{FromFen, ToFen, START_POSITION};

View File

@ -96,7 +96,7 @@ pub struct AntiMove {
impl AntiMove {
/// Undo the move.
fn unmake(self, pos: &mut Board) {
pub fn unmake(self, pos: &mut Board) {
pos.move_piece(self.dest, self.src);
pos.half_moves = self.half_moves;
pos.castle = self.castle;

69
src/search.rs Normal file
View File

@ -0,0 +1,69 @@
/*
This file is part of chess_inator.
chess_inator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
chess_inator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with chess_inator. If not, see https://www.gnu.org/licenses/.
Copyright © 2024 dogeystamp <dogeystamp@disroot.org>
*/
//! Game-tree search.
use crate::eval::{Eval, EvalInt};
use crate::movegen::{Move, MoveGen, MoveGenType};
use crate::Board;
use std::cmp::max;
/// Search the game tree to find the absolute (positive good) eval for the current player.
fn minmax(board: &mut Board, depth: usize) -> EvalInt {
if depth == 0 {
let eval = board.eval();
match board.turn {
crate::Color::White => return eval,
crate::Color::Black => return -eval,
}
}
let mvs: Vec<_> = board.gen_moves(MoveGenType::Legal).into_iter().collect();
let mut abs_best = EvalInt::MIN;
for mv in mvs {
let anti_mv = mv.make(board);
abs_best = max(abs_best, -minmax(board, depth - 1));
anti_mv.unmake(board);
}
abs_best
}
/// Find the best move for a position (internal interface).
fn search(board: &mut Board) -> Option<Move> {
const DEPTH: usize = 4;
let mvs: Vec<_> = board.gen_moves(MoveGenType::Legal).into_iter().collect();
// absolute eval value
let mut best_eval = EvalInt::MIN;
let mut best_mv: Option<Move> = None;
for mv in mvs {
let anti_mv = mv.make(board);
let abs_eval = -minmax(board, DEPTH);
if abs_eval > best_eval {
best_eval = abs_eval;
best_mv = Some(mv);
}
anti_mv.unmake(board);
}
best_mv
}
/// Find the best move.
pub fn best_move(board: &mut Board) -> Option<Move> {
search(board)
}