Skip to content

Commit

Permalink
Merge pull request #61 from emilio-zuniga/uci-testing
Browse files Browse the repository at this point in the history
Add UCI
  • Loading branch information
emilio-zuniga authored Nov 29, 2024
2 parents 8fbeba4 + bfb3129 commit 5e824a3
Show file tree
Hide file tree
Showing 16 changed files with 1,690 additions and 1,256 deletions.
23 changes: 23 additions & 0 deletions src/bitboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,28 @@ impl Default for BitBoard {
}

impl BitBoard {
/// Gets the total piece weights for a given side.
pub fn piece_mass(&self, color: Color) -> i32 {
match color {
Color::Black => {
self.king_black.count_ones() as i32 * PieceType::King as i32
+ self.queens_black.count_ones() as i32 * PieceType::Queen as i32
+ self.rooks_black.count_ones() as i32 * PieceType::Rook as i32
+ self.bishops_black.count_ones() as i32 * PieceType::Bishop as i32
+ self.knights_black.count_ones() as i32 * PieceType::Knight as i32
+ self.pawns_black.count_ones() as i32 * PieceType::Pawn as i32
}
Color::White => {
self.king_white.count_ones() as i32 * PieceType::King as i32
+ self.queens_white.count_ones() as i32 * PieceType::Queen as i32
+ self.rooks_white.count_ones() as i32 * PieceType::Rook as i32
+ self.bishops_white.count_ones() as i32 * PieceType::Bishop as i32
+ self.knights_white.count_ones() as i32 * PieceType::Knight as i32
+ self.pawns_white.count_ones() as i32 * PieceType::Pawn as i32
}
}
}

/// A utility method for generating a `BitBoard` from a FEN string\
/// * `fen` - a `&str` representing the board token of a FEN string\
/// * `returns` - a `BitBoard` as generated from the FEN token
Expand Down Expand Up @@ -180,6 +202,7 @@ impl BitBoard {
/// of this `PieceType` of this `Color`\
/// * `color` - the `Color` of the pieces\
/// * `pieces` - the `PieceType` of the pieces
#[allow(dead_code)]
pub fn get_bitboard(&self, color: Color, piece: PieceType) -> u64 {
match color {
Color::White => match piece {
Expand Down
10 changes: 10 additions & 0 deletions src/enginemanager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use vampirc_uci::UciMove;

use crate::{gamemanager::GameManager, movetable::{noarc::NoArc, MoveTable}};

pub struct Engine {
pub tbl: NoArc<MoveTable>,
pub move_history: Vec<UciMove>,
pub board: GameManager,
//pub set_new_game: bool,
}
106 changes: 106 additions & 0 deletions src/gamemanager/evaluation/heatmaps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
pub struct Heatmap {
pub pawns_start: [i32; 64],
pub pawns_end: [i32; 64],
pub knights: [i32; 64],
pub bishops: [i32; 64],
pub rooks: [i32; 64],
pub queens: [i32; 64],
pub kings_start: [i32; 64],
pub kings_end: [i32; 64],
}

impl Default for Heatmap {
/// Returns the heatmaps for white.
/// Use .rev() to get the heatmaps for black.
fn default() -> Self {
let pawns_start = [
0, 0, 0, 0, 0, 0, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 10, 10, 20, 30, 30, 20, 10, 10,
5, 5, 10, 25, 25, 10, 5, 5, 0, 0, 0, 20, 20, 0, 0, 0, 5, -5, -10, 0, 0, -10, -5, 5, 5,
10, 10, -20, -20, 10, 10, 5, 0, 0, 0, 0, 0, 0, 0, 0,
];

let pawns_end = [
0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 50, 50, 50, 50, 50, 50, 50, 50,
30, 30, 30, 30, 30, 30, 30, 30, 20, 20, 20, 20, 20, 20, 20, 20, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0,
];

let knights = [
-50, -40, -30, -30, -30, -30, -40, -50, -40, -20, 0, 0, 0, 0, -20, -40, -30, 0, 10, 15,
15, 10, 0, -30, -30, 5, 15, 20, 20, 15, 5, -30, -30, 0, 15, 20, 20, 15, 0, -30, -30, 5,
10, 15, 15, 10, 5, -30, -40, -20, 0, 5, 5, 0, -20, -40, -50, -40, -30, -30, -30, -30,
-40, -50,
];

let bishops = [
-20, -10, -10, -10, -10, -10, -10, -20, -10, 0, 0, 0, 0, 0, 0, -10, -10, 0, 5, 10, 10,
5, 0, -10, -10, 5, 5, 10, 10, 5, 5, -10, -10, 0, 10, 10, 10, 10, 0, -10, -10, 10, 10,
10, 10, 10, 10, -10, -10, 5, 0, 0, 0, 0, 5, -10, -20, -10, -10, -10, -10, -10, -10,
-20,
];

let rooks = [
0, 0, 0, 0, 0, 0, 0, 0, 5, 10, 10, 10, 10, 10, 10, 5, -5, 0, 0, 0, 0, 0, 0, -5, -5, 0,
0, 0, 0, 0, 0, -5, -5, 0, 0, 0, 0, 0, 0, -5, -5, 0, 0, 0, 0, 0, 0, -5, -5, 0, 0, 0, 0,
0, 0, -5, 0, 0, 0, 5, 5, 0, 0, 0,
];

let queens = [
-20, -10, -10, -5, -5, -10, -10, -20, -10, 0, 0, 0, 0, 0, 0, -10, -10, 0, 5, 5, 5, 5,
0, -10, -5, 0, 5, 5, 5, 5, 0, -5, 0, 0, 5, 5, 5, 5, 0, -5, -10, 5, 5, 5, 5, 5, 0, -10,
-10, 0, 5, 0, 0, 0, 0, -10, -20, -10, -10, -5, -5, -10, -10, -20,
];

let kings_start = [
-80, -70, -70, -70, -70, -70, -70, -80, -60, -60, -60, -60, -60, -60, -60, -60, -40,
-50, -50, -60, -60, -50, -50, -40, -30, -40, -40, -50, -50, -40, -40, -30, -20, -30,
-30, -40, -40, -30, -30, -20, -10, -20, -20, -20, -20, -20, -20, -10, 20, 20, -5, -5,
-5, -5, 20, 20, 20, 30, 10, 0, 0, 10, 30, 20,
];

let kings_end = [
-20, -10, -10, -10, -10, -10, -10, -20, -5, 0, 5, 5, 5, 5, 0, -5, -10, -5, 20, 30, 30,
20, -5, -10, -15, -10, 35, 45, 45, 35, -10, -15, -20, -15, 30, 40, 40, 30, -15, -20,
-25, -20, 20, 25, 25, 20, -20, -25, -30, -25, 0, 0, 0, 0, -25, -30, -50, -30, -30, -30,
-30, -30, -30, -50,
];

Self {
pawns_start,
pawns_end,
knights,
bishops,
rooks,
queens,
kings_start,
kings_end,
}
}
}

impl Heatmap {
/// Returns the heatmap for black, if the provided
/// heatmap is for white, and vice versa.
pub fn rev(&self) -> Self {
Self {
pawns_start: reverse_array(self.pawns_start),
pawns_end: reverse_array(self.pawns_end),
knights: reverse_array(self.knights),
bishops: reverse_array(self.bishops),
rooks: reverse_array(self.rooks),
queens: reverse_array(self.queens),
kings_start: reverse_array(self.kings_start),
kings_end: reverse_array(self.kings_end),
}
}
}

fn reverse_array(arr: [i32; 64]) -> [i32; 64] {
let mut ret = [0; 64];

// All heatmaps are symmetric about the central vertical axis.
for (idx, v) in arr.into_iter().rev().enumerate() {
ret[idx] = v;
}
ret
}
113 changes: 113 additions & 0 deletions src/gamemanager/evaluation/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use heatmaps::Heatmap;

use crate::{
bitboard::BitBoard,
types::{Color, MoveType, PieceType},
};

use super::GameManager;

mod heatmaps;

const START_MASS: i32 = PieceType::Queen as i32
+ PieceType::Rook as i32 * 2
+ PieceType::Bishop as i32 * 2
+ PieceType::Knight as i32 * 2
+ PieceType::Pawn as i32 * 8;

impl GameManager {
pub fn evaluate(&self, movetype: MoveType) -> i32 {
if self.white_to_move {
// Evaluate for black; better or worse after its move?
let mass_score = self.bitboard.piece_mass(Color::Black) + movetype_weight(movetype);
let heatmap = heatmaps::Heatmap::default();

let endgame_weight = mass_score * 100 / START_MASS;

let position_score =
eval_heatmaps(Color::Black, self.bitboard, heatmap, endgame_weight);

position_score + mass_score
} else {
// Ditto for white.
let mass_score = self.bitboard.piece_mass(Color::White) + movetype_weight(movetype);
let heatmap = heatmaps::Heatmap::default().rev();

let endgame_weight = mass_score * 100 / START_MASS;

let position_score =
eval_heatmaps(Color::White, self.bitboard, heatmap, endgame_weight);

position_score + mass_score
}
}
}

fn movetype_weight(mt: MoveType) -> i32 {
use MoveType::*;
use PieceType::*;
match mt {
QPromotion => Queen as i32,
QPromoCapture => Queen as i32 + 50,
RPromotion => Rook as i32,
RPromoCapture => Rook as i32 + 50,
BPromotion => Bishop as i32,
BPromoCapture => Bishop as i32 + 50,
NPromotion => Knight as i32,
NPromoCapture => Knight as i32 + 50,
EPCapture => Pawn as i32,
Capture => 400,
_ => 0,
}
}

fn eval_heatmaps(color: Color, board: BitBoard, map: Heatmap, endgame_weight: i32) -> i32 {
let base_value = match color {
Color::Black => {
eval_heatmap(map.knights, board.knights_black)
+ eval_heatmap(map.bishops, board.bishops_black)
+ eval_heatmap(map.rooks, board.rooks_black)
+ eval_heatmap(map.queens, board.queens_black)
}
Color::White => {
eval_heatmap(map.knights, board.knights_white)
+ eval_heatmap(map.bishops, board.bishops_white)
+ eval_heatmap(map.rooks, board.rooks_white)
+ eval_heatmap(map.queens, board.queens_white)
}
};

let weighted_value = match color {
Color::Black => {
eval_heatmap(map.pawns_start, board.pawns_black) * (100 - endgame_weight)
+ eval_heatmap(map.pawns_end, board.pawns_black) * endgame_weight
+ eval_heatmap(map.kings_start, board.king_black) * (100 - endgame_weight)
+ eval_heatmap(map.kings_end, board.king_black) * endgame_weight
}
Color::White => {
eval_heatmap(map.pawns_start, board.pawns_white) * (100 - endgame_weight)
+ eval_heatmap(map.pawns_end, board.pawns_white) * endgame_weight
+ eval_heatmap(map.kings_start, board.king_white) * (100 - endgame_weight)
+ eval_heatmap(map.kings_end, board.king_white) * endgame_weight
}
};

base_value + weighted_value
}

fn eval_heatmap(table: [i32; 64], bits: u64) -> i32 {
let mut score = 0;
let split_bits = split_bits(bits);
for idx in 0..64 {
score += table[idx] * split_bits[idx] as i32;
}
score
}

fn split_bits(int: u64) -> [u8; 64] {
let mut bits = [0u8; 64];
for idx in 0..64 {
bits[idx] = ((int >> idx) & 1) as u8;
}
bits
}
Loading

0 comments on commit 5e824a3

Please sign in to comment.