/// <summary> /// Search pawn and king hash table for a pawn and king specific score for the specific position hash. /// </summary> /// <param name="hashCodeA"> /// Hash Code for Board position A /// </param> /// <param name="hashCodeB"> /// Hash Code for Board position B /// </param> /// <param name="colour"> /// The player colour. /// </param> /// <returns> /// Pawn and king specific score for the specified position. /// </returns> public static unsafe int ProbeHash(ulong hashCodeA, ulong hashCodeB, Player.PlayerColourNames colour) { if (colour == Player.PlayerColourNames.Black) { hashCodeA |= 0x1; hashCodeB |= 0x1; } else { hashCodeA &= 0xFFFFFFFFFFFFFFFE; hashCodeB &= 0xFFFFFFFFFFFFFFFE; } Probes++; fixed(HashEntry *phashBase = &hashTableEntries[0]) { HashEntry *phashEntry = phashBase; phashEntry += (uint)(hashCodeA % hashTableSize); if (phashEntry->HashCodeA == hashCodeA && phashEntry->HashCodeB == hashCodeB) { Hits++; return(phashEntry->Points); } } return(NotFoundInHashTable); }
/// <summary> /// The lines first piece. /// </summary> /// <param name="colour"> /// The colour. /// </param> /// <param name="pieceName"> /// The piece name. /// </param> /// <param name="squareStart"> /// The square start. /// </param> /// <param name="offset"> /// The offset. /// </param> /// <returns> /// The first piece on the line, or null. /// </returns> public static Piece LinesFirstPiece( Player.PlayerColourNames colour, Piece.PieceNames pieceName, Square squareStart, int offset) { int intOrdinal = squareStart.Ordinal; Square square; intOrdinal += offset; while ((square = GetSquare(intOrdinal)) != null) { if (square.Piece == null) { } else if (square.Piece.Player.Colour != colour) { return(null); } else if (square.Piece.Name == pieceName || square.Piece.Name == Piece.PieceNames.Queen) { return(square.Piece); } else { return(null); } intOrdinal += offset; } return(null); }
/// <summary> /// Search Hash table for a previously stored score. /// </summary> /// <param name="hashCodeA"> /// Hash Code for Board position A /// </param> /// <param name="hashCodeB"> /// Hash Code for Board position B /// </param> /// <param name="depth"> /// The search depth. /// </param> /// <param name="alpha"> /// Apha value. /// </param> /// <param name="beta"> /// Beta value. /// </param> /// <param name="colour"> /// The player colour. /// </param> /// <returns> /// The positional score. /// </returns> public static unsafe int ProbeHash( ulong hashCodeA, ulong hashCodeB, int depth, int alpha, int beta, Player.PlayerColourNames colour) { Probes++; fixed(HashEntry *phashBase = &hashTableEntries[0]) { HashEntry *phashEntry = phashBase; phashEntry += (uint)(hashCodeA % hashTableSize); int intAttempt = 0; while (phashEntry >= phashBase && (phashEntry->HashCodeA != hashCodeA || phashEntry->HashCodeB != hashCodeB || phashEntry->Depth < depth)) { phashEntry--; intAttempt++; if (intAttempt == HashTableSlotDepth) { break; } } if (phashEntry < phashBase) { phashEntry = phashBase; } if (phashEntry->HashCodeA == hashCodeA && phashEntry->HashCodeB == hashCodeB && phashEntry->Depth >= depth) { if (phashEntry->Colour == colour) { if (phashEntry->Type == HashTypeNames.Exact) { Hits++; return(phashEntry->Result); } if ((phashEntry->Type == HashTypeNames.Alpha) && (phashEntry->Result <= alpha)) { Hits++; return(alpha); } if ((phashEntry->Type == HashTypeNames.Beta) && (phashEntry->Result >= beta)) { Hits++; return(beta); } } } } return(NotFoundInHashTable); }
/// <summary> /// Record a new history entry. /// </summary> /// <param name="colour"> /// The player colour. /// </param> /// <param name="ordinalFrom"> /// The From square ordinal. /// </param> /// <param name="ordinalTo"> /// The To square ordinal. /// </param> /// <param name="value"> /// The history heuristic weighting value. /// </param> public static void Record(Player.PlayerColourNames colour, int ordinalFrom, int ordinalTo, int value) { if (colour == Player.PlayerColourNames.White) { HistoryTableEntriesforWhite[ordinalFrom, ordinalTo] += value; } else { HistoryTableEntriesforBlack[ordinalFrom, ordinalTo] += value; } }
/// <summary> /// Record a new history entry. /// </summary> /// <param name="colour"> /// The player colour. /// </param> /// <param name="ordinalFrom"> /// The From square ordinal. /// </param> /// <param name="ordinalTo"> /// The To square ordinal. /// </param> /// <param name="value"> /// The history heuristic weighting value. /// </param> public static void Record(Player.PlayerColourNames colour, int ordinalFrom, int ordinalTo, int value) { // Disable if this feature when switched off. if (!Game.EnableHistoryHeuristic) { return; } if (colour == Player.PlayerColourNames.White) { HistoryTableEntriesforWhite[ordinalFrom, ordinalTo] += value; } else { HistoryTableEntriesforBlack[ordinalFrom, ordinalTo] += value; } }
/// <summary> /// Calculates a positional penalty score for a single open line to a square (usually the king square), in a specified direction. /// </summary> /// <param name="colour"> /// The player's colour. /// </param> /// <param name="squareStart"> /// The square piece (king) is on. /// </param> /// <param name="directionOffset"> /// The direction offset. /// </param> /// <returns> /// The open line penalty. /// </returns> public static int OpenLinePenalty(Player.PlayerColourNames colour, Square squareStart, int directionOffset) { int intOrdinal = squareStart.Ordinal; int intSquareCount = 0; int intPenalty = 0; Square square; intOrdinal += directionOffset; while (intSquareCount <= 2 && ((square = GetSquare(intOrdinal)) != null && (square.Piece == null || (square.Piece.Name != Piece.PieceNames.Pawn && square.Piece.Name != Piece.PieceNames.Rook) || square.Piece.Player.Colour != colour))) { intPenalty += 75; intSquareCount++; intOrdinal += directionOffset; } return(intPenalty); }
/// <summary> /// Record a hash new hash entry in the hash table. /// </summary> /// <param name="hashCodeA"> /// Hash Code for Board position A /// </param> /// <param name="hashCodeB"> /// Hash Code for Board position B /// </param> /// <param name="depth"> /// The search depth. /// </param> /// <param name="val"> /// The score of the position to record. /// </param> /// <param name="type"> /// The position type: alpha, beta or exact value. /// </param> /// <param name="from"> /// From square ordinal. /// </param> /// <param name="to"> /// To square ordinal. /// </param> /// <param name="moveName"> /// The move name. /// </param> /// <param name="colour"> /// The player colour. /// </param> public static unsafe void RecordHash( ulong hashCodeA, ulong hashCodeB, int depth, int val, HashTypeNames type, int from, int to, Move.MoveNames moveName, Player.PlayerColourNames colour) { Writes++; fixed(HashEntry *phashBase = &hashTableEntries[0]) { HashEntry *phashEntry = phashBase; phashEntry += (uint)(hashCodeA % hashTableSize); int intAttempt = 0; while (phashEntry >= phashBase && phashEntry->HashCodeA != 0 && phashEntry->Depth > depth) { phashEntry--; intAttempt++; if (intAttempt == HashTableSlotDepth) { break; } } if (phashEntry < phashBase) { phashEntry = phashBase; } if (phashEntry->HashCodeA != 0) { Collisions++; if (phashEntry->HashCodeA != hashCodeA || phashEntry->HashCodeB != hashCodeB) { Overwrites++; phashEntry->WhiteFrom = -1; phashEntry->BlackFrom = -1; } } phashEntry->HashCodeA = hashCodeA; phashEntry->HashCodeB = hashCodeB; phashEntry->Result = val; phashEntry->Type = type; phashEntry->Depth = (sbyte)depth; phashEntry->Colour = colour; if (from > -1) { if (colour == Player.PlayerColourNames.White) { phashEntry->WhiteMoveName = moveName; phashEntry->WhiteFrom = (sbyte)from; phashEntry->WhiteTo = (sbyte)to; } else { phashEntry->BlackMoveName = moveName; phashEntry->BlackFrom = (sbyte)from; phashEntry->BlackTo = (sbyte)to; } } } }
/// <summary> /// Search for best move in hash table. /// </summary> /// <param name="hashCodeA"> /// Hash Code for Board position A /// </param> /// <param name="hashCodeB"> /// Hash Code for Board position B /// </param> /// <param name="colour"> /// The player colour. /// </param> /// <returns> /// Best move, or null. /// </returns> public static unsafe Move ProbeForBestMove(ulong hashCodeA, ulong hashCodeB, Player.PlayerColourNames colour) { // TODO Unit test Hash Table. What happens when same position stored at different depths in diffenent slots with the same hash? fixed(HashEntry *phashBase = &hashTableEntries[0]) { HashEntry *phashEntry = phashBase; phashEntry += (uint)(hashCodeA % hashTableSize); int intAttempt = 0; while (phashEntry >= phashBase && (phashEntry->HashCodeA != hashCodeA || phashEntry->HashCodeB != hashCodeB)) { phashEntry--; intAttempt++; if (intAttempt == HashTableSlotDepth) { break; } } if (phashEntry < phashBase) { phashEntry = phashBase; } if (phashEntry->HashCodeA == hashCodeA && phashEntry->HashCodeB == hashCodeB) { if (colour == Player.PlayerColourNames.White) { if (phashEntry->WhiteFrom >= 0) { return(new Move( 0, 0, phashEntry->WhiteMoveName, Board.GetPiece(phashEntry->WhiteFrom), Board.GetSquare(phashEntry->WhiteFrom), Board.GetSquare(phashEntry->WhiteTo), Board.GetSquare(phashEntry->WhiteTo).Piece, 0, phashEntry->Result)); } } else { if (phashEntry->BlackFrom >= 0) { return(new Move( 0, 0, phashEntry->BlackMoveName, Board.GetPiece(phashEntry->BlackFrom), Board.GetSquare(phashEntry->BlackFrom), Board.GetSquare(phashEntry->BlackTo), Board.GetSquare(phashEntry->BlackTo).Piece, 0, phashEntry->Result)); } } } } return(null); }
/// <summary> /// Retrieve a value from the History Heuristic table. /// </summary> /// <param name="colour"> /// The player colour. /// </param> /// <param name="ordinalFrom"> /// The From square ordinal. /// </param> /// <param name="ordinalTo"> /// The To square ordinal. /// </param> /// <returns> /// The history heuristic weighting value. /// </returns> public static int Retrieve(Player.PlayerColourNames colour, int ordinalFrom, int ordinalTo) { return(colour == Player.PlayerColourNames.White ? HistoryTableEntriesforWhite[ordinalFrom, ordinalTo] : HistoryTableEntriesforBlack[ordinalFrom, ordinalTo]); }
/// <summary> /// Record the pawn and kind specific positional score in the pawn king hash table. /// </summary> /// <param name="hashCodeA"> /// Hash Code for Board position A /// </param> /// <param name="hashCodeB"> /// Hash Code for Board position B /// </param> /// <param name="val"> /// Pawn king specific score. /// </param> /// <param name="colour"> /// Player colour. /// </param> public static unsafe void RecordHash(ulong hashCodeA, ulong hashCodeB, int val, Player.PlayerColourNames colour) { if (colour == Player.PlayerColourNames.Black) { hashCodeA |= 0x1; hashCodeB |= 0x1; } else { hashCodeA &= 0xFFFFFFFFFFFFFFFE; hashCodeB &= 0xFFFFFFFFFFFFFFFE; } fixed(HashEntry *phashBase = &hashTableEntries[0]) { HashEntry *phashEntry = phashBase; phashEntry += (uint)(hashCodeA % hashTableSize); phashEntry->HashCodeA = hashCodeA; phashEntry->HashCodeB = hashCodeB; phashEntry->Points = val; } Writes++; }
/// <summary> /// Record a hash new hash entry in the hash table. /// </summary> /// <param name="hashCodeA"> /// Hash Code for Board position A /// </param> /// <param name="hashCodeB"> /// Hash Code for Board position B /// </param> /// <param name="from"> /// From square ordinal. /// </param> /// <param name="to"> /// To square ordinal. /// </param> /// <param name="moveName"> /// The move name. /// </param> /// <param name="colour"> /// The player colour. /// </param> private static unsafe void RecordHash(ulong hashCodeA, ulong hashCodeB, byte from, byte to, Move.MoveNames moveName, Player.PlayerColourNames colour) { if (colour == Player.PlayerColourNames.Black) { hashCodeA |= 0x1; hashCodeB |= 0x1; } else { hashCodeA &= 0xFFFFFFFFFFFFFFFE; hashCodeB &= 0xFFFFFFFFFFFFFFFE; } fixed(HashEntry *phashBase = &HashTableEntries[0]) { HashEntry *phashEntry = phashBase; phashEntry += (uint)(hashCodeA % HashTableSize); phashEntry->HashCodeA = hashCodeA; phashEntry->HashCodeB = hashCodeB; phashEntry->From = from; phashEntry->To = to; phashEntry->MoveName = moveName; } }
/// <summary> /// The probe opening book (hash table) for best move for the specied board position (hash code). /// </summary> /// <param name="hashCodeA"> /// The hash code for board position A. /// </param> /// <param name="hashCodeB"> /// The hash code for board position B. /// </param> /// <param name="colour"> /// The player colour. /// </param> /// <returns> /// The best move in the opening book (hash table) or null if there is no opening book entry for the specified board position. /// </returns> private static unsafe Move ProbeForBestMove(ulong hashCodeA, ulong hashCodeB, Player.PlayerColourNames colour) { if (colour == Player.PlayerColourNames.Black) { hashCodeA |= 0x1; hashCodeB |= 0x1; } else { hashCodeA &= 0xFFFFFFFFFFFFFFFE; hashCodeB &= 0xFFFFFFFFFFFFFFFE; } fixed(HashEntry *phashBase = &HashTableEntries[0]) { HashEntry *phashEntry = phashBase; phashEntry += (uint)(hashCodeA % HashTableSize); if (phashEntry->HashCodeA == hashCodeA && phashEntry->HashCodeB == hashCodeB) { return(new Move(0, 0, phashEntry->MoveName, Board.GetPiece(phashEntry->From), Board.GetSquare(phashEntry->From), Board.GetSquare(phashEntry->To), null, 0, 0)); } } return(NotFoundInHashTable); }
/// <summary> /// The search for best move in opening book. /// </summary> /// <param name="boardHashCodeA"> /// The board hash code a. /// </param> /// <param name="boardHashCodeB"> /// The board hash code b. /// </param> /// <param name="colour"> /// The colour. /// </param> /// <returns> /// The best move from the opening book. /// </returns> public static Move SearchForGoodMove(ulong boardHashCodeA, ulong boardHashCodeB, Player.PlayerColourNames colour) { return(ProbeForBestMove(boardHashCodeA, boardHashCodeB, colour)); }