public void PawnHashBackPawnTests() { PawnHashEntry entry = new PawnHashEntry(); int[] a = new int[] { 0, 15, 4, 0, 9, 15, 3, 2, 11, 8, 10, 0, 15, 15, 14, 1 }; int[] b = new int[] { 1, 0, 4, 15, 14, 15, 15, 0, 2, 9, 4, 15, 0, 15, 14, 15 }; for (int x = 0; x < 16; x++) { entry.SetBackPawnRank(0, x, a[x]); entry.SetBackPawnRank(1, x, b[x]); } for (int x = 0; x < 16; x++) { Assert.AreEqual(entry.GetBackPawnRank(0, x), a[x]); Assert.AreEqual(entry.GetBackPawnRank(1, x), b[x]); } for (int x = 0; x < 16; x++) { entry.SetBackPawnRank(0, x, b[x]); entry.SetBackPawnRank(1, x, a[x]); } for (int x = 0; x < 16; x++) { Assert.AreEqual(entry.GetBackPawnRank(0, x), b[x]); Assert.AreEqual(entry.GetBackPawnRank(1, x), a[x]); } // make sure copying the struct works correctly PawnHashEntry e2; e2 = entry; for (int x = 0; x < 16; x++) { Assert.AreEqual(e2.GetBackPawnRank(0, x), b[x]); Assert.AreEqual(e2.GetBackPawnRank(1, x), a[x]); } }
protected override void cleanup() { base.cleanup(); PawnStructureInfo = new PawnHashEntry(); }
public override void AdjustEvaluation(ref int midgameEval, ref int endgameEval) { // *** CHECK PAWN STRUCTURE HASH TABLE *** // if (pawnHashTable == null) { pawnHashTable = new PawnHashEntry[65536]; // 2^16 slots (4 MB) for (int x = 0; x < 65536; x++) { pawnHashTable[x].PassedPawns = new BitBoard(board.NumSquares); } } game.Statistics.PawnHashLookups++; int slot = (int)(game.Board.PawnHashCode & 0x000000000000FFFFUL); if (pawnHashTable[slot].HashCode == game.Board.PawnHashCode) { midgameEval += pawnHashTable[slot].MidgameAdjustment; endgameEval += pawnHashTable[slot].EndgameAdjustment; if (PassedPawnEvaluation == true) { EvaluatePassedPawns(pawnHashTable[slot].PassedPawns, ref midgameEval, ref endgameEval); } chessGame.PawnStructureInfo = pawnHashTable[slot]; game.Statistics.PawnHashHits++; return; } // *** DETERMINE BASIC PAWN INFO *** // int midgameAdjustment = 0; int endgameAdjustment = 0; // reset information pawnHashTable[slot].PassedPawns.Clear(); for (int file = 0; file < board.NumFiles + 2; file++) { player0pawns[file] = 0; player1pawns[file] = 0; player0backPawn[file] = 15; player1backPawn[file] = 0; } // loop through player 0's pawns BitBoard p0pawns = board.GetPieceTypeBitboard(0, pawnTypeNumber); while (p0pawns) { int square = p0pawns.ExtractLSB(); int file = board.GetFile(square); int rank = board.GetRank(square); player0pawns[file + 1]++; if (rank < player0backPawn[file + 1]) { player0backPawn[file + 1] = rank; } } // loop through player 1's pawns BitBoard p1pawns = board.GetPieceTypeBitboard(1, pawnTypeNumber); while (p1pawns) { int square = p1pawns.ExtractLSB(); int file = board.GetFile(square); int rank = board.GetRank(square); player1pawns[file + 1]++; if (rank > player1backPawn[file + 1]) { player1backPawn[file + 1] = rank; } } // Check for cylindrical board. If we are playing with a // cylindrical board, we need to consider the edges connected. if (board is Boards.CylindricalBoard) { player0pawns[0] = player0pawns[board.NumFiles]; player0backPawn[0] = player0backPawn[board.NumFiles]; player0pawns[board.NumFiles + 1] = player0pawns[1]; player0backPawn[board.NumFiles + 1] = player0backPawn[1]; player1pawns[0] = player1pawns[board.NumFiles]; player1backPawn[0] = player1backPawn[board.NumFiles]; player1pawns[board.NumFiles + 1] = player1pawns[1]; player1backPawn[board.NumFiles + 1] = player1backPawn[1]; } // *** APPLY THIS INFO TO EACH PAWN TO DETERMINE STATUS *** // // lopp through player 0's pawns p0pawns = board.GetPieceTypeBitboard(0, pawnTypeNumber); while (p0pawns) { int square = p0pawns.ExtractLSB(); int pawnFile = board.GetFile(square); int pawnRank = board.GetRank(square); bool isolated = false; bool backward = false; if (player0pawns[pawnFile] == 0 && player0pawns[pawnFile + 2] == 0) { // isolated pawn midgameAdjustment -= Adjustments.IsolatedMidgame; endgameAdjustment -= Adjustments.IsolatedEndgame; isolated = true; } if (player0backPawn[pawnFile] > pawnRank && player0backPawn[pawnFile + 2] > pawnRank) { // backward pawn midgameAdjustment -= Adjustments.BackwardMidgame; endgameAdjustment -= Adjustments.BackwardEndgame; backward = true; } if (player1pawns[pawnFile + 1] == 0) { // penalize weak, exposed pawns if (backward) { midgameAdjustment -= Adjustments.WeakExposedMidgame; endgameAdjustment -= Adjustments.WeakExposedEndgame; } if (isolated) { midgameAdjustment -= Adjustments.WeakExposedMidgame; endgameAdjustment -= Adjustments.WeakExposedEndgame; } } if (player0backPawn[pawnFile + 1] < pawnRank) { // doubled, trippled, etc. midgameAdjustment -= Adjustments.DoubledMidgame; endgameAdjustment -= Adjustments.DoubledEndgame; } if (pawnRank >= player1backPawn[pawnFile + 1] && pawnRank >= player1backPawn[pawnFile] && pawnRank >= player1backPawn[pawnFile + 2] && (player0pawns[pawnFile + 1] == 1 || pawnRank > player0backPawn[pawnFile + 1])) { // passed pawn pawnHashTable[slot].PassedPawns.SetBit(square); // midgameAdjustment += Adjustments.PassedMidgame; // endgameAdjustment += Adjustments.PassedEndgame; // if( !isolated ) // { // midgameAdjustment += Adjustments.PassedNotIsolatedMidgame; // endgameAdjustment += Adjustments.PassedNotIsolatedEndgame; // } } } // loop through player 1's pawns p1pawns = board.GetPieceTypeBitboard(1, pawnTypeNumber); while (p1pawns) { int square = p1pawns.ExtractLSB(); int pawnFile = board.GetFile(square); int pawnRank = board.GetRank(square); bool isolated = false; bool backward = false; if (player1pawns[pawnFile] == 0 && player1pawns[pawnFile + 2] == 0) { // isolated pawn midgameAdjustment += Adjustments.IsolatedMidgame; endgameAdjustment += Adjustments.IsolatedEndgame; isolated = true; } if (player1backPawn[pawnFile] < pawnRank && player1backPawn[pawnFile + 2] < pawnRank) { // backward pawn midgameAdjustment += Adjustments.BackwardMidgame; endgameAdjustment += Adjustments.BackwardEndgame; backward = true; } if (player0pawns[pawnFile + 1] == 0) { // penalize weak, exposed pawns if (backward) { midgameAdjustment += Adjustments.WeakExposedMidgame; endgameAdjustment += Adjustments.WeakExposedEndgame; } if (isolated) { midgameAdjustment += Adjustments.WeakExposedMidgame; endgameAdjustment += Adjustments.WeakExposedEndgame; } } if (player1backPawn[pawnFile + 1] > pawnRank) { // doubled, trippled, etc. midgameAdjustment += Adjustments.DoubledMidgame; endgameAdjustment += Adjustments.DoubledEndgame; } if (pawnRank <= player0backPawn[pawnFile + 1] && pawnRank <= player0backPawn[pawnFile] && pawnRank <= player0backPawn[pawnFile + 2] && (player1pawns[pawnFile + 1] == 1 || pawnRank < player1backPawn[pawnFile + 1])) { // passed pawn pawnHashTable[slot].PassedPawns.SetBit(square); // midgameAdjustment -= Adjustments.PassedMidgame; // endgameAdjustment -= Adjustments.PassedEndgame; // if( !isolated ) // { // midgameAdjustment -= Adjustments.PassedNotIsolatedMidgame; // endgameAdjustment -= Adjustments.PassedNotIsolatedEndgame; // } } } if (PassedPawnEvaluation == true) { EvaluatePassedPawns(pawnHashTable[slot].PassedPawns, ref midgameEval, ref endgameEval); } // store this information in the pawn hash table pawnHashTable[slot].HashCode = board.PawnHashCode; pawnHashTable[slot].MidgameAdjustment = midgameAdjustment; pawnHashTable[slot].EndgameAdjustment = endgameAdjustment; for (int file = 0; file < board.NumFiles; file++) { pawnHashTable[slot].SetBackPawnRank(0, file, player0backPawn[file + 1]); pawnHashTable[slot].SetBackPawnRank(1, file, player1backPawn[file + 1]); } chessGame.PawnStructureInfo = pawnHashTable[slot]; // adjust the actual evaluations accordingly midgameEval += midgameAdjustment; endgameEval += endgameAdjustment; }
// *** OVERRIDES *** // public override void AdjustEvaluation(ref int midgameEval, ref int endgameEval) { int penalty; int kingsq; int kingrank; int kingfile; int pawnguards; int sq; Piece p; PawnHashEntry pawnhash = chessGame.PawnStructureInfo; // *** PLAYER 0 *** // penalty = 0; kingsq = board.GetPieceTypeBitboard(0, kingTypeNumber).LSB; kingrank = board.GetRank(kingsq); kingfile = board.GetFile(kingsq); // count pawn guards pawnguards = 0; if (kingfile == 0) { pawnguards++; } else { sq = board.NextSquare(PredefinedDirections.NW, kingsq); if (sq >= 0) { p = board[sq]; if (p != null && p.Player == 0 && p.TypeNumber == pawnTypeNumber) { pawnguards++; } } } if (kingfile == board.NumFiles - 1) { pawnguards++; } else { sq = board.NextSquare(PredefinedDirections.NE, kingsq); if (sq >= 0) { p = board[sq]; if (p != null && p.Player == 0 && p.TypeNumber == pawnTypeNumber) { pawnguards++; } } } sq = board.NextSquare(PredefinedDirections.N, kingsq); if (sq >= 0) { p = board[sq]; if (p != null && p.Player == 0 && p.TypeNumber == pawnTypeNumber) { pawnguards++; } } // determine penalty for bad pawn protection penalty = 3 - pawnguards; if (kingrank != 0) { penalty += 3; if (kingfile == 0) { penalty--; } else { sq = board.NextSquare(PredefinedDirections.W, kingsq); p = board[sq]; if (p != null && p.Player == 0 && p.TypeNumber == pawnTypeNumber) { penalty--; } } if (kingfile == board.NumFiles - 1) { penalty--; } else { sq = board.NextSquare(PredefinedDirections.E, kingsq); p = board[sq]; if (p != null && p.Player == 0 && p.TypeNumber == pawnTypeNumber) { penalty--; } } } // penalty for being on or adjacent to open file or in front of pawn line int a = pawnhash.GetBackPawnRank(0, kingfile); if (pawnhash.GetBackPawnRank(0, kingfile) == 15 || pawnhash.GetBackPawnRank(0, kingfile) < board.GetRank(kingsq)) { penalty += 2; } else if (kingfile > 0 && (pawnhash.GetBackPawnRank(0, kingfile - 1) == 15 || pawnhash.GetBackPawnRank(0, kingfile - 1) < board.GetRank(kingsq))) { penalty += 2; } else if (kingfile < board.NumFiles - 1 && (pawnhash.GetBackPawnRank(0, kingfile + 1) == 15 || pawnhash.GetBackPawnRank(0, kingfile + 1) < board.GetRank(kingsq))) { penalty += 2; } // penalty for being close to enemy pieces of tropism types foreach (int type in tropismTypes) { BitBoard bb = board.GetPieceTypeBitboard(1, type); while (bb) { int psq = bb.ExtractLSB(); int distance = board.GetDistance(kingsq, psq); if (distance < 3) { penalty++; if (distance == 1) { penalty += 2; } } } } // assess penalty midgameEval -= penalty * 4; if (penalty >= 2) { midgameEval -= (penalty - 1) * 3; } if (penalty >= 4) { midgameEval -= (penalty - 3) * 4; } // *** PLAYER 1 *** // penalty = 0; kingsq = board.GetPieceTypeBitboard(1, kingTypeNumber).LSB; kingrank = board.GetRank(kingsq); kingfile = board.GetFile(kingsq); // count pawn guards pawnguards = 0; if (kingfile == 0) { pawnguards++; } else { sq = board.NextSquare(PredefinedDirections.SW, kingsq); if (sq >= 0) { p = board[sq]; if (p != null && p.Player == 1 && p.TypeNumber == pawnTypeNumber) { pawnguards++; } } } if (kingfile == board.NumFiles - 1) { pawnguards++; } else { sq = board.NextSquare(PredefinedDirections.SE, kingsq); if (sq >= 0) { p = board[sq]; if (p != null && p.Player == 1 && p.TypeNumber == pawnTypeNumber) { pawnguards++; } } } sq = board.NextSquare(PredefinedDirections.S, kingsq); if (sq >= 0) { p = board[sq]; if (p != null && p.Player == 1 && p.TypeNumber == pawnTypeNumber) { pawnguards++; } } // determine penalty for bad pawn protection penalty = 3 - pawnguards; if (kingrank != board.NumRanks - 1) { penalty += 3; if (kingfile == 0) { penalty--; } else { sq = board.NextSquare(PredefinedDirections.W, kingsq); p = board[sq]; if (p != null && p.Player == 1 && p.TypeNumber == pawnTypeNumber) { penalty--; } } if (kingfile == board.NumFiles - 1) { penalty--; } else { sq = board.NextSquare(PredefinedDirections.E, kingsq); p = board[sq]; if (p != null && p.Player == 1 && p.TypeNumber == pawnTypeNumber) { penalty--; } } } // penalty for being on or adjacent to open file or in front of pawn line if (pawnhash.GetBackPawnRank(0, kingfile) == 0 || pawnhash.GetBackPawnRank(0, kingfile) > board.GetRank(kingsq)) { penalty += 2; } else if (kingfile > 0 && (pawnhash.GetBackPawnRank(0, kingfile - 1) == 0 || pawnhash.GetBackPawnRank(0, kingfile - 1) > board.GetRank(kingsq))) { penalty += 2; } else if (kingfile < board.NumFiles - 1 && (pawnhash.GetBackPawnRank(0, kingfile + 1) == 0 || pawnhash.GetBackPawnRank(0, kingfile + 1) > board.GetRank(kingsq))) { penalty += 2; } // penalty for being close to enemy pieces of tropism types foreach (int type in tropismTypes) { BitBoard bb = board.GetPieceTypeBitboard(0, type); while (bb) { int psq = bb.ExtractLSB(); int distance = board.GetDistance(kingsq, psq); if (distance < 3) { penalty++; if (distance == 1) { penalty += 2; } } } } // assess penalty midgameEval += penalty * 4; if (penalty >= 2) { midgameEval += (penalty - 1) * 3; } if (penalty >= 4) { midgameEval += (penalty - 3) * 4; } }