master
Drake 1 year ago
parent 289d77d822
commit f856c15a61

@ -15,9 +15,9 @@ impl Info<'_> {
pub const INFO: Info = Info {
name: "inkwell",
version: "0.0.3-rc",
version: "0.0.666-rc",
author: "Bendy (real)",
};
// FIXME: this needs to be configurable via UCI
pub const depth: u8 = 3;
pub const depth: u8 = 6;

@ -1,98 +1,156 @@
use rand::prelude::*;
use std::f64::{INFINITY, NEG_INFINITY};
use chess::{Board, BoardStatus, ChessMove, Color, MoveGen, Piece};
pub fn eval_board(
fn static_board_eval(
mov: ChessMove,
board: Board,
playing_as: Color,
curr_depth: u8,
move_history: Vec<(ChessMove, Board)>,
) -> i128 {
let mut current_eval: i128 = 0;
) -> f64 {
if move_history.len() > 6 {
if move_history[move_history.len() - 1].0 == mov
&& move_history[move_history.len() - 2].0 == mov
{
return -666.0;
}
}
let moves_iter = MoveGen::new_legal(&board).into_iter();
let mut current_eval = 0.0;
moves_iter.for_each(|mov| {
let tmp_board = board.make_move_new(mov);
// basic material counting
board.color_combined(playing_as).for_each(|square| {
match board.piece_on(square) {
Some(Piece::Pawn) => current_eval += 1.0,
Some(Piece::Knight) => current_eval += 3.0,
Some(Piece::Bishop) => current_eval += 5.0,
Some(Piece::Rook) => current_eval += 5.0,
Some(Piece::Queen) => current_eval += 8.0,
_ => { /* do nothing */ }
}
});
// force it to not draw (and cockblock someone trying *to* draw)
if move_history.len() > 6 {
if move_history[move_history.len() - 2].0 == mov
&& move_history[move_history.len() - 6].0 == mov
{
current_eval -= 6666666666666666666666666666;
return;
}
board.color_combined(!playing_as).for_each(|square| {
match board.piece_on(square) {
Some(Piece::Pawn) => current_eval -= 1.0,
Some(Piece::Knight) => current_eval -= 3.0,
Some(Piece::Bishop) => current_eval -= 5.0,
Some(Piece::Rook) => current_eval -= 5.0,
Some(Piece::Queen) => current_eval -= 8.0,
_ => { /* do nothing */ }
}
});
// basic material counting
tmp_board.color_combined(playing_as).for_each(|square| {
match tmp_board.piece_on(square) {
Some(Piece::Pawn) => current_eval += 1,
Some(Piece::Knight) => current_eval += 3,
Some(Piece::Bishop) => current_eval += 5,
Some(Piece::Rook) => current_eval += 5,
Some(Piece::Queen) => current_eval += 8,
_ => { /* do nothing */ }
// checking heuristic
let mut are_we_in_check = false;
let mut is_opponent_in_check = false;
board
.checkers()
.filter(|sq| board.color_on(*sq).unwrap() == playing_as)
.for_each(|_| {
if !are_we_in_check {
current_eval -= 66.6;
are_we_in_check = true;
} else {
current_eval -= 12.5;
}
});
tmp_board.color_combined(!playing_as).for_each(|square| {
match tmp_board.piece_on(square) {
Some(Piece::Pawn) => current_eval -= 1,
Some(Piece::Knight) => current_eval -= 3,
Some(Piece::Bishop) => current_eval -= 5,
Some(Piece::Rook) => current_eval -= 5,
Some(Piece::Queen) => current_eval -= 8,
_ => { /* do nothing */ }
board
.checkers()
.filter(|sq| board.color_on(*sq).unwrap() == !playing_as)
.for_each(|_| {
if !is_opponent_in_check
&& move_history.len()
> *vec![10, 11, 12, 13, 14, 15]
.choose(&mut rand::thread_rng())
.unwrap() as usize
{
current_eval += 17.5;
is_opponent_in_check = true;
} else {
current_eval += 3.5;
}
});
// checking heuristic
let mut are_we_in_check = false;
let mut is_opponent_in_check = false;
tmp_board
.checkers()
.filter(|sq| tmp_board.color_on(*sq).unwrap() == playing_as)
.for_each(|_| {
if !are_we_in_check {
current_eval -= 666;
are_we_in_check = true;
} else {
current_eval -= 15;
}
});
tmp_board
.checkers()
.filter(|sq| tmp_board.color_on(*sq).unwrap() == !playing_as)
.for_each(|_| {
if !is_opponent_in_check {
current_eval += 15;
is_opponent_in_check = true;
} else {
current_eval += 5;
}
});
// deprioritize king movement
if board.piece_on(mov.get_source()).unwrap_or(Piece::Pawn) == Piece::King && !are_we_in_check {
current_eval -= 12.5;
}
// die
if tmp_board.status() == BoardStatus::Checkmate && tmp_board.side_to_move() == playing_as {
current_eval -= 666_666;
}
current_eval
}
// go for checkmate
if tmp_board.status() == BoardStatus::Checkmate && tmp_board.side_to_move() == !playing_as {
current_eval += 666_666;
}
pub fn eval_board(
board: Board,
is_maximizing_player: bool,
depth: u8,
move_history: Vec<(ChessMove, Board)>,
last_move: Option<ChessMove>,
original_playing_as: Color,
mut alpha: f64,
mut beta: f64,
) -> f64 {
let moves_iter = MoveGen::new_legal(&board).into_iter();
// deprioritize king movement
if board.piece_on(mov.get_source()).unwrap() == Piece::King && !are_we_in_check {
current_eval -= 10;
}
if depth == 0 || board.status() == BoardStatus::Checkmate {
return static_board_eval(
last_move.unwrap_or(move_history.last().unwrap().0),
board,
original_playing_as,
move_history,
);
} else {
if is_maximizing_player {
let mut max_eval = NEG_INFINITY;
for mov in moves_iter {
let mut new_move_history = move_history.clone();
if curr_depth != 0 {
let mut new_move_history = move_history.clone();
new_move_history.push((mov, tmp_board));
current_eval += eval_board(tmp_board, playing_as, curr_depth - 1, new_move_history);
}
});
let new_board = board.make_move_new(mov);
new_move_history.push((mov, new_board));
return current_eval;
let eval = eval_board(
new_board,
false,
depth - 1,
new_move_history,
Some(mov),
original_playing_as,
alpha,
beta,
);
max_eval = max_eval.max(eval);
alpha = alpha.max(eval);
if beta <= alpha {
break;
}
}
return max_eval;
} else {
let mut min_eval = INFINITY;
for mov in moves_iter {
let mut new_move_history = move_history.clone();
let new_board = board.make_move_new(mov);
new_move_history.push((mov, new_board));
let eval = eval_board(
new_board,
true,
depth - 1,
new_move_history,
Some(mov),
original_playing_as,
alpha,
beta,
);
min_eval = min_eval.min(eval);
beta = beta.min(eval);
if beta <= alpha {
break;
}
}
return min_eval;
}
}
}

@ -7,6 +7,7 @@ use eval::eval_board;
use itertools::Itertools;
use std::collections::HashMap;
use std::f64::{INFINITY, NEG_INFINITY};
use std::io::{self, BufRead};
use std::process;
use std::str::FromStr;
@ -101,18 +102,44 @@ fn main() {
let mut sorted_moves = iter.sorted_by(|a, b| {
if !moves_hash_map.contains_key(a) {
moves_hash_map
.insert(*a, eval_board(a.1, color, depth, move_history.clone()));
moves_hash_map.insert(
*a,
eval_board(
a.1,
true,
depth,
move_history.clone(),
if move_history.len() > 0 {
Some(move_history.last().unwrap().0)
} else {
None
},
color,
NEG_INFINITY,
INFINITY,
),
);
}
if !moves_hash_map.contains_key(b) {
moves_hash_map
.insert(*b, eval_board(b.1, color, depth, move_history.clone()));
moves_hash_map.insert(
*b,
eval_board(
b.1,
true,
depth,
move_history.clone(),
None,
color,
NEG_INFINITY,
INFINITY,
),
);
}
let a_eval = moves_hash_map.get(a).unwrap();
let b_eval = moves_hash_map.get(b).unwrap();
Ord::cmp(&b_eval, &a_eval)
b_eval.total_cmp(a_eval)
});
let best_move = sorted_moves.next().unwrap();
@ -123,12 +150,12 @@ fn main() {
eprintln!(
"best move: {}, {}",
best_move.0,
moves_hash_map.get(&best_move).unwrap_or(&0)
moves_hash_map.get(&best_move).unwrap_or(&0.0)
);
eprintln!(
"worst move: {}, {}",
worst_move.0,
moves_hash_map.get(&worst_move).unwrap_or(&0)
moves_hash_map.get(&worst_move).unwrap_or(&0.0)
);
println!("bestmove {}", best_move.0);

Loading…
Cancel
Save