Implement piece/psqt scores and tests
This commit is contained in:
116
src/evaluation.rs
Normal file
116
src/evaluation.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
use u64 as Bitboard;
|
||||
|
||||
use crate::{
|
||||
bitboard::lsb,
|
||||
board::{Board, Color, Kind},
|
||||
psqt::{mirror_index, piece_square_score},
|
||||
};
|
||||
|
||||
const fn piece_score(kind: Kind) -> i32 {
|
||||
match kind {
|
||||
Kind::Pawn => 100,
|
||||
Kind::Knight => 320,
|
||||
Kind::Bishop => 330,
|
||||
Kind::Rook => 500,
|
||||
Kind::Queen => 900,
|
||||
Kind::King => 20000,
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_side(board: &Board, color: Color) -> i32 {
|
||||
let mut total_score = 0;
|
||||
let pieces = match color {
|
||||
Color::White => &board.white_pieces,
|
||||
Color::Black => &board.black_pieces,
|
||||
};
|
||||
|
||||
for piece in pieces {
|
||||
let (kind, mut bitboard): (Kind, Bitboard) = (piece.kind, piece.bitboard);
|
||||
let mut score = 0;
|
||||
while bitboard != 0 {
|
||||
let psqt_index = match color {
|
||||
Color::White => lsb(bitboard),
|
||||
Color::Black => mirror_index(lsb(bitboard)),
|
||||
};
|
||||
|
||||
score += piece_score(kind);
|
||||
score += piece_square_score(kind, psqt_index);
|
||||
bitboard &= bitboard - 1;
|
||||
}
|
||||
total_score += score;
|
||||
}
|
||||
total_score
|
||||
}
|
||||
|
||||
pub fn evaluate_position(board: &Board, color: Color) -> i32 {
|
||||
let total_white_score = evaluate_side(board, Color::White);
|
||||
let total_black_score = evaluate_side(board, Color::Black);
|
||||
let evaluation = total_white_score - total_black_score;
|
||||
|
||||
match color {
|
||||
Color::White => evaluation,
|
||||
Color::Black => -evaluation,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
board::{Color, Kind},
|
||||
evaluation::{evaluate_position, evaluate_side, piece_score},
|
||||
fen::from_fen,
|
||||
};
|
||||
|
||||
const FEN_QUIET: [&str; 2] = [
|
||||
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
||||
"rnbqkbnr/ppp2ppp/4p3/3pN3/3P4/8/PPP1PPPP/RNBQKB1R w KQkq - 0 1",
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn test_piece_score() -> Result<(), String> {
|
||||
assert_eq!(100, piece_score(Kind::Pawn));
|
||||
assert_eq!(320, piece_score(Kind::Knight));
|
||||
assert_eq!(330, piece_score(Kind::Bishop));
|
||||
assert_eq!(500, piece_score(Kind::Rook));
|
||||
assert_eq!(900, piece_score(Kind::Queen));
|
||||
assert_eq!(20000, piece_score(Kind::King));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_evaluate_side() -> Result<(), String> {
|
||||
let game = from_fen(FEN_QUIET[0])?;
|
||||
|
||||
assert_eq!(
|
||||
evaluate_side(&game.board, Color::White),
|
||||
evaluate_side(&game.board, Color::Black)
|
||||
);
|
||||
|
||||
let game_2 = from_fen(FEN_QUIET[1])?;
|
||||
let evaluate_white = evaluate_side(&game_2.board, Color::White);
|
||||
let evaluate_black = evaluate_side(&game_2.board, Color::Black);
|
||||
|
||||
assert_eq!(24005, evaluate_white);
|
||||
assert_eq!(23965, evaluate_black);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_evaluate() -> Result<(), String> {
|
||||
let game = from_fen(FEN_QUIET[0])?;
|
||||
|
||||
assert_eq!(
|
||||
evaluate_position(&game.board, Color::White),
|
||||
evaluate_position(&game.board, Color::Black)
|
||||
);
|
||||
|
||||
let game_2 = from_fen(FEN_QUIET[1])?;
|
||||
|
||||
assert_eq!(40, evaluate_position(&game_2.board, Color::White));
|
||||
assert_eq!(-40, evaluate_position(&game_2.board, Color::Black));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
pub mod attack;
|
||||
pub mod bitboard;
|
||||
pub mod board;
|
||||
pub mod evaluation;
|
||||
pub mod fen;
|
||||
pub mod game;
|
||||
pub mod magic;
|
||||
pub mod r#move;
|
||||
pub mod movegen;
|
||||
pub mod perft;
|
||||
pub mod psqt;
|
||||
pub mod search;
|
||||
pub mod square;
|
||||
pub mod state;
|
||||
|
||||
143
src/psqt.rs
Normal file
143
src/psqt.rs
Normal file
@@ -0,0 +1,143 @@
|
||||
use crate::board::Kind;
|
||||
|
||||
pub const fn piece_square_score(kind: Kind, index: usize) -> i32 {
|
||||
match kind {
|
||||
Kind::Pawn => PAWN_PSQT[index],
|
||||
Kind::Knight => KNIGHT_PSQT[index],
|
||||
Kind::Bishop => BISHOP_PSQT[index],
|
||||
Kind::Rook => ROOK_PSQT[index],
|
||||
Kind::Queen => QUEEN_PSQT[index],
|
||||
Kind::King => KING_MIDGAME_PSQT[index],
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn piece_square_score_endgame(kind: Kind, index: usize) -> i32 {
|
||||
match kind {
|
||||
Kind::Pawn => PAWN_PSQT[index],
|
||||
Kind::Knight => KNIGHT_PSQT[index],
|
||||
Kind::Bishop => BISHOP_PSQT[index],
|
||||
Kind::Rook => ROOK_PSQT[index],
|
||||
Kind::Queen => QUEEN_PSQT[index],
|
||||
Kind::King => KING_ENDGAME_PSQT[index],
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn mirror_index(idx: usize) -> usize {
|
||||
63 - idx
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
const PAWN_PSQT: [i32; 64] = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
5, 10, 10,-20,-20, 10, 10, 5,
|
||||
5, -5,-10, 0, 0,-10, -5, 5,
|
||||
0, 0, 0, 20, 20, 0, 0, 0,
|
||||
5, 5, 10, 25, 25, 10, 5, 5,
|
||||
10, 10, 20, 30, 30, 20, 10, 10,
|
||||
50, 50, 50, 50, 50, 50, 50, 50,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
const KNIGHT_PSQT: [i32; 64] = [
|
||||
-50,-40,-30,-30,-30,-30,-40,-50,
|
||||
-40,-20, 0, 5, 5, 0,-20,-40,
|
||||
-30, 5, 10, 15, 15, 10, 5,-30,
|
||||
-30, 0, 15, 20, 20, 15, 0,-30,
|
||||
-30, 5, 15, 20, 20, 15, 5,-30,
|
||||
-30, 0, 10, 15, 15, 10, 0,-30,
|
||||
-40,-20, 0, 0, 0, 0,-20,-40,
|
||||
-50,-40,-30,-30,-30,-30,-40,-50,
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
const BISHOP_PSQT: [i32; 64] = [
|
||||
-20,-10,-10,-10,-10,-10,-10,-20,
|
||||
-10, 5, 0, 0, 0, 0, 5,-10,
|
||||
-10, 10, 10, 10, 10, 10, 10,-10,
|
||||
-10, 0, 10, 10, 10, 10, 0,-10,
|
||||
-10, 5, 5, 10, 10, 5, 5,-10,
|
||||
-10, 0, 5, 10, 10, 5, 0,-10,
|
||||
-10, 0, 0, 0, 0, 0, 0,-10,
|
||||
-20,-10,-10,-10,-10,-10,-10,-20,
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
const ROOK_PSQT: [i32; 64] = [
|
||||
0, 0, 0, 5, 5, 0, 0, 0,
|
||||
-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,
|
||||
5, 10, 10, 10, 10, 10, 10, 5,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
const QUEEN_PSQT: [i32; 64] = [
|
||||
-20,-10,-10, -5, -5,-10,-10,-20,
|
||||
-10, 0, 5, 0, 0, 0, 0,-10,
|
||||
-10, 5, 5, 5, 5, 5, 0,-10,
|
||||
-5, 0, 5, 5, 5, 5, 0, -5,
|
||||
0, 0, 5, 5, 5, 5, 0, -5,
|
||||
-10, 0, 5, 5, 5, 5, 0,-10,
|
||||
-10, 0, 0, 0, 0, 0, 0,-10,
|
||||
-20,-10,-10, -5, -5,-10,-10,-20
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
const KING_MIDGAME_PSQT: [i32; 64] = [
|
||||
20, 30, 10, 0, 0, 10, 30, 20,
|
||||
20, 20, 0, 0, 0, 0, 20, 20,
|
||||
-10,-20,-20,-20,-20,-20,-20,-10,
|
||||
-20,-30,-30,-40,-40,-30,-30,-20,
|
||||
-30,-40,-40,-50,-50,-40,-40,-30,
|
||||
-30,-40,-40,-50,-50,-40,-40,-30,
|
||||
-30,-40,-40,-50,-50,-40,-40,-30,
|
||||
-30,-40,-40,-50,-50,-40,-40,-30
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
const KING_ENDGAME_PSQT: [i32; 64] = [
|
||||
-50,-30,-30,-30,-30,-30,-30,-50,
|
||||
-30,-30, 0, 0, 0, 0,-30,-30,
|
||||
-30,-10, 20, 30, 30, 20,-10,-30,
|
||||
-30,-10, 30, 40, 40, 30,-10,-30,
|
||||
-30,-10, 30, 40, 40, 30,-10,-30,
|
||||
-30,-10, 20, 30, 30, 20,-10,-30,
|
||||
-30,-20,-10, 0, 0,-10,-20,-30,
|
||||
-50,-40,-30,-20,-20,-30,-40,-50
|
||||
];
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
board::Kind,
|
||||
psqt::{mirror_index, piece_square_score},
|
||||
square::Square,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_piece_square_score() -> Result<(), String> {
|
||||
assert_eq!(50, piece_square_score(Kind::Pawn, Square::A7));
|
||||
assert_eq!(-40, piece_square_score(Kind::Knight, Square::B1));
|
||||
assert_eq!(0, piece_square_score(Kind::Bishop, Square::D2));
|
||||
assert_eq!(-5, piece_square_score(Kind::Rook, Square::A2));
|
||||
assert_eq!(5, piece_square_score(Kind::Queen, Square::D3));
|
||||
assert_eq!(30, piece_square_score(Kind::King, Square::G1));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mirror_index() -> Result<(), String> {
|
||||
let a1_mirror = mirror_index(Square::A1);
|
||||
assert_eq!(Square::H8, a1_mirror);
|
||||
|
||||
let d4_mirror = mirror_index(Square::D4);
|
||||
assert_eq!(Square::E5, d4_mirror);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user