Today I've routed search output through the engine thread to the Comm module, so search doesn't write to STDOUT directly anymore. This allows me to convert the search information into UCI, XBoard, or whatever protocol I need to support in the future without actually having to change either the search or the engine. (Assuming I don't need additional information.)
I've also implemented basic move sorting using MVV_LVA using this table:
Code: Select all
pub const MVV_LVA: [[u8; NrOf::PIECE_TYPES + 1]; NrOf::PIECE_TYPES + 1] = [
[0, 0, 0, 0, 0, 0, 0], // victim K, attacker K, Q, R, B, N, P, None
[50, 51, 52, 53, 54, 55, 0], // victim Q, attacker K, Q, R, B, N, P, None
[40, 41, 42, 43, 44, 45, 0], // victim R, attacker K, Q, R, B, N, P, None
[30, 31, 32, 33, 34, 35, 0], // victim B, attacker K, Q, R, B, N, P, None
[20, 21, 22, 23, 24, 25, 0], // victim K, attacker K, Q, R, B, N, P, None
[10, 11, 12, 13, 14, 15, 0], // victim P, attacker K, Q, R, B, N, P, None
[0, 0, 0, 0, 0, 0, 0], // victim None, attacker K, Q, R, B, N, P, None
];
The King (impossible to capture) and None (no piece captured) are just in there so i can index any move into this table without checking anything. So Queen captured by Pawn yields 55, Rook captured by King yields 40, and so on. Using this I implemented move_scoring() and then tried sort_moves() and then pick_move() (sort_moves sorts all the moves, pick_move runs through the list and swaps the best scored move into the current index in the move list):
Code: Select all
$ ./target/release/rustic.exe -f "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1"
// No sorting.
depth: 1, bestmove: d2d4, eval: 400, time: 0s, nodes: 1, knps: 0
depth: 2, bestmove: d2d4, eval: -855, time: 0s, nodes: 8, knps: 0
depth: 3, bestmove: d2d4, eval: 35, time: 0s, nodes: 242, knps: 0
depth: 4, bestmove: g1h1, eval: -560, time: 0.002s, nodes: 2541, knps: 1271
depth: 5, bestmove: c4c5, eval: -105, time: 0.044s, nodes: 90990, knps: 2068
depth: 6, bestmove: g1h1, eval: -550, time: 0.53s, nodes: 704017, knps: 1328
depth: 7, bestmove: c4c5, eval: -140, time: 7.655s, nodes: 19164279, knps: 2503
depth: 8, bestmove: c4c5, eval: -525, time: 101.286s, nodes: 149397666, knps: 1475
// Sort Moves
depth: 1, bestmove: d2d4, eval: 400, time: 0s, nodes: 1, knps: 0
depth: 2, bestmove: d2d4, eval: -855, time: 0s, nodes: 8, knps: 0
depth: 3, bestmove: d2d4, eval: 35, time: 0s, nodes: 107, knps: 0
depth: 4, bestmove: g1h1, eval: -560, time: 0s, nodes: 625, knps: 0
depth: 5, bestmove: c4c5, eval: -105, time: 0.005s, nodes: 8324, knps: 1665
depth: 6, bestmove: g1h1, eval: -550, time: 0.022s, nodes: 26090, knps: 1186
depth: 7, bestmove: c4c5, eval: -140, time: 0.142s, nodes: 222147, knps: 1564
depth: 8, bestmove: c4c5, eval: -525, time: 0.692s, nodes: 839942, knps: 1214
depth: 9, bestmove: c4c5, eval: -190, time: 4.11s, nodes: 6640093, knps: 1616
depth: 10, bestmove: c4c5, eval: -490, time: 17.971s, nodes: 23531619, knps: 1309
// Pick Move
depth: 1, bestmove: d2d4, eval: 400, time: 0s, nodes: 1, knps: 0
depth: 2, bestmove: d2d4, eval: -855, time: 0s, nodes: 8, knps: 0
depth: 3, bestmove: d2d4, eval: 35, time: 0s, nodes: 107, knps: 0
depth: 4, bestmove: g1h1, eval: -560, time: 0s, nodes: 625, knps: 0
depth: 5, bestmove: c4c5, eval: -105, time: 0.003s, nodes: 8324, knps: 2775
depth: 6, bestmove: g1h1, eval: -550, time: 0.012s, nodes: 26090, knps: 2174
depth: 7, bestmove: c4c5, eval: -140, time: 0.07s, nodes: 222147, knps: 3174
depth: 8, bestmove: c4c5, eval: -525, time: 0.499s, nodes: 839942, knps: 1683
depth: 9, bestmove: c4c5, eval: -190, time: 1.881s, nodes: 6640093, knps: 3530
depth: 10, bestmove: c4c5, eval: -490, time: 13.823s, nodes: 23531619, knps: 1702
depth: 11, bestmove: c4c5, eval: -265, time: 64.836s, nodes: 228325596, knps: 3522
Rustic can now basically search up to depth 8-9 instantaneously in many positions. Please note that killers, history heuristic and a hash table are not yet implemented. (And quiescence search isn't either, which will probably cause iterative deepening to not go as deep, as it extends each iteration. I also assume that QSearch will solve the evaluation jumping around, and I'll have to look up if I need to print the eval from the side to move, or use the side of the color the engine is playing all the time.)