const std = @import("std");
const Chess = @import("Chess.zig");
const BitMove = @import("Board.zig").BitMove;
const BitMoveType = @import("Board.zig").BitMoveType;
const Search = @import("Search.zig").Search;
const Square = @import("Board.zig").Square;
const MoveList = @import("Board.zig").MoveList;
// These values are arbitrary, but only decreasing makes sense.
const CAPTURE_BOOST = 10_000;
const KILLER_FIRST = 9_000;
const KILLER_SECOND = 8_000;
// PV value score
pub const PV_SCORE = 20_000;
// Best move score
const BEST_MOVE_SCORE = 30_000;
// Killer moves [first/second][MAX_PLY]
pub var killer_moves: [2][64]BitMove = undefined;
// History moves [piece][square]
pub var history_moves: [@typeInfo(Chess.PE).Enum.fields.len - 1][@typeInfo(Square).Enum.fields.len]usize = undefined;
pub fn moves(search: *const Search, ml: *MoveList, best: BitMove) void {
for (ml.slice()) |*mp| {
mp.score = scoreMove(search, mp.move, best);
}
}
fn scoreMove(search: *const Search, move: BitMove, best: BitMove) isize {
if (@as(BitMoveType, @bitCast(move)) == @as(BitMoveType, @bitCast(best))) {
return BEST_MOVE_SCORE;
}
if (move.capture) {
var target_piece = Chess.PE.P; // this could be p as well
const pieces = switch (search.state.side) {
.white => &[_]Chess.PE{ .p, .n, .b, .r, .q, .k },
.black => &[_]Chess.PE{ .P, .N, .B, .R, .Q, .K },
};
for (pieces) |piece| {
if (search.state.bitboards[@intFromEnum(piece)].isSet(move.target)) {
target_piece = piece;
break;
}
}
return MVV_LVA[@intFromEnum(move.piece)][@intFromEnum(target_piece)] + CAPTURE_BOOST;
} else {
// score 1st killer move
if (@as(BitMoveType, @bitCast(killer_moves[0][search.ply])) == @as(BitMoveType, @bitCast(move))) {
return KILLER_FIRST;
}
// score 2nd killer move
else if (@as(BitMoveType, @bitCast(killer_moves[1][search.ply])) == @as(BitMoveType, @bitCast(move))) {
return KILLER_SECOND;
}
// score history moves
else {
return @as(
isize,
@intCast(history_moves[@intFromEnum(move.piece)][@intFromEnum(move.target)]),
);
}
return 0;
}
return 0;
}
// most valuable victim & less valuable attacker
// (Victims) Pawn Knight Bishop Rook Queen King
// (Attackers)
// Pawn 105 205 305 405 505 605
// Knight 104 204 304 404 504 604
// Bishop 103 203 303 403 503 603
// Rook 102 202 302 402 502 602
// Queen 101 201 301 401 501 601
// King 100 200 300 400 500 600
// MVV LVA [attacker][victim]
const MVV_LVA: [12][12]isize = .{
.{ 105, 205, 305, 405, 505, 605, 105, 205, 305, 405, 505, 605 },
.{ 104, 204, 304, 404, 504, 604, 104, 204, 304, 404, 504, 604 },
.{ 103, 203, 303, 403, 503, 603, 103, 203, 303, 403, 503, 603 },
.{ 102, 202, 302, 402, 502, 602, 102, 202, 302, 402, 502, 602 },
.{ 101, 201, 301, 401, 501, 601, 101, 201, 301, 401, 501, 601 },
.{ 100, 200, 300, 400, 500, 600, 100, 200, 300, 400, 500, 600 },
.{ 105, 205, 305, 405, 505, 605, 105, 205, 305, 405, 505, 605 },
.{ 104, 204, 304, 404, 504, 604, 104, 204, 304, 404, 504, 604 },
.{ 103, 203, 303, 403, 503, 603, 103, 203, 303, 403, 503, 603 },
.{ 102, 202, 302, 402, 502, 602, 102, 202, 302, 402, 502, 602 },
.{ 101, 201, 301, 401, 501, 601, 101, 201, 301, 401, 501, 601 },
.{ 100, 200, 300, 400, 500, 600, 100, 200, 300, 400, 500, 600 },
};