1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use super::*;
use crate::state::movescan;
use crate::state::representation::Board;
use crate::utils::assert_fast;

#[cfg(feature = "dev")]
use crate::tuning::tuner::TunerCoeff;

pub struct MobilityData {
    knight_mobility: PieceMobility,
    bishop_mobility: PieceMobility,
    rook_mobility: PieceMobility,
    queen_mobility: PieceMobility,
}

#[derive(Default)]
pub struct EvalAux {
    pub king_area_threats: i8,
}

pub struct PieceMobility {
    pub inner: i8,
    pub outer: i8,
}

/// Evaluates mobility and part of the king safety on the `board` and returns score from the white color perspective (more than 0 when advantage,
/// less than 0 when disadvantage). This evaluator does two things at once: first, counts all possible moves of knight, bishop, rook, queen
/// (pawns and king are too slow and not very important), and second, fills `white_aux` and `black_aux` with additional data used in other evaluators.
pub fn evaluate(board: &Board, white_aux: &mut EvalAux, black_aux: &mut EvalAux) -> PackedEval {
    let mut result = PackedEval::default();
    let white_data = get_mobility_data(board, WHITE, white_aux);
    let black_data = get_mobility_data(board, BLACK, black_aux);

    result += (white_data.knight_mobility.inner - black_data.knight_mobility.inner) * params::MOBILITY_INNER[KNIGHT];
    result += (white_data.bishop_mobility.inner - black_data.bishop_mobility.inner) * params::MOBILITY_INNER[BISHOP];
    result += (white_data.rook_mobility.inner - black_data.rook_mobility.inner) * params::MOBILITY_INNER[ROOK];
    result += (white_data.queen_mobility.inner - black_data.queen_mobility.inner) * params::MOBILITY_INNER[QUEEN];

    result += (white_data.knight_mobility.outer - black_data.knight_mobility.outer) * params::MOBILITY_OUTER[KNIGHT];
    result += (white_data.bishop_mobility.outer - black_data.bishop_mobility.outer) * params::MOBILITY_OUTER[BISHOP];
    result += (white_data.rook_mobility.outer - black_data.rook_mobility.outer) * params::MOBILITY_OUTER[ROOK];
    result += (white_data.queen_mobility.outer - black_data.queen_mobility.outer) * params::MOBILITY_OUTER[QUEEN];

    result
}

/// Gets mobility data for `board`, `color` and fills `aux` with additional data used in other evaluators.
fn get_mobility_data(board: &Board, color: usize, aux: &mut EvalAux) -> MobilityData {
    assert_fast!(color < 2);

    MobilityData {
        knight_mobility: movescan::get_piece_mobility::<KNIGHT>(board, color, aux),
        bishop_mobility: movescan::get_piece_mobility::<BISHOP>(board, color, aux),
        rook_mobility: movescan::get_piece_mobility::<ROOK>(board, color, aux),
        queen_mobility: movescan::get_piece_mobility::<QUEEN>(board, color, aux),
    }
}

/// Gets coefficients of mobility for `board` and inserts them into `coeffs`. Similarly, their indices (starting from `index`) are inserted into `indices`.
/// Some additional data is also saved in `white_aux` and `black_aux` for further processing.
#[cfg(feature = "dev")]
pub fn get_coeffs(board: &Board, white_aux: &mut EvalAux, black_aux: &mut EvalAux, index: &mut u16, coeffs: &mut Vec<TunerCoeff>, indices: &mut Vec<u16>) {
    let white_data = get_mobility_data(board, WHITE, white_aux);
    let black_data = get_mobility_data(board, BLACK, black_aux);

    let mut data = [
        TunerCoeff::new(0, OPENING),
        TunerCoeff::new(0, ENDING),
        TunerCoeff::new(white_data.knight_mobility.inner - black_data.knight_mobility.inner, OPENING),
        TunerCoeff::new(white_data.knight_mobility.inner - black_data.knight_mobility.inner, ENDING),
        TunerCoeff::new(white_data.bishop_mobility.inner - black_data.bishop_mobility.inner, OPENING),
        TunerCoeff::new(white_data.bishop_mobility.inner - black_data.bishop_mobility.inner, ENDING),
        TunerCoeff::new(white_data.rook_mobility.inner - black_data.rook_mobility.inner, OPENING),
        TunerCoeff::new(white_data.rook_mobility.inner - black_data.rook_mobility.inner, ENDING),
        TunerCoeff::new(white_data.queen_mobility.inner - black_data.queen_mobility.inner, OPENING),
        TunerCoeff::new(white_data.queen_mobility.inner - black_data.queen_mobility.inner, ENDING),
        TunerCoeff::new(0, OPENING),
        TunerCoeff::new(0, ENDING),
        //
        TunerCoeff::new(0, OPENING),
        TunerCoeff::new(0, ENDING),
        TunerCoeff::new(white_data.knight_mobility.outer - black_data.knight_mobility.outer, OPENING),
        TunerCoeff::new(white_data.knight_mobility.outer - black_data.knight_mobility.outer, ENDING),
        TunerCoeff::new(white_data.bishop_mobility.outer - black_data.bishop_mobility.outer, OPENING),
        TunerCoeff::new(white_data.bishop_mobility.outer - black_data.bishop_mobility.outer, ENDING),
        TunerCoeff::new(white_data.rook_mobility.outer - black_data.rook_mobility.outer, OPENING),
        TunerCoeff::new(white_data.rook_mobility.outer - black_data.rook_mobility.outer, ENDING),
        TunerCoeff::new(white_data.queen_mobility.outer - black_data.queen_mobility.outer, OPENING),
        TunerCoeff::new(white_data.queen_mobility.outer - black_data.queen_mobility.outer, ENDING),
        TunerCoeff::new(0, OPENING),
        TunerCoeff::new(0, ENDING),
    ];

    for coeff in &mut data {
        let (value, _) = coeff.get_data();
        if value != 0 {
            indices.push(*index);
            coeffs.push(coeff.clone());
        }

        *index += 1;
    }
}