master
Drake 1 year ago
parent 289d77d822
commit f856c15a61

@ -15,9 +15,9 @@ impl Info<'_> {
pub const INFO: Info = Info { pub const INFO: Info = Info {
name: "inkwell", name: "inkwell",
version: "0.0.3-rc", version: "0.0.666-rc",
author: "Bendy (real)", author: "Bendy (real)",
}; };
// FIXME: this needs to be configurable via UCI // 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}; use chess::{Board, BoardStatus, ChessMove, Color, MoveGen, Piece};
pub fn eval_board( fn static_board_eval(
mov: ChessMove,
board: Board, board: Board,
playing_as: Color, playing_as: Color,
curr_depth: u8,
move_history: Vec<(ChessMove, Board)>, move_history: Vec<(ChessMove, Board)>,
) -> i128 { ) -> f64 {
let mut current_eval: i128 = 0; 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| { // basic material counting
let tmp_board = board.make_move_new(mov); 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) board.color_combined(!playing_as).for_each(|square| {
if move_history.len() > 6 { match board.piece_on(square) {
if move_history[move_history.len() - 2].0 == mov Some(Piece::Pawn) => current_eval -= 1.0,
&& move_history[move_history.len() - 6].0 == mov Some(Piece::Knight) => current_eval -= 3.0,
{ Some(Piece::Bishop) => current_eval -= 5.0,
current_eval -= 6666666666666666666666666666; Some(Piece::Rook) => current_eval -= 5.0,
return; Some(Piece::Queen) => current_eval -= 8.0,
} _ => { /* do nothing */ }
} }
});
// basic material counting // checking heuristic
tmp_board.color_combined(playing_as).for_each(|square| { let mut are_we_in_check = false;
match tmp_board.piece_on(square) { let mut is_opponent_in_check = false;
Some(Piece::Pawn) => current_eval += 1, board
Some(Piece::Knight) => current_eval += 3, .checkers()
Some(Piece::Bishop) => current_eval += 5, .filter(|sq| board.color_on(*sq).unwrap() == playing_as)
Some(Piece::Rook) => current_eval += 5, .for_each(|_| {
Some(Piece::Queen) => current_eval += 8, if !are_we_in_check {
_ => { /* do nothing */ } current_eval -= 66.6;
are_we_in_check = true;
} else {
current_eval -= 12.5;
} }
}); });
board
tmp_board.color_combined(!playing_as).for_each(|square| { .checkers()
match tmp_board.piece_on(square) { .filter(|sq| board.color_on(*sq).unwrap() == !playing_as)
Some(Piece::Pawn) => current_eval -= 1, .for_each(|_| {
Some(Piece::Knight) => current_eval -= 3, if !is_opponent_in_check
Some(Piece::Bishop) => current_eval -= 5, && move_history.len()
Some(Piece::Rook) => current_eval -= 5, > *vec![10, 11, 12, 13, 14, 15]
Some(Piece::Queen) => current_eval -= 8, .choose(&mut rand::thread_rng())
_ => { /* do nothing */ } .unwrap() as usize
{
current_eval += 17.5;
is_opponent_in_check = true;
} else {
current_eval += 3.5;
} }
}); });
// checking heuristic // deprioritize king movement
let mut are_we_in_check = false; if board.piece_on(mov.get_source()).unwrap_or(Piece::Pawn) == Piece::King && !are_we_in_check {
let mut is_opponent_in_check = false; current_eval -= 12.5;
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;
}
});
// die current_eval
if tmp_board.status() == BoardStatus::Checkmate && tmp_board.side_to_move() == playing_as { }
current_eval -= 666_666;
}
// go for checkmate pub fn eval_board(
if tmp_board.status() == BoardStatus::Checkmate && tmp_board.side_to_move() == !playing_as { board: Board,
current_eval += 666_666; 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 depth == 0 || board.status() == BoardStatus::Checkmate {
if board.piece_on(mov.get_source()).unwrap() == Piece::King && !are_we_in_check { return static_board_eval(
current_eval -= 10; 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 new_board = board.make_move_new(mov);
let mut new_move_history = move_history.clone(); new_move_history.push((mov, new_board));
new_move_history.push((mov, tmp_board));
current_eval += eval_board(tmp_board, playing_as, curr_depth - 1, new_move_history);
}
});
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 itertools::Itertools;
use std::collections::HashMap; use std::collections::HashMap;
use std::f64::{INFINITY, NEG_INFINITY};
use std::io::{self, BufRead}; use std::io::{self, BufRead};
use std::process; use std::process;
use std::str::FromStr; use std::str::FromStr;
@ -101,18 +102,44 @@ fn main() {
let mut sorted_moves = iter.sorted_by(|a, b| { let mut sorted_moves = iter.sorted_by(|a, b| {
if !moves_hash_map.contains_key(a) { if !moves_hash_map.contains_key(a) {
moves_hash_map moves_hash_map.insert(
.insert(*a, eval_board(a.1, color, depth, move_history.clone())); *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) { if !moves_hash_map.contains_key(b) {
moves_hash_map moves_hash_map.insert(
.insert(*b, eval_board(b.1, color, depth, move_history.clone())); *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 a_eval = moves_hash_map.get(a).unwrap();
let b_eval = moves_hash_map.get(b).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(); let best_move = sorted_moves.next().unwrap();
@ -123,12 +150,12 @@ fn main() {
eprintln!( eprintln!(
"best move: {}, {}", "best move: {}, {}",
best_move.0, best_move.0,
moves_hash_map.get(&best_move).unwrap_or(&0) moves_hash_map.get(&best_move).unwrap_or(&0.0)
); );
eprintln!( eprintln!(
"worst move: {}, {}", "worst move: {}, {}",
worst_move.0, 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); println!("bestmove {}", best_move.0);

Loading…
Cancel
Save