|
@@ -2,45 +2,79 @@ use game::*;
|
|
|
use bitboard::*;
|
|
|
use movegen::*;
|
|
|
|
|
|
-use std::f32::*;
|
|
|
+use std::i32;
|
|
|
|
|
|
-pub type PosValue = f32;
|
|
|
-pub const MIN_VALUE: PosValue = -1000000.0f32;
|
|
|
-pub const MAX_VALUE: PosValue = 1000000.0f32;
|
|
|
+pub type PosValue = i32;
|
|
|
|
|
|
-fn value_castling_rights(game: &Game, side: Side) -> PosValue {
|
|
|
- let mut val: PosValue = 0.0f32;
|
|
|
+pub const MIN_VALUE: PosValue = i32::MIN + 1;
|
|
|
+pub const MAX_VALUE: PosValue = i32::MAX;
|
|
|
|
|
|
- for i in 0..2 {
|
|
|
- if game.castling_rights[i] { val += 12.0f32; }
|
|
|
+const MATE_SHIFT: usize = 24;
|
|
|
+
|
|
|
+pub fn mate() -> PosValue {
|
|
|
+ mate_in_p1(1)
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * constructs a PosValue that indicates that from a given position mate
|
|
|
+ * can be achieved in turns-1 moves (not halfmoves)
|
|
|
+ */
|
|
|
+pub fn mate_in_p1(turns: i8) -> PosValue {
|
|
|
+ if turns >= 0 || turns == -128 {
|
|
|
+ (((127 - turns) as PosValue) << MATE_SHIFT) as i32
|
|
|
}
|
|
|
- for i in 2..4 {
|
|
|
- if game.castling_rights[i] { val -= 12.0f32; }
|
|
|
+ else {
|
|
|
+ -mate_in_p1(-turns)
|
|
|
}
|
|
|
-
|
|
|
- if side == BLACK {
|
|
|
- return -val;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * returns Some(turns) if the pos_val indicates that mate
|
|
|
+ * can be reached in turns-1 moves
|
|
|
+ *
|
|
|
+ * turns is negative if the moving side is getting mated
|
|
|
+ * in turns moves
|
|
|
+ */
|
|
|
+pub fn is_mate_in_p1(pos_val: PosValue) -> Option<i8> {
|
|
|
+ let highest_byte = (pos_val >> MATE_SHIFT) as i8;
|
|
|
+
|
|
|
+ if highest_byte != 0 && highest_byte != -1 {
|
|
|
+ if pos_val < 0 {
|
|
|
+ Some(-127 - highest_byte)
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Some(127 - highest_byte)
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
else {
|
|
|
- return val;
|
|
|
+ None
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
fn side_value(game: &Game, side: Side) -> u32 {
|
|
|
+ let adv_pawn_mask = match side { WHITE => ROW_7, BLACK => ROW_2 };
|
|
|
+ let semi_adv_pawn_mask = match side { WHITE => ROW_6, BLACK => ROW_3 };
|
|
|
+ let advanced_pawns = (game.get_piece(PAWN, side) & adv_pawn_mask).count_ones() * 200;
|
|
|
+ let semi_advanced_pawns = (game.get_piece(PAWN, side) & semi_adv_pawn_mask).count_ones() * 50;
|
|
|
+ advanced_pawns + semi_advanced_pawns
|
|
|
+}
|
|
|
+
|
|
|
+fn knight_value(game: &Game, side: Side) -> PosValue {
|
|
|
let knights = game.get_piece(KNIGHT, side);
|
|
|
let ks = BitboardIterator(knights);
|
|
|
let mut k_attacks: u32 = 0;
|
|
|
|
|
|
for k in ks {
|
|
|
let targets = get_knight_targets(square(k));
|
|
|
- k_attacks += targets.count_ones() * 4;
|
|
|
+ k_attacks += targets.count_ones() * 8;
|
|
|
}
|
|
|
|
|
|
- let adv_pawn_mask = match side { WHITE => ROW_7, BLACK => ROW_2 };
|
|
|
- let advanced_pawns = (game.get_piece(PAWN, side) & adv_pawn_mask).count_ones() * 200;
|
|
|
-
|
|
|
- advanced_pawns + k_attacks
|
|
|
-
|
|
|
+ let num_opp_pawns = game.get_piece(PAWN, !side).count_ones() as PosValue;
|
|
|
+ let num_knights = game.get_piece(KNIGHT, side).count_ones() as PosValue;
|
|
|
+
|
|
|
+ k_attacks as PosValue + ((num_knights * 75 * num_opp_pawns) / 8) as PosValue
|
|
|
}
|
|
|
|
|
|
fn material_value(game: &Game, side: Side) -> PosValue {
|
|
@@ -51,10 +85,34 @@ fn material_value(game: &Game, side: Side) -> PosValue {
|
|
|
+ game.get_piece(QUEEN, side).count_ones() * 700) as PosValue
|
|
|
}
|
|
|
|
|
|
+fn king_safety(game: &Game, side: Side) -> PosValue {
|
|
|
+ let king = game.get_piece(KING, side);
|
|
|
+ let area = north_one(king)
|
|
|
+ | south_one(king)
|
|
|
+ | east_one(king)
|
|
|
+ | west_one(king)
|
|
|
+ | northeast_one(king)
|
|
|
+ | northwest_one(king)
|
|
|
+ | southwest_one(king)
|
|
|
+ | southeast_one(king);
|
|
|
+
|
|
|
+ let guards = game.get_all_side(side) & area;
|
|
|
+ let attackers = game.get_all_side(!side) & area;
|
|
|
+
|
|
|
+ guards.count_ones() as PosValue * 10 - attackers.count_ones() as PosValue * 35
|
|
|
+}
|
|
|
+
|
|
|
+fn king_there(game: &Game, side: Side) -> PosValue {
|
|
|
+ if game.get_piece(KING, side) != 0 { 10000 } else { 0 }
|
|
|
+}
|
|
|
+
|
|
|
pub fn evaluate(game: &Game) -> PosValue {
|
|
|
let sv = side_value(game, game.turn) as PosValue - side_value(game, !game.turn) as PosValue;
|
|
|
let material_value_us = material_value(game, game.turn);
|
|
|
let material_value_them = material_value(game, !game.turn);
|
|
|
- let mat_val = material_value_us.powf(0.995f32) - material_value_them.powf(0.995f32);
|
|
|
- return mat_val + value_castling_rights(game, game.turn);
|
|
|
+ let mat_val = ((material_value_us as f32).powf(0.995f32) - (material_value_them as f32).powf(0.995f32)) as PosValue;
|
|
|
+ let kv = knight_value(game, game.turn) - knight_value(game, !game.turn);
|
|
|
+ let king_safety = king_safety(game, game.turn) - king_safety(game, !game.turn);
|
|
|
+ let king_there = king_there(game, game.turn) - king_there(game, !game.turn);
|
|
|
+ return sv + kv + king_safety + mat_val + king_there;
|
|
|
}
|