use Board;
use std::i32;
use core::*;
use core::masks::*;
use core::bitboard::BitBoard;
use core::mono_traits::*;
use core::score::Value;
lazy_static! {
pub static ref PAWN_POS: [[i32; SQ_CNT]; PLAYER_CNT] = [ flatten(flip(PAWN_POS_ARRAY)), flatten(PAWN_POS_ARRAY) ];
}
const PAWN_POS_ARRAY: [[i32; FILE_CNT]; RANK_CNT] = [
[0, 0, 0, 0, 0, 0, 0, 0], [5, 10, 15, 20, 20, 15, 10, 5],
[4, 8, 12, 16, 16, 12, 8, 4],
[0, 6, 9, 10, 10, 9, 6, 0],
[0, 4, 6, 10, 10, 6, 4, 0],
[0, 2, 3, 4, 4, 3, 2, 0],
[0, 0, 0, -5, -5, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0], ];
fn flip(arr: [[i32; FILE_CNT]; RANK_CNT]) -> [[i32; FILE_CNT]; RANK_CNT] {
let mut new_arr: [[i32; FILE_CNT]; RANK_CNT] = [[0; FILE_CNT]; RANK_CNT];
for i in 0..RANK_CNT {
new_arr[i] = arr[7 - i];
}
new_arr
}
fn flatten(arr: [[i32; FILE_CNT]; RANK_CNT]) -> [i32; SQ_CNT] {
let mut new_arr: [i32; SQ_CNT] = [0; SQ_CNT];
for i in 0..SQ_CNT {
new_arr[i] = arr[i / 8][i % 8];
}
new_arr
}
pub struct Eval;
trait EvalRuns {
fn eval_castling<PlayerTrait>(&self) -> i32;
fn eval_king_pos<PlayerTrait>(&self) -> i32;
fn eval_bishop_pos<PlayerTrait>(&self) -> i32;
fn eval_threats<PlayerTrait>(&self) -> i32;
fn eval_piece_counts<PlayerTrait,PieceTrait>(&self) -> i32;
}
const INFINITY: i32 = 30_001;
const NEG_INFINITY: i32 = -30_001;
const STALEMATE: i32 = 0;
const PAWN_VALUE: i32 = 100;
const KNIGHT_VALUE: i32 = 300;
const BISHOP_VALUE: i32 = 300;
const ROOK_VALUE: i32 = 500;
const QUEEN_VALUE: i32 = 800;
const KING_VALUE: i32 = 350;
const CASTLE_ABILITY: i32 = 7;
const CASTLE_BONUS: i32 = 20;
const KING_BOTTOM: i32 = 8;
const MATE: i32 = -25_000;
const CHECK: i32 = 14;
pub const PIECE_VALS: [i32; PIECE_TYPE_CNT] = [
0,
PAWN_VALUE,
KNIGHT_VALUE,
BISHOP_VALUE,
ROOK_VALUE,
QUEEN_VALUE,
KING_VALUE,
0,
];
impl Eval {
pub fn eval_low(board: &Board) -> Value {
match board.turn() {
Player::White => eval_all::<WhiteType>(board) - eval_all::<BlackType>(board) + board.non_pawn_material(Player::White) - board.non_pawn_material(Player::Black),
Player::Black => eval_all::<BlackType>(board) - eval_all::<WhiteType>(board) + board.non_pawn_material(Player::Black) - board.non_pawn_material(Player::White)
}
}
}
fn eval_all<P: PlayerTrait>(board: &Board) -> Value {
if board.rule_50() >= 50 {
return MATE;
}
eval_piece_counts::<P>(board) +
eval_castling::<P>(board) +
eval_king_pos::<P>(board) +
eval_bishop_pos::<P>(board) +
eval_king_blockers_pinners::<P>(board) +
eval_pawns::<P>(board)
}
fn eval_piece_counts<P: PlayerTrait>(board: &Board) -> i32 {
board.count_piece(P::player(), PieceType::P) as i32 * PAWN_VALUE
}
fn eval_castling<P: PlayerTrait>(board: &Board) -> i32 {
let mut score: i32 = 0;
if board.can_castle(P::player(), CastleType::KingSide) {
score += CASTLE_ABILITY
}
if board.can_castle(P::player(), CastleType::QueenSide) {
score += CASTLE_ABILITY
}
score
}
fn eval_king_pos<P: PlayerTrait>(board: &Board) -> i32 {
let mut score: i32 = 0;
let us_ksq = board.king_sq(P::player());
if board.in_check() && P::player() == board.turn() {
score -= CHECK
}
let bb_around_us: BitBoard = board.magic_helper.king_moves(us_ksq) & board.get_occupied_player(P::player());
score += bb_around_us.count_bits() as i32 * 9;
score
}
fn eval_bishop_pos<P: PlayerTrait>(board: &Board) -> i32 {
let mut score: i32 = 0;
if board.count_piece(P::player(), PieceType::B) > 1 {
score += 19
}
score
}
fn eval_king_blockers_pinners<P: PlayerTrait>(board: &Board) -> i32 {
let mut score: i32 = 0;
let blockers: BitBoard = board.all_pinned_pieces(P::player());
let them_blockers: BitBoard = blockers & board.get_occupied_player(P::opp_player());
let us_blockers: BitBoard = blockers & board.get_occupied_player(P::player());
score += 18 * us_blockers.count_bits() as i32;
score += 6 * them_blockers.count_bits() as i32;
score
}
fn eval_pawns<P: PlayerTrait>(board: &Board) -> i32 {
let mut score: i32 = 0;
let pawns_bb: BitBoard = board.piece_bb(P::player(), PieceType::P);
let mut bb = pawns_bb;
let mut file_counts: [u8; FILE_CNT] = [0; FILE_CNT];
let mut sqs_defended: BitBoard = BitBoard(0);
while bb.is_not_empty() {
let lsb = bb.lsb();
let sq = lsb.to_sq();
sqs_defended |= board.magic_helper.pawn_attacks_from(sq, P::player());
file_counts[(sq.0 % 8) as usize] += 1;
score += PAWN_POS[P::player() as usize][sq.0 as usize];
bb &= !lsb;
}
score += sqs_defended.count_bits() as i32;
sqs_defended &= pawns_bb;
score += 3 * sqs_defended.count_bits() as i32;
for i in 0..FILE_CNT {
if file_counts[i] > 1 {
score -= (file_counts[i] * 3) as i32;
}
if i > 0 && i < 7 && file_counts[i] > 0 {
if file_counts[i - 1] != 0 {
if file_counts[i + 1] != 0 {
score += 7;
} else {
score += 3;
}
} else if file_counts[i + 1] != 0 {
score += 3;
} else {
score -= 4;
}
}
}
score
}