From 289d77d822732f8d574d441848e558facfbf0397 Mon Sep 17 00:00:00 2001 From: Ruthenic Date: Fri, 27 Jan 2023 01:20:30 -0500 Subject: [PATCH] stuff or smth --- .cargo/config.toml | 2 + Cargo.toml | 6 +++ src/config.rs | 4 +- src/eval.rs | 92 ++++++++++++++++++++++++++++++++++++++++++---- src/main.rs | 76 ++++++++++++++++++++++++++------------ 5 files changed, 147 insertions(+), 33 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..03f4879 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["-Ctarget-cpu=native"] diff --git a/Cargo.toml b/Cargo.toml index 0229ed0..52a9efa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,12 @@ name = "inkwell" version = "0.1.0" edition = "2021" +[profile.release] +lto = "fat" +opt-level = 3 +panic = "abort" +codegen-units = 1 + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/src/config.rs b/src/config.rs index 6498684..81f7de9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -15,9 +15,9 @@ impl Info<'_> { pub const INFO: Info = Info { name: "inkwell", - version: "0.0.1-rc", + version: "0.0.3-rc", author: "Bendy (real)", }; // FIXME: this needs to be configurable via UCI -pub const depth: u8 = 0; +pub const depth: u8 = 3; diff --git a/src/eval.rs b/src/eval.rs index 4bcbddf..10d168f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,18 +1,96 @@ -use chess::{Board, ChessMove, Color, MoveGen, Piece}; +use chess::{Board, BoardStatus, ChessMove, Color, MoveGen, Piece}; -pub fn eval_board(board: Board, playing_as: Color, curr_depth: u8) -> i128 { +pub fn eval_board( + board: Board, + playing_as: Color, + curr_depth: u8, + move_history: Vec<(ChessMove, Board)>, +) -> i128 { let mut current_eval: i128 = 0; let moves_iter = MoveGen::new_legal(&board).into_iter(); moves_iter.for_each(|mov| { let tmp_board = board.make_move_new(mov); - current_eval += tmp_board.color_combined(playing_as).count() as i128; - current_eval -= tmp_board.color_combined(!playing_as).count() as i128; - eprintln!("{}", current_eval); + + // 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; + } + } + + // 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 */ } + } + }); + + 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; + 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 + if tmp_board.status() == BoardStatus::Checkmate && tmp_board.side_to_move() == playing_as { + current_eval -= 666_666; + } + + // go for checkmate + if tmp_board.status() == BoardStatus::Checkmate && tmp_board.side_to_move() == !playing_as { + current_eval += 666_666; + } + + // deprioritize king movement + if board.piece_on(mov.get_source()).unwrap() == Piece::King && !are_we_in_check { + current_eval -= 10; + } + if curr_depth != 0 { - eprintln!("{}", curr_depth); - current_eval += eval_board(tmp_board, playing_as, curr_depth - 1) + 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); } }); diff --git a/src/main.rs b/src/main.rs index 8822651..a35cde9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,24 @@ mod config; mod eval; -use chess::{Board, MoveGen}; +use chess::{Board, ChessMove, MoveGen}; use config::INFO; use eval::eval_board; use itertools::Itertools; -use rand::seq::IteratorRandom; + +use std::collections::HashMap; use std::io::{self, BufRead}; use std::process; use std::str::FromStr; use vampirc_uci::parse_one; -use vampirc_uci::{ - MessageList, Serializable, UciMessage, UciOptionConfig, UciSearchControl, UciTimeControl, -}; +use vampirc_uci::{UciMessage, UciOptionConfig, UciTimeControl}; use crate::config::depth; fn main() { - let mut rng = rand::thread_rng(); + let _rng = rand::thread_rng(); let mut board: Option = None; + let mut move_history: Vec<(ChessMove, Board)> = vec![]; for line in io::stdin().lock().lines() { let msg: UciMessage = parse_one(&line.unwrap()); match msg { @@ -39,7 +39,10 @@ fn main() { UciMessage::IsReady => { println!("{}", UciMessage::ReadyOk) } - UciMessage::UciNewGame => board = Some(Board::default()), + UciMessage::UciNewGame => { + board = Some(Board::default()); + move_history = vec![]; + } UciMessage::Position { startpos, fen, @@ -51,7 +54,7 @@ fn main() { if let Some(fen) = fen { board = Some(Board::from_str(fen.as_str()).expect("Invalid FEN board")) } - if moves.len() != 0 { + if !moves.is_empty() { for chess_move in moves.iter() { if let Some(goofy_board) = board { board = Some(goofy_board.make_move_new(*chess_move)); @@ -66,11 +69,11 @@ fn main() { if let Some(tc) = time_control { match tc { UciTimeControl::TimeLeft { - white_time, - black_time, - white_increment, - black_increment, - moves_to_go, + white_time: _, + black_time: _, + white_increment: _, + black_increment: _, + moves_to_go: _, } => { // FIXME: impl time-related Things } @@ -85,25 +88,50 @@ fn main() { } } } - if let Some(sc) = search_control { + if let Some(_sc) = search_control { // FIXME: impl search control things } if let Some(board) = board { let color = board.side_to_move(); - let moves = MoveGen::new_legal(&board).into_iter(); + let moves = MoveGen::new_legal(&board); let iter = moves.map(|mov| (mov, board.make_move_new(mov))); - println!( - "bestmove {}", - iter.sorted_by(|a, b| Ord::cmp( - &eval_board(b.1, color, depth), - &eval_board(a.1, color, depth) - )) - .next() - .unwrap() - .0 + let mut moves_hash_map = HashMap::new(); + + 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())); + } + + if !moves_hash_map.contains_key(b) { + moves_hash_map + .insert(*b, eval_board(b.1, color, depth, move_history.clone())); + } + + let a_eval = moves_hash_map.get(a).unwrap(); + let b_eval = moves_hash_map.get(b).unwrap(); + Ord::cmp(&b_eval, &a_eval) + }); + + let best_move = sorted_moves.next().unwrap(); + let worst_move = sorted_moves.last().unwrap_or(best_move); + + move_history.push(best_move); + + eprintln!( + "best move: {}, {}", + best_move.0, + moves_hash_map.get(&best_move).unwrap_or(&0) + ); + eprintln!( + "worst move: {}, {}", + worst_move.0, + moves_hash_map.get(&worst_move).unwrap_or(&0) ); + + println!("bestmove {}", best_move.0); } } UciMessage::Stop => {