| | 1 | | using Rudim.Common; |
| | 2 | | using System.Collections.Generic; |
| | 3 | | using System.Linq; |
| | 4 | |
|
| | 5 | | namespace Rudim.Board |
| | 6 | | { |
| | 7 | | public static class MoveOrdering |
| | 8 | | { |
| | 9 | | private static readonly int[,] MostValuableVictimLeastValuableAttacker; |
| | 10 | | private static Move[,] _killerMoves; |
| | 11 | | private static int[,] _historyMoves; |
| | 12 | |
|
| | 13 | | static MoveOrdering() |
| | 14 | | { |
| 1 | 15 | | MostValuableVictimLeastValuableAttacker = new[,] |
| 1 | 16 | | { |
| 1 | 17 | | // P , N , B , R , Q , K , None |
| 1 | 18 | | { 15_000, 14_000, 13_000, 12_000, 11_000, 10_000, 0 }, // P |
| 1 | 19 | | { 25_000, 24_000, 23_000, 22_000, 21_000, 20_000, 0 }, // N |
| 1 | 20 | | { 35_000, 34_000, 33_000, 32_000, 31_000, 30_000, 0 }, // B |
| 1 | 21 | | { 45_000, 44_000, 43_000, 42_000, 41_000, 40_000, 0 }, // R |
| 1 | 22 | | { 55_000, 54_000, 53_000, 52_000, 51_000, 50_000, 0 }, // Q |
| 1 | 23 | | { 65_000, 64_000, 63_000, 62_000, 61_000, 60_000, 0 }, // K |
| 1 | 24 | | { 0, 0, 0, 0, 0, 0, 0 } // None |
| 1 | 25 | | }; |
| 1 | 26 | | ResetMoveHeuristic(); |
| 1 | 27 | | } |
| | 28 | |
|
| | 29 | | public static void PopulateMoveScore(Move move, BoardState boardState, int ply = Constants.MaxPly - 1) |
| | 30 | | { |
| 62281546 | 31 | | if (!move.IsCapture()) |
| | 32 | | { |
| 55336120 | 33 | | if (move == _killerMoves[0, ply]) |
| 364967 | 34 | | move.Score = 9000; // TODO : Revisit, assign better values and extract to constants |
| 54971153 | 35 | | else if (move == _killerMoves[1, ply]) |
| 276004 | 36 | | move.Score = 8000; |
| | 37 | | else |
| 54695149 | 38 | | move.Score = _historyMoves[boardState.GetPieceOn(move.Source), (int)move.Target]; |
| 54695149 | 39 | | return; |
| | 40 | | } |
| | 41 | | int targetPiece; |
| 6945426 | 42 | | int sourcePiece = boardState.GetPieceOn(move.Source, boardState.SideToMove); |
| 6945426 | 43 | | if (move.Type == MoveTypes.EnPassant) |
| 16710 | 44 | | targetPiece = (int)Piece.Pawn; |
| | 45 | | else |
| 6928716 | 46 | | targetPiece = boardState.GetPieceOn(move.Target, boardState.SideToMove.Other()); |
| 6945426 | 47 | | move.Score = MostValuableVictimLeastValuableAttacker[targetPiece, sourcePiece]; |
| 6945426 | 48 | | } |
| | 49 | |
|
| | 50 | | public static void AddKillerMove(Move move, int ply) |
| | 51 | | { |
| 69557 | 52 | | if (_killerMoves[0, ply] == move) |
| | 53 | | { |
| 62453 | 54 | | return; |
| | 55 | | } |
| | 56 | |
|
| 7104 | 57 | | _killerMoves[1, ply] = _killerMoves[0, ply]; |
| 7104 | 58 | | _killerMoves[0, ply] = move; |
| 7104 | 59 | | } |
| | 60 | |
|
| | 61 | | public static void AddHistoryMove(int piece, Move move, int depth) |
| | 62 | | { |
| 1120 | 63 | | _historyMoves[piece, (int)move.Target] += depth * depth; |
| 1120 | 64 | | } |
| | 65 | |
|
| | 66 | | public static void ResetMoveHeuristic() |
| | 67 | | { |
| 10 | 68 | | _killerMoves = new Move[Constants.Sides, Constants.MaxPly]; |
| 10 | 69 | | _historyMoves = new int[Constants.Pieces * 2, Constants.Squares]; |
| 10 | 70 | | } |
| | 71 | |
|
| | 72 | | public static bool IsMoveHeuristicEmpty() |
| | 73 | | { |
| 899 | 74 | | return _killerMoves.Cast<Move>().All(move => move == null) && _historyMoves.Cast<int>().All(move => move == |
| | 75 | | } |
| | 76 | |
|
| | 77 | | public static void PopulateHashMove(Move move) |
| | 78 | | { |
| 0 | 79 | | move.Score = 10_500; |
| 0 | 80 | | } |
| | 81 | |
|
| | 82 | | public static void SortNextBestMove(List<Move> moves, int startingIndex) |
| | 83 | | { |
| 6396424 | 84 | | int bestIndex = startingIndex; |
| 388241798 | 85 | | for (int i = startingIndex + 1; i < moves.Count; ++i) |
| | 86 | | { |
| 187724475 | 87 | | if (moves[i].Score >= moves[bestIndex].Score) |
| 46138334 | 88 | | bestIndex = i; |
| | 89 | | } |
| | 90 | |
|
| 6396424 | 91 | | if(bestIndex != startingIndex) |
| 6191500 | 92 | | (moves[bestIndex], moves[startingIndex]) = (moves[startingIndex], moves[bestIndex]); |
| 6396424 | 93 | | } |
| | 94 | | } |
| | 95 | | } |