/// <summary>we are informed of the score produced by the move at any level</summary> public virtual void BetaCutoff(Board board, int move, int depth) { // removes captures and promotions from killers if (move == 0 || Move.IsTactical(move)) { return; } if (move != killerMove1[depth]) { killerMove2[depth] = killerMove1[depth]; killerMove1[depth] = move; } history[Move.GetPieceMoved(move) - 1][Move.GetToIndex(move)]++; // Detect history overflows and divide all values by two if (history[Move.GetPieceMoved(move) - 1][Move.GetToIndex(move)] >= HISTORY_MAX) { for (int i = 0; i < 6; i++) { for (int j = 0; j < 64; j++) { history[i][j] = (int)(((uint)history[i][j]) >> 1); } } } }
/// <summary>TODO elaborate a bit</summary> /// <returns></returns> public virtual long CalculateMoveTime(Board board) { if (infinite) { return 999999999; } if (moveTime != 0) { return moveTime; } int calctime = 0; if (board.GetTurn()) { if (wtime > 0) { calctime = wtime / 40 + winc; } } else { if (btime > 0) { calctime = btime / 40 + binc; } } logger.Debug("Thinking for " + calctime + "Ms"); return calctime; }
public MoveIterator(Board board, SortInfo sortInfo, int depth) { this.sortInfo = sortInfo; this.board = board; this.depth = depth; bbAttacks = BitboardAttacks.GetInstance(); }
/// <summary>get only LEGAL Operations by testing with domove</summary> public override int GenerateMoves(Board board, int[] moves, int index) { int lastIndex = base.GenerateMoves(board, moves, index); int j = index; for (int i = 0; i < lastIndex; i++) { if (board.DoMove(moves[i], false)) { moves[j++] = moves[i]; board.UndoMove(); } } return j; }
public virtual void Save(Board board, byte depthAnalyzed, int bestMove, int score , int lowerBound, int upperBound, bool exclusion) { if (score <= lowerBound) { Set(board, TranspositionTable.TYPE_FAIL_LOW, bestMove, score, depthAnalyzed, exclusion ); } else { if (score >= upperBound) { Set(board, TranspositionTable.TYPE_FAIL_HIGH, bestMove, score, depthAnalyzed, exclusion ); } else { Set(board, TranspositionTable.TYPE_EXACT_SCORE, bestMove, score, depthAnalyzed, exclusion ); } } }
/// <summary>Returns true if key matches with key stored</summary> public override bool Search(Board board, bool exclusion) { info = 0; index = (int)((long)(((ulong)(exclusion ? board.GetExclusionKey() : board.GetKey( ))) >> (64 - sizeBits))) & ~unchecked((int)(0x01)); // Get the first odd index long key2 = board.GetKey2(); // Verifies that is really this board if (keys[index] == key2 || keys[++index] == key2) { // Already returns the correct index info = infos[index]; return true; } return false; }
public override void Set(Board board, int nodeType, int bestMove, int score, byte depthAnalyzed, bool exclusion) { long key2 = board.GetKey2(); index = (int)((long)(((ulong)(exclusion ? board.GetExclusionKey() : board.GetKey( ))) >> (64 - sizeBits))) & ~unchecked((int)(0x01)); // Get the first odd index info = infos[index]; if (keys[index] == 0 || ((sbyte)GetDepthAnalyzed()) <= depthAnalyzed || GetGeneration () != generation) { } else { // Replace odd entry // Replace even entry index++; } keys[index] = key2; info = (bestMove & unchecked((int)(0x1fffff))) | ((nodeType & unchecked((int)(0xf ))) << 21) | (((long)(generation & unchecked((int)(0xff)))) << 32) | (((long)(depthAnalyzed & unchecked((int)(0xff)))) << 40) | (((long)(score & unchecked((int)(0xffff)))) << 48); infos[index] = info; }
// D5 // logger.debug("***PAWN"); // printPcsq(pawnIndexValue); // logger.debug("***KNIGHT"); // printPcsq(knightIndexValue); // logger.debug("***BISHOP"); // printPcsq(bishopIndexValue); // logger.debug("***ROOK"); // printPcsq(rookIndexValue); // logger.debug("***QUEEN"); // printPcsq(queenIndexValue); // logger.debug("***KING"); // printPcsq(kingIndexValue); // logger.debug("PCSQ tables generated"); // private static void printPcsq(int pcsq[][]) { // StringBuffer sb = new StringBuffer(); // for (int k=0; k<2; k++) { // if (k==0) sb.append("Opening:\n"); // else sb.append("Endgame:\n"); // for (int i = 0; i<64; i++) { // String aux = " " + pcsq[i][k]; // aux = aux.substring(aux.length()-5); // sb.append(aux); // if (i%8 != 7) { // sb.append(","); // } else { // sb.append("\n"); // } // } // } // logger.debug(sb.toString()); // } // int kingDefense[] = {0,0}; // Squares attackeds by pawns // Squares surrounding King public override int EvaluateBoard(Board board, int alpha, int beta) { all = board.GetAll(); Arrays.Fill(bishopCount, 0); Arrays.Fill(superiorPieceAttacked, 0); Arrays.Fill(material, 0); Arrays.Fill(pawnMaterial, 0); Arrays.Fill(mobility, 0); Arrays.Fill(attacks, 0); Arrays.Fill(center, 0); Arrays.Fill(positional, 0); Arrays.Fill(kingAttackersCount, 0); Arrays.Fill(kingSafety, 0); Arrays.Fill(pawnStructure, 0); Arrays.Fill(passedPawns, 0); // Squares attackeds by pawns pawnAttacks[0] = ((board.pawns & board.whites & ~BitboardUtils.b_l) << 9) | ((board .pawns & board.whites & ~BitboardUtils.b_r) << 7); pawnAttacks[1] = ((long)(((ulong)(board.pawns & board.blacks & ~BitboardUtils.b_r )) >> 9)) | ((long)(((ulong)(board.pawns & board.blacks & ~BitboardUtils.b_l)) >> 7)); // Squares surrounding King squaresNearKing[0] = bbAttacks.king[BitboardUtils.Square2Index(board.whites & board .kings)]; squaresNearKing[1] = bbAttacks.king[BitboardUtils.Square2Index(board.blacks & board .kings)]; // From material imbalances (Larry Kaufmann): // A further refinement would be to raise the knight's value by 1/16 and lower the rook's value by 1/8 // for each pawn above five of the side being valued, with the opposite adjustment for each pawn short of five int whitePawnsCount = BitboardUtils.PopCount(board.pawns & board.whites); int blackPawnsCount = BitboardUtils.PopCount(board.pawns & board.blacks); knightKaufBonus[0] = KNIGHT_KAUF_BONUS * (whitePawnsCount - 5); knightKaufBonus[1] = KNIGHT_KAUF_BONUS * (blackPawnsCount - 5); rookKaufBonus[0] = ROOK_KAUF_BONUS * (whitePawnsCount - 5); rookKaufBonus[1] = ROOK_KAUF_BONUS * (blackPawnsCount - 5); square = 1; index = 0; while (square != 0) { isWhite = ((board.whites & square) != 0); color = (isWhite ? 0 : 1); mines = (isWhite ? board.whites : board.blacks); others = (isWhite ? board.blacks : board.whites); pcsqIndex = (isWhite ? index : 63 - index); if ((square & all) != 0) { int rank = index >> 3; int column = 7 - index & 7; if ((square & board.pawns) != 0) { pawnMaterial[color] += PAWN; center[color] += pawnIndexValue[pcsqIndex]; pieceAttacks = (isWhite ? bbAttacks.pawnUpwards[index] : bbAttacks.pawnDownwards[ index]); superiorPieceAttacked[color] |= pieceAttacks & others & (board.knights | board.bishops | board.rooks | board.queens); if ((pieceAttacks & squaresNearKing[1 - color]) != 0) { kingSafety[color] += PAWN_ATTACKS_KING; } // Doubled pawn detection if ((BitboardUtils.COLUMN[column] & BitboardUtils.RANKS_FORWARD[color][rank] & board .pawns & mines) != square) { pawnStructure[color] += PAWN_DOUBLED; } // Blocked Pawn // boolean blocked = ((isWhite ? (square<< 8) : (square >>> 8)) & others) != 0; // if (blocked) pawnStructure[color] += PAWN_BLOCKED; // Backwards Pawn // if (((BitboardUtils.COLUMN[column] | BitboardUtils.COLUMNS_ADJACENTS[column]) & ~BitboardUtils.RANKS_FORWARD[color][rank] & board.pawns & mines) == 0) // pawnStructure[color] += PAWN_BACKWARD; // Passed Pawn if (((BitboardUtils.COLUMN[column] | BitboardUtils.COLUMNS_ADJACENTS[column]) & ( isWhite ? BitboardUtils.RANKS_UPWARDS[rank] : BitboardUtils.RANKS_DOWNWARDS[rank ]) & board.pawns & others) == 0) { passedPawns[color] += PAWN_PASSER[(isWhite ? rank : 7 - rank)]; if ((square & pawnAttacks[color]) != 0) { passedPawns[color] += PAWN_PASSER_SUPPORT[(isWhite ? rank : 7 - rank)]; } passedPawns[color] += PAWN_PASSER_KING_D[(isWhite ? rank : 7 - rank)] * BitboardUtils .Distance(index, BitboardUtils.Square2Index(board.kings & others)); } // Isolated pawn bool isolated = (BitboardUtils.COLUMNS_ADJACENTS[column] & board.pawns & mines) == 0; if (isolated) { pawnStructure[color] += PAWN_ISOLATED; } long auxLong; long auxLong2; bool weak = !isolated && (pawnAttacks[color] & square) == 0; // && pcsqIndex >= 24 // not defended is weak and only if over rank 2 if (weak) { // Can be defended advancing one square auxLong = (isWhite ? bbAttacks.pawnDownwards[color] : bbAttacks.pawnUpwards[color ]) & ~pawnAttacks[1 - color] & ~all; while (auxLong != 0) { // Not attacked by other pawn and empty auxLong2 = BitboardUtils.Lsb(auxLong); auxLong &= ~auxLong2; auxLong2 = isWhite ? (long)(((ulong)auxLong2) >> 8) : auxLong2 << 8; if ((auxLong2 & mines & board.pawns) != 0) { weak = false; } else { // Defended advancing one pawn two squares if ((auxLong2 & all) == 0) { // empty square auxLong2 = (isWhite ? (long)(((ulong)auxLong2) >> 8) : auxLong2 << 8); if (((isWhite ? BitboardUtils.RANK[1] : BitboardUtils.RANK[6]) & auxLong2 & board .pawns & mines) != 0) { weak = false; } } } } if (weak) { // Can advance to be supported auxLong = (isWhite ? square << 8 : (long)(((ulong)square) >> 8)) & ~pawnAttacks[1 - color] & ~all; if (auxLong != 0) { if ((auxLong & pawnAttacks[color]) != 0) { weak = false; } else { // Checks advancing two squares if in initial position if (((isWhite ? BitboardUtils.RANK[1] : BitboardUtils.RANK[6]) & square) != 0) { auxLong = (isWhite ? square << 16 : (long)(((ulong)square) >> 16)) & ~pawnAttacks [1 - color] & ~all; if ((auxLong & pawnAttacks[color]) != 0) { weak = false; } } } } } } if (weak) { pawnStructure[color] += PAWN_WEAK; } } else { // if (weak) { // System.out.println("weak pawn: \n" + board.toString()); // System.out.println("square: \n" + BitboardUtils.toString(square)); // } if ((square & board.knights) != 0) { material[color] += KNIGHT + knightKaufBonus[color]; center[color] += knightIndexValue[pcsqIndex]; pieceAttacks = bbAttacks.knight[index]; auxInt = BitboardUtils.PopCount(pieceAttacks & ~mines & ~pawnAttacks[1 - color]) - KNIGHT_M_UNITS; mobility[color] += KNIGHT_M * auxInt; if ((pieceAttacks & squaresNearKing[color]) != 0) { kingSafety[color] += KNIGHT_ATTACKS_KING; kingAttackersCount[color]++; } superiorPieceAttacked[color] |= pieceAttacks & others & (board.rooks | board.queens ); // Knight outpost: no opposite pawns can attack the square and is defended by one of our pawns if (((BitboardUtils.COLUMNS_ADJACENTS[column] & (isWhite ? BitboardUtils.RANKS_UPWARDS [rank] : BitboardUtils.RANKS_DOWNWARDS[rank]) & board.pawns & others) == 0) && ( ((isWhite ? bbAttacks.pawnDownwards[index] : bbAttacks.pawnUpwards[index]) & board .pawns & mines) != 0)) { positional[color] += KNIGTH_OUTPOST[pcsqIndex]; } } else { if ((square & board.bishops) != 0) { material[color] += BISHOP; if (bishopCount[color]++ == 2) { material[color] += BISHOP_PAIR; } center[color] += bishopIndexValue[pcsqIndex]; pieceAttacks = bbAttacks.GetBishopAttacks(index, all); auxInt = BitboardUtils.PopCount(pieceAttacks & ~mines & ~pawnAttacks[1 - color]) - BISHOP_M_UNITS; mobility[color] += BISHOP_M * auxInt; if ((pieceAttacks & squaresNearKing[1 - color]) != 0) { kingSafety[color] += BISHOP_ATTACKS_KING; kingAttackersCount[color]++; } pieceAttacksXray = bbAttacks.GetBishopAttacks(index, all & ~(pieceAttacks & others )) & ~pieceAttacks; if ((pieceAttacksXray & (board.rooks | board.queens | board.kings) & others) != 0) { attacks[color] += PINNED_PIECE; } superiorPieceAttacked[color] |= pieceAttacks & others & (board.rooks | board.queens ); if ((BISHOP_TRAPPING[index] & board.pawns & others) != 0) { mobility[color] += BISHOP_TRAPPED; } } else { if ((square & board.rooks) != 0) { material[color] += ROOK + rookKaufBonus[color]; center[color] += rookIndexValue[pcsqIndex]; pieceAttacks = bbAttacks.GetRookAttacks(index, all); auxInt = BitboardUtils.PopCount(pieceAttacks & ~mines & ~pawnAttacks[1 - color]) - ROOK_M_UNITS; mobility[color] += ROOK_M * auxInt; pieceAttacksXray = bbAttacks.GetRookAttacks(index, all & ~(pieceAttacks & others) ) & ~pieceAttacks; if ((pieceAttacksXray & (board.queens | board.kings) & others) != 0) { attacks[color] += PINNED_PIECE; } if ((pieceAttacks & squaresNearKing[1 - color]) != 0) { kingSafety[color] += ROOK_ATTACKS_KING; kingAttackersCount[color]++; } superiorPieceAttacked[color] |= pieceAttacks & others & board.queens; if ((pieceAttacks & mines & (board.rooks)) != 0) { positional[color] += ROOK_CONNECT; } pieceAttacks = BitboardUtils.COLUMN[column]; if ((pieceAttacks & board.pawns) == 0) { positional[color] += ROOK_COLUMN_OPEN; } else { if ((pieceAttacks & board.pawns & mines) == 0) { positional[color] += ROOK_COLUMN_SEMIOPEN; } } } else { if ((square & board.queens) != 0) { center[color] += queenIndexValue[pcsqIndex]; material[color] += QUEEN; pieceAttacks = bbAttacks.GetRookAttacks(index, all) | bbAttacks.GetBishopAttacks( index, all); auxInt = BitboardUtils.PopCount(pieceAttacks & ~mines & ~pawnAttacks[1 - color]) - QUEEN_M_UNITS; mobility[color] += QUEEN_M * auxInt; if ((pieceAttacks & squaresNearKing[1 - color]) != 0) { kingSafety[color] += QUEEN_ATTACKS_KING; kingAttackersCount[color]++; } pieceAttacksXray = (bbAttacks.GetRookAttacks(index, all & ~(pieceAttacks & others )) | bbAttacks.GetBishopAttacks(index, all & ~(pieceAttacks & others))) & ~pieceAttacks; if ((pieceAttacksXray & board.kings & others) != 0) { attacks[color] += PINNED_PIECE; } } else { if ((square & board.kings) != 0) { pieceAttacks = bbAttacks.king[index]; center[color] += kingIndexValue[pcsqIndex]; // TODO if ((square & (isWhite ? BitboardUtils.RANK[1] : BitboardUtils.RANK[7])) != 0) { positional[color] += KING_PAWN_NEAR * BitboardUtils.PopCount(pieceAttacks & mines & board.pawns); } } } } } } } } square <<= 1; index++; } // Ponder opening and Endgame value depending of the non-pawn pieces: // opening=> gamephase = 255 / ending => gamephase ~= 0 int gamePhase = ((material[0] + material[1]) << 8) / 5000; if (gamePhase > 256) { gamePhase = 256; } // Security int value = 0; // First Material value += pawnMaterial[0] - pawnMaterial[1] + material[0] - material[1]; // Tempo value += (board.GetTurn() ? TEMPO : -TEMPO); int oe = config.GetEvalCenter() * (center[0] - center[1]) + config.GetEvalPositional () * (positional[0] - positional[1]) + config.GetEvalAttacks() * (attacks[0] - attacks [1]) + config.GetEvalMobility() * (mobility[0] - mobility[1]) + config.GetEvalPawnStructure () * (pawnStructure[0] - pawnStructure[1]) + config.GetEvalPassedPawns() * (passedPawns [0] - passedPawns[1]) + (config.GetEvalKingSafety() / 8) * ((KING_SAFETY_PONDER[ kingAttackersCount[0]] * kingSafety[0] - KING_SAFETY_PONDER[kingAttackersCount[1 ]] * kingSafety[1])) + config.GetEvalAttacks() * ((BitboardUtils.PopCount(superiorPieceAttacked [0]) >= 2 ? HUNG_PIECES : 0) - (BitboardUtils.PopCount(superiorPieceAttacked[1]) >= 2 ? HUNG_PIECES : 0)); // Divide by eight value += (gamePhase * O(oe)) / (256 * 100); // divide by 256 value += ((256 - gamePhase) * E(oe)) / (256 * 100); if (debug) { logger.Debug("\n" + board.ToString()); logger.Debug(board.GetFen()); logger.Debug("materialValue = " + (material[0] - material[1])); logger.Debug("pawnMaterialValue = " + (pawnMaterial[0] - pawnMaterial[1])); logger.Debug("centerOpening = " + O(center[0] - center[1])); logger.Debug("centerEndgame = " + E(center[0] - center[1])); logger.Debug("positionalOpening = " + O(positional[0] - positional[1])); logger.Debug("positionalEndgame = " + E(positional[0] - positional[1])); logger.Debug("attacksO = " + O(attacks[0] - attacks[1])); logger.Debug("attacksE = " + E(attacks[0] - attacks[1])); logger.Debug("mobilityO = " + O(mobility[0] - mobility[1])); logger.Debug("mobilityE = " + E(mobility[0] - mobility[1])); logger.Debug("pawnsO = " + O(pawnStructure[0] - pawnStructure[1]) ); logger.Debug("pawnsE = " + E(pawnStructure[0] - pawnStructure[1]) ); logger.Debug("passedPawnsO = " + O(passedPawns[0] - passedPawns[1])); logger.Debug("passedPawnsE = " + E(passedPawns[0] - passedPawns[1])); logger.Debug("kingSafetyValueO = " + O(KING_SAFETY_PONDER[kingAttackersCount [0]] * kingSafety[0] - KING_SAFETY_PONDER[kingAttackersCount[1]] * kingSafety[1] )); logger.Debug("kingSafetyValueE = " + E(KING_SAFETY_PONDER[kingAttackersCount [0]] * kingSafety[0] - KING_SAFETY_PONDER[kingAttackersCount[1]] * kingSafety[1] )); logger.Debug("HungPiecesO = " + O((BitboardUtils.PopCount(superiorPieceAttacked [0]) >= 2 ? HUNG_PIECES : 0) - (BitboardUtils.PopCount(superiorPieceAttacked[1]) >= 2 ? HUNG_PIECES : 0))); logger.Debug("HungPiecesE = " + O((BitboardUtils.PopCount(superiorPieceAttacked [0]) >= 2 ? HUNG_PIECES : 0) - (BitboardUtils.PopCount(superiorPieceAttacked[1]) >= 2 ? HUNG_PIECES : 0))); logger.Debug("gamePhase = " + gamePhase); logger.Debug("tempo = " + (board.GetTurn() ? TEMPO : -TEMPO)); logger.Debug("value = " + value); } return value; }
public static long[] GetKey(Board board) { long[] key = new long[] { 0, 0 }; long square = BitboardUtils.H1; byte index = 0; int color = 0; while (square != 0) { color = (square & board.whites) != 0 ? 0 : 1; key[color] ^= GetKeyPieceIndex(index, board.GetPieceAt(square)); square <<= 1; index++; } if (board.GetWhiteKingsideCastling()) { key[0] ^= whiteKingSideCastling; } if (board.GetWhiteQueensideCastling()) { key[0] ^= whiteQueenSideCastling; } if (board.GetBlackKingsideCastling()) { key[1] ^= blackKingSideCastling; } if (board.GetBlackQueensideCastling()) { key[1] ^= blackQueenSideCastling; } // passant flags only when pawn can capture long passant = board.GetPassantSquare(); if ((passant != 0) && (((!board.GetTurn() && (((passant << 9) | (passant << 7)) & board.blacks & board.pawns) != 0)) || ((board.GetTurn() && ((((long)(((ulong)passant ) >> 9)) | ((long)(((ulong)passant) >> 7))) & board.whites & board.pawns) != 0)) )) { color = board.GetTurn() ? 0 : 1; // TODO test key[1 - color] ^= passantColumn[BitboardUtils.GetColumn(passant)]; } if (board.GetTurn()) { key[0] ^= whiteMove; } return key; }
public virtual string GetPgn(Board b, string whiteName, string blackName, string @event, string site, string result) { // logger.debug("PGN start"); StringBuilder sb = new StringBuilder(); if (whiteName == null || string.Empty.Equals(whiteName)) { whiteName = "?"; } if (blackName == null || string.Empty.Equals(blackName)) { blackName = "?"; } if (@event == null) { @event = "Chess Game"; } if (site == null) { site = "-"; } sb.Append("[Event \"" + @event + "\"]\n"); sb.Append("[Site \"" + site + "\"]\n"); //DateTime d = new DateTime(); // For GWT we use deprecated methods //sb.Append("[Date \"" + d.GetYear() + "." + d.GetMonth() + "." + d.GetDay() + "\"]\n" // ); sb.Append("[Round \"?\"]\n"); sb.Append("[White \"" + whiteName + "\"]\n"); sb.Append("[Black \"" + blackName + "\"]\n"); if (result == null) { result = "*"; switch (b.IsEndGame()) { case 1: { result = "1-0"; break; } case -1: { result = "0-1"; break; } case 99: { result = "1/2-1/2"; break; } } } sb.Append("[Result \"" + result + "\"]\n"); if (!Board.FEN_START_POSITION.Equals(b.initialFen)) { sb.Append("[FEN \"" + b.initialFen + "\"]\n"); } sb.Append("[PlyCount \"" + (b.moveNumber - b.initialMoveNumber) + "\"]\n"); sb.Append("\n"); StringBuilder line = new StringBuilder(); for (int i = b.initialMoveNumber; i < b.moveNumber; i++) { line.Append(" "); if ((i & 1) == 0) { line.Append(((int)(((uint)i) >> 1)) + 1); line.Append("."); } line.Append(b.GetSanMove(i)); } if (!"*".Equals(result)) { line.Append(" "); line.Append(result); } // Cut line in a limit of 80 characters string[] tokens = line.ToString().Split("[ \\t\\n\\x0B\\f\\r]+"); int length = 0; for (int i_1 = 0; i_1 < tokens.Length; i_1++) { string next = tokens[i_1]; if (length + next.Length + 1 > 80) { sb.Append("\n"); length = 0; } else { if (length > 0) { sb.Append(" "); length++; } } length += next.Length; sb.Append(next); } // logger.debug("PGN end"); // logger.debug("PGN:\n" + sb.toString()); return sb.ToString(); }
public SearchEngine(Config config) { // time to think to // For testing suites // Inital Ply of search // For performance Benching // aspiration window // Futility pruning // Aggresive Futility pruning // Razoring // Singular Extension // Null Move // Transposition Table this.config = config; random = new Random(); board = new Board(); sortInfo = new SortInfo(); moveIterators = new MoveIterator[MAX_DEPTH]; for (int i = 0; i < MAX_DEPTH; i++) { moveIterators[i] = new MoveIterator(board, sortInfo, i); } pvReductionMatrix = new int[][] { new int[64], new int[64], new int[64], new int[ 64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64 ], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int [64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64 ], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int [64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64 ], new int[64], new int[64], new int[64], new int[64] }; nonPvReductionMatrix = new int[][] { new int[64], new int[64], new int[64], new int [64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64 ], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int [64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64 ], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64], new int [64], new int[64], new int[64], new int[64], new int[64], new int[64], new int[64 ], new int[64], new int[64], new int[64], new int[64] }; // Init our reduction lookup tables for (int depth = 1; depth < MAX_DEPTH; depth++) { // OnePly = 1 for (int moveNumber = 1; moveNumber < 64; moveNumber++) { double pvRed = 0.5 + Math.Log(depth) * Math.Log(moveNumber) / 6.0; double nonPVRed = 0.5 + Math.Log(depth) * Math.Log(moveNumber) / 3.0; pvReductionMatrix[depth][moveNumber] = (int)(pvRed >= 1.0 ? Math.Floor(pvRed * PLY ) : 0); nonPvReductionMatrix[depth][moveNumber] = (int)(nonPVRed >= 1.0 ? Math.Floor(nonPVRed * PLY) : 0); } } // System.out.println(i + " " + j + " " + // pvReductionMatrix[i][j] + " " + nonPvReductionMatrix[i][j]); Init(); }
public virtual long GetXrayAttacks(Board board, int index, long all) { if (index < 0 || index > 63) { return 0; } return ((GetRookAttacks(index, all) & (board.rooks | board.queens)) | (GetBishopAttacks (index, all) & (board.bishops | board.queens))) & all; }
/// <summary>In case of collision overwrites replace the eldest keep pv nodes</summary> public override void Set(Board board, int nodeType, int bestMove, int score, byte depthAnalyzed, bool exclusion) { long key2 = board.GetKey2(); int startIndex = (int)((long)(((ulong)(exclusion ? board.GetExclusionKey() : board .GetKey())) >> (64 - sizeBits))) & ~unchecked((int)(0x03)); // Verifies that is really this board index = -1; for (int i = startIndex; i < startIndex + MAX_PROBES; i++) { info = infos[i]; if (keys[i] == 0 || (keys[i] == key2)) { // Empty or replace if (keys[i] != 0 && GetGeneration() == generation && (depthAnalyzed == 0 || GetDepthAnalyzed () > depthAnalyzed)) { // When // replacing // something // my // generation // || (getDepthAnalyzed() == depthAnalyzed && // getNodeType() == TYPE_EXACT_SCORE && nodeType != // TYPE_EXACT_SCORE) return; } // Never replace with eval values or lower depth or // exact scores with other nodetypes index = i; if (keys[i] == key2 && bestMove == 0) { bestMove = GetBestMove(); } // Keep best move when replacing // and no move break; } if (GetGeneration() != generation || ((sbyte)GetDepthAnalyzed()) < depthAnalyzed) { // TODO // < // or // >= // ? index = i; break; } } if (index == -1) { return; } // No slot found keys[index] = key2; info = (bestMove & unchecked((int)(0x1fffff))) | ((nodeType & unchecked((int)(0xf ))) << 21) | (((long)(generation & unchecked((int)(0xff)))) << 32) | (((long)(depthAnalyzed & unchecked((int)(0xff)))) << 40) | (((long)(score & unchecked((int)(0xffff)))) << 48); infos[index] = info; }
public virtual void SetBoard(Board board) { this.board = board; }
/// <summary>In case of collision overwrites replace the eldest keep pv nodes</summary> public override void Set(Board board, int nodeType, int bestMove, int score, byte depthAnalyzed, bool exclusion) { long key2 = board.GetKey2(); int startIndex = (int)((long)(((ulong)(exclusion ? board.GetExclusionKey() : board .GetKey())) >> (64 - sizeBits))); // Verifies that is really this board int oldGenerationIndex = -1; // first index of an old generation entry int notPvIndex = -1; // first index of an not PV entry index = -1; for (int i = startIndex; i < startIndex + MAX_PROBES && i < size; i++) { info = infos[i]; // TODO do not replace PVs //if (keys[i] == 0 || (keys[i] == key2 && (getGeneration() != generation || getDepthAnalyzed() <= depthAnalyzed))) { if (keys[i] == 0 || (keys[i] == key2)) { index = i; break; } if (oldGenerationIndex == -1 && GetGeneration() != generation) { oldGenerationIndex = i; } if (notPvIndex == -1 && GetNodeType() != TYPE_EXACT_SCORE) { notPvIndex = i; } } if (index == -1 && oldGenerationIndex != -1) { index = oldGenerationIndex; } if (index == -1 && notPvIndex != -1) { index = notPvIndex; } if (index == -1) { return; } // Do not overwrite unless a PV node // if (nodeType != TYPE_EXACT_SCORE) return; // index = startIndex; keys[index] = key2; info = (bestMove & unchecked((int)(0x1fffff))) | ((nodeType & unchecked((int)(0xf ))) << 21) | (((long)(generation & unchecked((int)(0xff)))) << 32) | (((long)(depthAnalyzed & unchecked((int)(0xff)))) << 40) | (((long)(score & unchecked((int)(0xffff)))) << 48); infos[index] = info; }
/// <summary> /// Given a boards creates a move from a String in uci format or short /// algebraic form /// </summary> /// <param name="board"></param> /// <param name="move"></param> public static int GetFromString(Board board, string move, bool checkLegality) { int fromIndex = 0; int toIndex = 0; int moveType = 0; int pieceMoved = 0; // Ignore checks, captures indicators... move = move.Replace("+", string.Empty).Replace("x", string.Empty).Replace("-", string.Empty ).Replace("=", string.Empty).Replace("#", string.Empty).ReplaceAll(" ", string.Empty ).ReplaceAll("0", "o").ReplaceAll("O", "o"); if ("ooo".Equals(move)) { if (board.GetTurn()) { move = "e1c1"; } else { move = "e8c8"; } } else { if ("oo".Equals(move)) { if (board.GetTurn()) { move = "e1g1"; } else { move = "e8g8"; } } } char promo = move[move.Length - 1]; switch (System.Char.ToLower(promo)) { case 'q': { moveType = TYPE_PROMOTION_QUEEN; break; } case 'n': { moveType = TYPE_PROMOTION_KNIGHT; break; } case 'b': { moveType = TYPE_PROMOTION_BISHOP; break; } case 'r': { moveType = TYPE_PROMOTION_ROOK; break; } } // If promotion, remove the last char if (moveType != 0) { move = Sharpen.Runtime.Substring(move, 0, move.Length - 1); } // To is always the last 2 characters toIndex = BitboardUtils.Algebraic2Index(Sharpen.Runtime.Substring(move, move.Length - 2, move.Length)); long to = unchecked((long)(0x1L)) << toIndex; long from = 0; BitboardAttacks bbAttacks = BitboardAttacks.GetInstance(); switch (move[0]) { case 'N': { // Fills from with a mask of possible from values from = board.knights & board.GetMines() & bbAttacks.knight[toIndex]; break; } case 'K': { from = board.kings & board.GetMines() & bbAttacks.king[toIndex]; break; } case 'R': { from = board.rooks & board.GetMines() & bbAttacks.GetRookAttacks(toIndex, board.GetAll ()); break; } case 'B': { from = board.bishops & board.GetMines() & bbAttacks.GetBishopAttacks(toIndex, board .GetAll()); break; } case 'Q': { from = board.queens & board.GetMines() & (bbAttacks.GetRookAttacks(toIndex, board .GetAll()) | bbAttacks.GetBishopAttacks(toIndex, board.GetAll())); break; } } if (from != 0) { // remove the piece char move = Sharpen.Runtime.Substring(move, 1); } else { // Pawn moves if (move.Length == 2) { if (board.GetTurn()) { from = board.pawns & board.GetMines() & (((long)(((ulong)to) >> 8)) | ((((long)(( (ulong)to) >> 8)) & board.GetAll()) == 0 ? ((long)(((ulong)to) >> 16)) : 0)); } else { from = board.pawns & board.GetMines() & ((to << 8) | (((to << 8) & board.GetAll() ) == 0 ? (to << 16) : 0)); } } if (move.Length == 3) { // Pawn capture from = board.pawns & board.GetMines() & (board.GetTurn() ? bbAttacks.pawnDownwards [toIndex] : bbAttacks.pawnUpwards[toIndex]); } } if (move.Length == 3) { // now disambiaguate char disambiguate = move[0]; int i = "abcdefgh".IndexOf(disambiguate); if (i >= 0) { from &= BitboardUtils.COLUMN[i]; } int j = "12345678".IndexOf(disambiguate); if (j >= 0) { from &= BitboardUtils.RANK[j]; } } // if (BitboardUtils.popCount(from) > 1) { // logger.error("Move NOT disambiaguated:\n"+board.toString() + "\n" + // in); // System.exit(-1); // return -1; // } if (move.Length == 4) { // was algebraic complete e2e4 (=UCI!) from = BitboardUtils.Algebraic2Square(Sharpen.Runtime.Substring(move, 0, 2)); } if (from == 0) { return -1; } // Treats multiple froms, choosing the first Legal Move while (from != 0) { long myFrom = BitboardUtils.Lsb(from); from ^= myFrom; fromIndex = BitboardUtils.Square2Index(myFrom); bool capture = false; if ((myFrom & board.pawns) != 0) { pieceMoved = PAWN; // for passant captures if ((toIndex != (fromIndex - 8)) && (toIndex != (fromIndex + 8)) && (toIndex != ( fromIndex - 16)) && (toIndex != (fromIndex + 16))) { if ((to & board.GetAll()) == 0) { moveType = TYPE_PASSANT; capture = true; } } // later is changed if it was not a pawn // Default promotion to queen if not specified if ((to & (BitboardUtils.b_u | BitboardUtils.b_d)) != 0 && (moveType < TYPE_PROMOTION_QUEEN )) { moveType = TYPE_PROMOTION_QUEEN; } } if ((myFrom & board.bishops) != 0) { pieceMoved = BISHOP; } else { if ((myFrom & board.knights) != 0) { pieceMoved = KNIGHT; } else { if ((myFrom & board.rooks) != 0) { pieceMoved = ROOK; } else { if ((myFrom & board.queens) != 0) { pieceMoved = QUEEN; } else { if ((myFrom & board.kings) != 0) { pieceMoved = KING; // Only if origin square is king's initial square TODO FRC if (fromIndex == 3 || fromIndex == 3 + (8 * 7)) { if (toIndex == (fromIndex + 2)) { moveType = TYPE_QUEENSIDE_CASTLING; } if (toIndex == (fromIndex - 2)) { moveType = TYPE_KINGSIDE_CASTLING; } } } } } } } // Now set captured piece flag if ((to & (board.whites | board.blacks)) != 0) { capture = true; } int moveInt = Move.GenMove(fromIndex, toIndex, pieceMoved, capture, moveType); if (checkLegality && board.DoMove(moveInt, false)) { board.UndoMove(); return moveInt; } else { return moveInt; } } return -1; }
/// <summary>Des not append + or #</summary> /// <param name="board"></param> /// <param name="move"></param> /// <param name="legalMoves"></param> /// <param name="legalMoveCount"></param> /// <returns></returns> public static string ToSan(Board board, int move, int[] legalMoves, int legalMoveCount ) { if (move == 0 || move == -1) { return "none"; } if (Move.GetMoveType(move) == TYPE_KINGSIDE_CASTLING) { return "O-O"; } else { if (Move.GetMoveType(move) == TYPE_QUEENSIDE_CASTLING) { return "O-O-O"; } } StringBuilder sb = new StringBuilder(); if (GetPieceMoved(move) != Move.PAWN) { sb.Append(" PNBRQK"[GetPieceMoved(move)]); } bool disambiguate = false; bool colEqual = false; bool rowEqual = false; for (int i = 0; i < legalMoveCount; i++) { int move2 = legalMoves[i]; if (GetToIndex(move) == GetToIndex(move2) && GetFromIndex(move) != GetFromIndex(move2 ) && GetPieceMoved(move) == GetPieceMoved(move2)) { disambiguate = true; if ((GetFromIndex(move) % 8) == (GetFromIndex(move2) % 8)) { colEqual = true; } if ((GetFromIndex(move) / 8) == (GetFromIndex(move2) / 8)) { rowEqual = true; } } } string fromSq = BitboardUtils.Index2Algebraic(Move.GetFromIndex(move)); if (GetCapture(move) && GetPieceMoved(move) == Move.PAWN) { disambiguate = true; } if (disambiguate) { if (colEqual && rowEqual) { sb.Append(fromSq); } else { if (colEqual && !rowEqual) { sb.Append(fromSq[1]); } else { sb.Append(fromSq[0]); } } } if (GetCapture(move)) { sb.Append("x"); } sb.Append(BitboardUtils.Index2Algebraic(Move.GetToIndex(move))); switch (Move.GetMoveType(move)) { case TYPE_PROMOTION_QUEEN: { sb.Append("Q"); break; } case TYPE_PROMOTION_KNIGHT: { sb.Append("N"); break; } case TYPE_PROMOTION_BISHOP: { sb.Append("B"); break; } case TYPE_PROMOTION_ROOK: { sb.Append("R"); break; } } return sb.ToString(); }
// Values are rotated for whites, so when white is playing is like shown in the code TODO at the moment must be symmetric // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // public override int EvaluateBoard(Board board, int alpha, int beta) { long all = board.GetAll(); int[] materialValue = new int[] { 0, 0 }; int[] pawnMaterialValue = new int[] { 0, 0 }; int[] pcsqValue = new int[] { 0, 0 }; int[] pcsqOpeningValue = new int[] { 0, 0 }; int[] pcsqEndgameValue = new int[] { 0, 0 }; bool[] noQueen = new bool[] { true, true }; long square = 1; byte index = 0; while (square != 0) { bool isWhite = ((board.whites & square) != 0); int color = (isWhite ? 0 : 1); int pcsqIndex = (isWhite ? 63 - index : index); if ((square & all) != 0) { if ((square & board.pawns) != 0) { pawnMaterialValue[color] += PAWN; pcsqValue[color] += pawnSquare[pcsqIndex]; } else { if ((square & board.knights) != 0) { materialValue[color] += KNIGHT; pcsqValue[color] += knightSquare[pcsqIndex]; } else { if ((square & board.bishops) != 0) { materialValue[color] += BISHOP; pcsqValue[color] += bishopSquare[pcsqIndex]; } else { if ((square & board.rooks) != 0) { materialValue[color] += ROOK; pcsqValue[color] += rookSquare[pcsqIndex]; } else { if ((square & board.queens) != 0) { pcsqValue[color] += queenSquare[pcsqIndex]; materialValue[color] += QUEEN; noQueen[color] = false; } else { if ((square & board.kings) != 0) { pcsqOpeningValue[color] += kingSquareOpening[pcsqIndex]; pcsqEndgameValue[color] += kingSquareEndGame[pcsqIndex]; } } } } } } } square <<= 1; index++; } int value = 0; value += pawnMaterialValue[0] - pawnMaterialValue[1]; value += materialValue[0] - materialValue[1]; value += pcsqValue[0] - pcsqValue[1]; // Endgame // 1. Both sides have no queens or // 2. Every side which has a queen has additionally no other pieces or one minorpiece maximum. if ((noQueen[0] || materialValue[0] <= QUEEN + BISHOP) && (noQueen[1] || materialValue [1] <= QUEEN + BISHOP)) { value += pcsqEndgameValue[0] - pcsqEndgameValue[1]; } else { value += pcsqOpeningValue[0] - pcsqOpeningValue[1]; } return value; }
public virtual int GenerateMoves(Board board, int[] moves, int mIndex) { this.moves = moves; bbAttacks = BitboardAttacks.GetInstance(); moveIndex = mIndex; all = board.GetAll(); // only for clearity mines = board.GetMines(); others = board.GetOthers(); byte index = 0; long square = unchecked((long)(0x1L)); while (square != 0) { if (board.GetTurn() == ((square & board.whites) != 0)) { if ((square & board.rooks) != 0) { // Rook GenerateMovesFromAttacks(Move.ROOK, index, bbAttacks.GetRookAttacks(index, all)); } else { if ((square & board.bishops) != 0) { // Bishop GenerateMovesFromAttacks(Move.BISHOP, index, bbAttacks.GetBishopAttacks(index, all )); } else { if ((square & board.queens) != 0) { // Queen GenerateMovesFromAttacks(Move.QUEEN, index, bbAttacks.GetRookAttacks(index, all)); GenerateMovesFromAttacks(Move.QUEEN, index, bbAttacks.GetBishopAttacks(index, all )); } else { if ((square & board.kings) != 0) { // King GenerateMovesFromAttacks(Move.KING, index, bbAttacks.king[index]); } else { if ((square & board.knights) != 0) { // Knight GenerateMovesFromAttacks(Move.KNIGHT, index, bbAttacks.knight[index]); } else { if ((square & board.pawns) != 0) { // Pawns if ((square & board.whites) != 0) { if (((square << 8) & all) == 0) { AddMoves(Move.PAWN, index, index + 8, (square << 8), false, true, 0); // Two squares if it is in he first row if (((square & BitboardUtils.b2_d) != 0) && (((square << 16) & all) == 0)) { AddMoves(Move.PAWN, index, index + 16, (square << 16), false, false, 0); } } GeneratePawnCapturesFromAttacks(index, bbAttacks.pawnUpwards[index], board.GetPassantSquare ()); } else { if ((((long)(((ulong)square) >> 8)) & all) == 0) { AddMoves(Move.PAWN, index, index - 8, ((long)(((ulong)square) >> 8)), false, true , 0); // Two squares if it is in he first row if (((square & BitboardUtils.b2_u) != 0) && ((((long)(((ulong)square) >> 16)) & all ) == 0)) { AddMoves(Move.PAWN, index, index - 16, ((long)(((ulong)square) >> 16)), false, false , 0); } } GeneratePawnCapturesFromAttacks(index, bbAttacks.pawnDownwards[index], board.GetPassantSquare ()); } } } } } } } } square <<= 1; index++; } square = board.kings & mines; // my king byte myKingIndex = unchecked((byte)(-1)); // Castling: disabled when in check or squares attacked if ((((all & (board.GetTurn() ? unchecked((long)(0x06L)) : unchecked((long)(0x0600000000000000L )))) == 0 && (board.GetTurn() ? board.GetWhiteKingsideCastling() : board.GetBlackKingsideCastling ())))) { myKingIndex = BitboardUtils.Square2Index(square); if (!board.GetCheck() && !bbAttacks.IsIndexAttacked(board, unchecked((byte)(myKingIndex - 1)), board.GetTurn()) && !bbAttacks.IsIndexAttacked(board, unchecked((byte)(myKingIndex - 2)), board.GetTurn())) { AddMoves(Move.KING, myKingIndex, myKingIndex - 2, 0, false, false, Move.TYPE_KINGSIDE_CASTLING ); } } if ((((all & (board.GetTurn() ? unchecked((long)(0x70L)) : unchecked((long)(0x7000000000000000L )))) == 0 && (board.GetTurn() ? board.GetWhiteQueensideCastling() : board.GetBlackQueensideCastling ())))) { if (myKingIndex == -1) { myKingIndex = BitboardUtils.Square2Index(square); } if (!board.GetCheck() && !bbAttacks.IsIndexAttacked(board, unchecked((byte)(myKingIndex + 1)), board.GetTurn()) && !bbAttacks.IsIndexAttacked(board, unchecked((byte)(myKingIndex + 2)), board.GetTurn())) { AddMoves(Move.KING, myKingIndex, myKingIndex + 2, 0, false, false, Move.TYPE_QUEENSIDE_CASTLING ); } } return moveIndex; }
/// <summary>Discover attacks to squares using magics: expensive version</summary> public virtual bool IsSquareAttacked(Board board, long square, bool white) { return IsIndexAttacked(board, BitboardUtils.Square2Index(square), white); }
public override bool Search(Board board, bool exclusion) { info = 0; int startIndex = (int)((long)(((ulong)(exclusion ? board.GetExclusionKey() : board .GetKey())) >> (64 - sizeBits))); // Verifies that is really this board for (index = startIndex; index < startIndex + MAX_PROBES && index < size; index++) { if (keys[index] == board.GetKey2()) { info = infos[index]; return true; } } return false; }
// logger.debug("***PAWN"); // printPcsq(pawnIndexValue); // logger.debug("***KNIGHT"); // printPcsq(knightIndexValue); // logger.debug("***BISHOP"); // printPcsq(bishopIndexValue); // logger.debug("***ROOK"); // printPcsq(rookIndexValue); // logger.debug("***QUEEN"); // printPcsq(queenIndexValue); // logger.debug("***KING"); // printPcsq(kingIndexValue); // logger.debug("PCSQ tables generated"); // private static void printPcsq(int pcsq[]) { // StringBuffer sb = new StringBuffer(); // for (int k=0; k<2; k++) { // if (k==0) sb.append("Opening:\n"); // else sb.append("Endgame:\n"); // for (int i = 0; i<64; i++) { // String aux = " " + (k==0 ? o(pcsq[i]) : e(pcsq[i])); // aux = aux.substring(aux.length()-5); // sb.append(aux); // if (i%8 != 7) { // sb.append(","); // } else { // sb.append("\n"); // } // } // } // logger.debug(sb.toString()); // } public override int EvaluateBoard(Board board, int alpha, int beta) { long square = 1; byte index = 0; all = board.GetAll(); superiorPieceAttacked[0] = superiorPieceAttacked[1] = 0; attacksColor[0] = attacksColor[1] = 0; material[0] = material[1] = 0; pawnMaterial[0] = pawnMaterial[1] = 0; center[0] = center[1] = 0; positional[0] = positional[1] = 0; mobility[0] = mobility[1] = 0; attacks[0] = attacks[1] = 0; kingAttackersCount[0] = kingAttackersCount[1] = 0; kingSafety[0] = kingSafety[1] = 0; kingDefense[0] = kingDefense[1] = 0; pawnStructure[0] = pawnStructure[1] = 0; passedPawns[0] = passedPawns[1] = 0; bishopCount[0] = bishopCount[1] = 0; // Squares attackeds by pawns pawnAttacks[0] = ((board.pawns & board.whites & ~BitboardUtils.b_l) << 9) | ((board .pawns & board.whites & ~BitboardUtils.b_r) << 7); pawnAttacks[1] = ((long)(((ulong)(board.pawns & board.blacks & ~BitboardUtils.b_r )) >> 9)) | ((long)(((ulong)(board.pawns & board.blacks & ~BitboardUtils.b_l)) >> 7)); // Square that pawn attacks or can attack by advancing pawnCanAttack[0] = pawnAttacks[0] | pawnAttacks[0] << 8 | pawnAttacks[0] << 16 | pawnAttacks[0] << 24 | pawnAttacks[0] << 32 | pawnAttacks[0] << 40; pawnCanAttack[1] = pawnAttacks[1] | (long)(((ulong)pawnAttacks[1]) >> 8) | (long) (((ulong)pawnAttacks[1]) >> 16) | (long)(((ulong)pawnAttacks[1]) >> 24) | (long) (((ulong)pawnAttacks[1]) >> 32) | (long)(((ulong)pawnAttacks[1]) >> 40); // Squares surrounding King squaresNearKing[0] = bbAttacks.king[BitboardUtils.Square2Index(board.whites & board .kings)] | board.whites & board.kings; squaresNearKing[1] = bbAttacks.king[BitboardUtils.Square2Index(board.blacks & board .kings)] | board.blacks & board.kings; minorPiecesDefendedByPawns[0] = board.whites & (board.bishops | board.knights) & pawnAttacks[0]; minorPiecesDefendedByPawns[1] = board.blacks & (board.bishops | board.knights) & pawnAttacks[1]; // first build attacks info square = 1; for (index = 0; ((sbyte)index) < 64; index++) { if ((square & all) != 0) { bool isWhite = ((board.whites & square) != 0); int color = (isWhite ? 0 : 1); if ((square & board.pawns) != 0) { pieceAttacks = (isWhite ? bbAttacks.pawnUpwards[index] : bbAttacks.pawnDownwards[ index]); } else { if ((square & board.knights) != 0) { pieceAttacks = bbAttacks.knight[index]; } else { if ((square & board.bishops) != 0) { pieceAttacks = bbAttacks.GetBishopAttacks(index, all); } else { if ((square & board.rooks) != 0) { pieceAttacks = bbAttacks.GetRookAttacks(index, all); } else { if ((square & board.queens) != 0) { pieceAttacks = bbAttacks.GetRookAttacks(index, all) | bbAttacks.GetBishopAttacks( index, all); } else { if ((square & board.kings) != 0) { pieceAttacks = bbAttacks.king[index]; } else { pieceAttacks = 0; } } } } } } attacksColor[color] |= pieceAttacks; attacksSquare[index] = pieceAttacks; } square <<= 1; } // Ok, ended initialization square = 1; index = 0; while (square != 0) { if ((square & all) != 0) { bool isWhite = ((board.whites & square) != 0); int color = (isWhite ? 0 : 1); long mines = (isWhite ? board.whites : board.blacks); long others = (isWhite ? board.blacks : board.whites); long otherPawnAttacks = (isWhite ? pawnAttacks[1] : pawnAttacks[0]); int pcsqIndex = (isWhite ? index : 63 - index); int rank = index >> 3; int column = 7 - index & 7; pieceAttacks = attacksSquare[index]; if ((square & board.pawns) != 0) { pawnMaterial[color] += PAWN; center[color] += pawnIndexValue[pcsqIndex]; if ((pieceAttacks & squaresNearKing[1 - color] & ~otherPawnAttacks) != 0) { kingSafety[color] += PAWN_ATTACKS_KING; } // TODO: if two pawns attacks the same square, add only once if ((pieceAttacks & board.knights & others) != 0) { attacks[color] += PAWN_ATTACKS_KNIGHT; } if ((pieceAttacks & board.bishops & others) != 0) { attacks[color] += PAWN_ATTACKS_BISHOP; } if ((pieceAttacks & board.rooks & others) != 0) { attacks[color] += PAWN_ATTACKS_ROOK; } if ((pieceAttacks & board.queens & others) != 0) { attacks[color] += PAWN_ATTACKS_QUEEN; } superiorPieceAttacked[color] |= pieceAttacks & others & (board.knights | board.bishops | board.rooks | board.queens); bool isolated = (BitboardUtils.COLUMNS_ADJACENTS[column] & board.pawns & mines) == 0; bool doubled = (BitboardUtils.COLUMN[column] & BitboardUtils.RANKS_FORWARD[color] [rank] & board.pawns & mines) != 0; // boolean backwards = ((BitboardUtils.COLUMN[column] | BitboardUtils.COLUMNS_ADJACENTS[column]) & ~BitboardUtils.RANKS_FORWARD[color][rank] & board.pawns & mines) == 0; // boolean weak = !isolated && (pawnAttacks[color] & square) == 0 // && pcsqIndex >= 24; // // not defended is weak // if (weak) { // // Can be defended advancing one pawn // auxLong = (isWhite ? BitboardAttacks.pawnDownwards[color] : BitboardAttacks.pawnUpwards[color]) & ~otherPawnAttacks & ~all; // while (auxLong != 0) { // Not attacked by other pawn and empty // auxLong2 = BitboardUtils.lsb(auxLong); // auxLong &= ~auxLong2; // auxLong2 = isWhite ? auxLong2 >>> 8 : auxLong2 << 8; // if ((auxLong2 & mines & board.pawns) !=0) { // weak = false; // } else { // Defended advancing one pawn two squares // if ((auxLong2 & all) == 0) { // empty square // auxLong2 = (isWhite ? auxLong2 >>> 8 : auxLong2 << 8); // if (((isWhite ? BitboardUtils.RANK[1] : BitboardUtils.RANK[6]) & auxLong2 & board.pawns & mines) != 0) { // weak = false; // } // } // } // } // // if (weak) { // // Can advance to be supported // auxLong = (isWhite ? square << 8 : square >>> 8) & ~otherPawnAttacks & ~all; // if (auxLong != 0) { // if ((auxLong & pawnAttacks[color]) != 0) { // weak = false; // } else { // // Checks advancing two squares if in initial position // if (((isWhite ? BitboardUtils.RANK[1] : BitboardUtils.RANK[6]) & square) != 0) { // auxLong = (isWhite ? square << 16 : square >>> 16) & ~otherPawnAttacks & ~all; // if ((auxLong & pawnAttacks[color]) != 0) weak = false; // } // } // } // } // } // if (weak) pawnStructure[color] += PAWN_WEAK; //// if (weak) { //// System.out.println("weak pawn: \n" + board.toString()); //// System.out.println("square: \n" + BitboardUtils.toString(square)); //// } // // No pawns in front if ((BitboardUtils.COLUMN[column] & BitboardUtils.RANKS_FORWARD[color][rank] & board .pawns) == 0) { if (doubled) { pawnStructure[color] += PAWN_NO_FRONT_DOUBLED; if (isolated) { pawnStructure[color] += PAWN_NO_FRONT_DOUB_ISO; } } else { if (isolated) { pawnStructure[color] += PAWN_NO_FRONT_ISOLATED; } } } else { // pawns in front if (doubled) { pawnStructure[color] += PAWN_FRONT_DOUBLED; if (isolated) { pawnStructure[color] += PAWN_FRONT_DOUB_ISO; } } else { if (isolated) { pawnStructure[color] += PAWN_FRONT_ISOLATED; } } } // Backwards pawns and advance squares attacked by opposite pawns (TODO only three) // if (backwards && (BitboardUtils.COLUMN[column] & BitboardUtils.RANKS_FORWARD[color][rank] & otherPawnAttacks) !=0) // pawnStructure[color] += PAWN_BACKWARDS; // Passed Pawns if (((BitboardUtils.COLUMN[column] | BitboardUtils.COLUMNS_ADJACENTS[column]) & BitboardUtils .RANKS_FORWARD[color][rank] & board.pawns & others) == 0) { // Static part passedPawns[color] += PAWN_PASSER[(isWhite ? rank : 7 - rank)]; if ((square & pawnAttacks[color]) != 0) { passedPawns[color] += PAWN_PASSER_PROTECTED[(isWhite ? rank : 7 - rank)]; } if ((BitboardUtils.ROWS_LEFT[column] & board.pawns & others) == 0 && (BitboardUtils .ROWS_RIGHT[column] & board.pawns & others) == 0) { passedPawns[color] += PAWN_PASSER_OUTSIDE[(isWhite ? rank : 7 - rank)]; } // Dynamic part auxLong = BitboardUtils.COLUMN[column] & BitboardUtils.RANKS_FORWARD[color][rank]; if ((auxLong & mines) == 0) { passedPawns[color] += PAWN_PASSER_NO_MINES[(isWhite ? rank : 7 - rank)]; } if ((auxLong & others) == 0) { passedPawns[color] += PAWN_PASSER_NO_OTHERS[(isWhite ? rank : 7 - rank)]; } if (((isWhite ? square << 8 : (long)(((ulong)square) >> 8)) & others) == 0) { passedPawns[color] += PAWN_PASSER_MOBILE[(isWhite ? rank : 7 - rank)]; } if ((auxLong & ~attacksColor[color] & attacksColor[1 - color]) == 0) { passedPawns[color] += PAWN_PASSER_RUNNER[(isWhite ? rank : 7 - rank)]; } if ((BitboardUtils.COLUMN[column] & BitboardUtils.RANKS_BACKWARD[color][rank] & board .rooks & mines) != 0) { passedPawns[color] += PAWN_PASSER_ROOK_BEHIND[(isWhite ? rank : 7 - rank)]; } } else { // Candidates is the same check but removing opposite pawns attacking our square if (((BitboardUtils.COLUMN[column] | BitboardUtils.COLUMNS_ADJACENTS[column]) & BitboardUtils .RANKS_FORWARD[color][rank] & (isWhite ? bbAttacks.pawnUpwards[index] : bbAttacks .pawnDownwards[index]) & board.pawns & others) == 0) { passedPawns[color] += PAWN_CANDIDATE[(isWhite ? rank : 7 - rank)]; } } } else { if ((square & board.knights) != 0) { material[color] += KNIGHT; center[color] += knightIndexValue[pcsqIndex]; // Only mobility forward mobility[color] += KNIGHT_M * BitboardUtils.PopCount(pieceAttacks & ~mines & ~otherPawnAttacks & BitboardUtils.RANKS_FORWARD[color][rank]); if ((pieceAttacks & squaresNearKing[1 - color] & ~otherPawnAttacks) != 0) { kingSafety[color] += KNIGHT_ATTACKS_KING; kingAttackersCount[color]++; } if ((pieceAttacks & squaresNearKing[color]) != 0) { kingDefense[color] += KNIGHT_DEFENDS_KING; } if ((pieceAttacks & board.pawns & others & ~otherPawnAttacks) != 0) { attacks[color] += KNIGHT_ATTACKS_PU_P; } if ((pieceAttacks & board.bishops & others & ~otherPawnAttacks) != 0) { attacks[color] += KNIGHT_ATTACKS_PU_B; } if ((pieceAttacks & (board.rooks | board.queens) & others) != 0) { attacks[color] += KNIGHT_ATTACKS_RQ; } superiorPieceAttacked[color] |= pieceAttacks & others & (board.rooks | board.queens ); // Knight Outpost: no opposite pawns can attack the square if ((square & OUTPOST_MASK[color] & ~pawnCanAttack[1 - color]) != 0) { positional[color] += KNIGHT_OUTPOST; // Defended by one of our pawns if ((square & pawnAttacks[color]) != 0) { positional[color] += KNIGHT_OUTPOST; // Attacks squares near king or other pieces pawn undefended if ((pieceAttacks & (squaresNearKing[1 - color] | others) & ~otherPawnAttacks) != 0) { positional[color] += KNIGHT_OUTPOST_ATTACKS_NK_PU[pcsqIndex]; } } } } else { if ((square & board.bishops) != 0) { material[color] += BISHOP; if (bishopCount[color]++ == 2) { material[color] += BISHOP_PAIR; } center[color] += bishopIndexValue[pcsqIndex]; mobility[color] += BISHOP_M * BitboardUtils.PopCount(pieceAttacks & ~mines & ~otherPawnAttacks & BitboardUtils.RANKS_FORWARD[color][rank]); if ((pieceAttacks & squaresNearKing[1 - color] & ~otherPawnAttacks) != 0) { kingSafety[color] += BISHOP_ATTACKS_KING; kingAttackersCount[color]++; } if ((pieceAttacks & squaresNearKing[color]) != 0) { kingDefense[color] += BISHOP_DEFENDS_KING; } if ((pieceAttacks & board.pawns & others & ~otherPawnAttacks) != 0) { attacks[color] += BISHOP_ATTACKS_PU_P; } if ((pieceAttacks & board.knights & others & ~otherPawnAttacks) != 0) { attacks[color] += BISHOP_ATTACKS_PU_K; } if ((pieceAttacks & (board.rooks | board.queens) & others) != 0) { attacks[color] += BISHOP_ATTACKS_RQ; } superiorPieceAttacked[color] |= pieceAttacks & others & (board.rooks | board.queens ); pieceAttacksXray = bbAttacks.GetBishopAttacks(index, all & ~(pieceAttacks & others )) & ~pieceAttacks; if ((pieceAttacksXray & (board.rooks | board.queens | board.kings) & others) != 0) { attacks[color] += PINNED_PIECE; } // Bishop Outpost: no opposite pawns can attack the square and defended by one of our pawns if ((square & OUTPOST_MASK[color] & ~pawnCanAttack[1 - color] & pawnAttacks[color ]) != 0) { positional[color] += BISHOP_OUTPOST; // Attacks squares near king or other pieces pawn undefended if ((pieceAttacks & (squaresNearKing[1 - color] | others) & ~otherPawnAttacks) != 0) { positional[color] += BISHOP_OUTPOST_ATT_NK_PU; } } // Pawns in our color if ((square & BitboardUtils.WHITE_SQUARES) != 0) { auxLong = BitboardUtils.WHITE_SQUARES; } else { auxLong = BitboardUtils.BLACK_SQUARES; } positional[color] += ((int)(((uint)BitboardUtils.PopCount(auxLong & board.pawns & mines) + BitboardUtils.PopCount(auxLong & board.pawns & mines)) >> 1)) * BISHOP_PAWN_IN_COLOR; positional[color] += ((int)(((uint)BitboardUtils.PopCount(auxLong & board.pawns & others & BitboardUtils.RANKS_FORWARD[color][rank])) >> 1)) * BISHOP_FORWARD_P_PU; if ((BISHOP_TRAPPING[index] & board.pawns & others) != 0) { mobility[color] += BISHOP_TRAPPED; } } else { // TODO protection if ((square & board.rooks) != 0) { material[color] += ROOK; center[color] += rookIndexValue[pcsqIndex]; mobility[color] += ROOK_M * BitboardUtils.PopCount(pieceAttacks & ~mines & ~otherPawnAttacks ); if ((pieceAttacks & squaresNearKing[1 - color] & ~otherPawnAttacks) != 0) { kingSafety[color] += ROOK_ATTACKS_KING; kingAttackersCount[color]++; } if ((pieceAttacks & squaresNearKing[color]) != 0) { kingDefense[color] += ROOK_DEFENDS_KING; } if ((pieceAttacks & board.pawns & others & ~otherPawnAttacks) != 0) { attacks[color] += ROOK_ATTACKS_PU_P; } if ((pieceAttacks & (board.bishops | board.knights) & others & ~otherPawnAttacks) != 0) { attacks[color] += ROOK_ATTACKS_PU_BK; } if ((pieceAttacks & board.queens & others) != 0) { attacks[color] += ROOK_ATTACKS_Q; } superiorPieceAttacked[color] |= pieceAttacks & others & board.queens; pieceAttacksXray = bbAttacks.GetRookAttacks(index, all & ~(pieceAttacks & others) ) & ~pieceAttacks; if ((pieceAttacksXray & (board.queens | board.kings) & others) != 0) { attacks[color] += PINNED_PIECE; } auxLong = (isWhite ? BitboardUtils.b_u : BitboardUtils.b_d); if ((square & auxLong) != 0 && (others & board.kings & auxLong) != 0) { positional[color] += ROOK_8_KING_8; } if ((square & (isWhite ? BitboardUtils.r2_u : BitboardUtils.r2_d)) != 0 & (others & (board.kings | board.pawns) & (isWhite ? BitboardUtils.b2_u : BitboardUtils.b2_d )) != 0) { positional[color] += ROOK_7_KP_78; if ((others & board.kings & auxLong) != 0 && (pieceAttacks & others & (board.queens | board.rooks) & (isWhite ? BitboardUtils.r2_u : BitboardUtils.r2_d)) != 0) { positional[color] += ROOK_7_P_78_K_8_RQ_7; } } if ((square & (isWhite ? BitboardUtils.r3_u : BitboardUtils.r3_d)) != 0 & (others & (board.kings | board.pawns) & (isWhite ? BitboardUtils.b3_u : BitboardUtils.b3_d )) != 0) { positional[color] += ROOK_6_KP_678; } auxLong = BitboardUtils.COLUMN[column] & BitboardUtils.RANKS_FORWARD[color][rank]; if ((auxLong & board.pawns & mines) == 0) { positional[color] += ROOK_COLUMN_SEMIOPEN; if ((auxLong & board.pawns) == 0) { if ((auxLong & minorPiecesDefendedByPawns[1 - color]) == 0) { positional[color] += ROOK_COLUMN_OPEN_NO_MG; } else { if ((auxLong & minorPiecesDefendedByPawns[1 - color] & pawnCanAttack[color]) == 0) { positional[color] += ROOK_COLUMN_OPEN_MG_NP; } else { positional[color] += ROOK_COLUMN_OPEN_MG_P; } } } else { // There is an opposite backward pawn if ((auxLong & board.pawns & others & pawnCanAttack[1 - color]) == 0) { positional[color] += ROOK_COLUMN_SEMIOPEN_BP; } } if ((auxLong & board.kings & others) != 0) { positional[color] += ROOK_COLUMN_SEMIOPEN_K; } } // Rook Outpost: no opposite pawns can attack the square and defended by one of our pawns if ((square & OUTPOST_MASK[color] & ~pawnCanAttack[1 - color] & pawnAttacks[color ]) != 0) { positional[color] += ROOK_OUTPOST; // Attacks squares near king or other pieces pawn undefended if ((pieceAttacks & (squaresNearKing[1 - color] | others) & ~otherPawnAttacks) != 0) { positional[color] += ROOK_OUTPOST_ATT_NK_PU; } } } else { if ((square & board.queens) != 0) { material[color] += QUEEN; center[color] += queenIndexValue[pcsqIndex]; mobility[color] += QUEEN_M * BitboardUtils.PopCount(pieceAttacks & ~mines & ~otherPawnAttacks ); if ((pieceAttacks & squaresNearKing[1 - color] & ~otherPawnAttacks) != 0) { kingSafety[color] += QUEEN_ATTACKS_KING; kingAttackersCount[color]++; } if ((pieceAttacks & squaresNearKing[color]) != 0) { kingDefense[color] += QUEEN_DEFENDS_KING; } if ((pieceAttacks & others & ~otherPawnAttacks) != 0) { attacks[color] += QUEEN_ATTACKS_PU; } pieceAttacksXray = (bbAttacks.GetRookAttacks(index, all & ~(pieceAttacks & others )) | bbAttacks.GetBishopAttacks(index, all & ~(pieceAttacks & others))) & ~pieceAttacks; if ((pieceAttacksXray & board.kings & others) != 0) { attacks[color] += PINNED_PIECE; } auxLong = (isWhite ? BitboardUtils.b_u : BitboardUtils.b_d); auxLong2 = (isWhite ? BitboardUtils.r2_u : BitboardUtils.r2_d); if ((square & auxLong2) != 0 && (others & (board.kings | board.pawns) & (auxLong | auxLong2)) != 0) { attacks[color] += QUEEN_7_KP_78; if ((board.rooks & mines & auxLong2 & pieceAttacks) != 0 && (board.kings & others & auxLong) != 0) { positional[color] += QUEEN_7_P_78_K_8_R_7; } } } else { if ((square & board.kings) != 0) { center[color] += kingIndexValue[pcsqIndex]; // If king is in the first rank, we add the pawn shield if ((square & (isWhite ? BitboardUtils.RANK[0] : BitboardUtils.RANK[7])) != 0) { kingDefense[color] += KING_PAWN_SHIELD * BitboardUtils.PopCount(pieceAttacks & mines & board.pawns); } } } } } } } } square <<= 1; index++; } // Ponder opening and Endgame value depending of the non-pawn pieces: // opening=> gamephase = 255 / ending => gamephase ~= 0 int gamePhase = ((material[0] + material[1]) << 8) / 5000; if (gamePhase > 256) { gamePhase = 256; } // Security int value = 0; // First Material value += pawnMaterial[0] - pawnMaterial[1] + material[0] - material[1]; // Tempo value += (board.GetTurn() ? TEMPO : -TEMPO); int oe = config.GetEvalCenter() * (center[0] - center[1]) + config.GetEvalPositional () * (positional[0] - positional[1]) + config.GetEvalAttacks() * (attacks[0] - attacks [1]) + config.GetEvalMobility() * (mobility[0] - mobility[1]) + config.GetEvalPawnStructure () * (pawnStructure[0] - pawnStructure[1]) + config.GetEvalPassedPawns() * (passedPawns [0] - passedPawns[1]) + config.GetEvalKingSafety() * (kingDefense[0] - kingDefense [1]) + config.GetEvalKingSafety() * (KING_SAFETY_PONDER[kingAttackersCount[0]] * kingSafety[0] - KING_SAFETY_PONDER[kingAttackersCount[1]] * kingSafety[1]) + config .GetEvalAttacks() * ((BitboardUtils.PopCount(superiorPieceAttacked[0]) >= 2 ? HUNG_PIECES : 0) - (BitboardUtils.PopCount(superiorPieceAttacked[1]) >= 2 ? HUNG_PIECES : 0 )); value += (gamePhase * O(oe)) / (256 * 100); // divide by 256 value += ((256 - gamePhase) * E(oe)) / (256 * 100); if (debug) { logger.Debug("\n" + board.ToString()); logger.Debug(board.GetFen()); logger.Debug("materialValue = " + (material[0] - material[1])); logger.Debug("pawnMaterialValue = " + (pawnMaterial[0] - pawnMaterial[1])); logger.Debug("centerOpening = " + O(center[0] - center[1])); logger.Debug("centerEndgame = " + E(center[0] - center[1])); logger.Debug("positionalOpening = " + O(positional[0] - positional[1])); logger.Debug("positionalEndgame = " + E(positional[0] - positional[1])); logger.Debug("attacksO = " + O(attacks[0] - attacks[1])); logger.Debug("attacksE = " + E(attacks[0] - attacks[1])); logger.Debug("mobilityO = " + O(mobility[0] - mobility[1])); logger.Debug("mobilityE = " + E(mobility[0] - mobility[1])); logger.Debug("pawnsO = " + O(pawnStructure[0] - pawnStructure[1]) ); logger.Debug("pawnsE = " + E(pawnStructure[0] - pawnStructure[1]) ); logger.Debug("passedPawnsO = " + O(passedPawns[0] - passedPawns[1])); logger.Debug("passedPawnsE = " + E(passedPawns[0] - passedPawns[1])); logger.Debug("kingSafetyValueO = " + O(KING_SAFETY_PONDER[kingAttackersCount [0]] * kingSafety[0] - KING_SAFETY_PONDER[kingAttackersCount[1]] * kingSafety[1] )); logger.Debug("kingSafetyValueE = " + E(KING_SAFETY_PONDER[kingAttackersCount [0]] * kingSafety[0] - KING_SAFETY_PONDER[kingAttackersCount[1]] * kingSafety[1] )); logger.Debug("kingDefenseO = " + O(kingDefense[0] - kingDefense[1])); logger.Debug("kingDefenseE = " + E(kingDefense[0] - kingDefense[1])); logger.Debug("HungPiecesO = " + O((BitboardUtils.PopCount(superiorPieceAttacked [0]) >= 2 ? HUNG_PIECES : 0) - (BitboardUtils.PopCount(superiorPieceAttacked[1]) >= 2 ? HUNG_PIECES : 0))); logger.Debug("HungPiecesE = " + O((BitboardUtils.PopCount(superiorPieceAttacked [0]) >= 2 ? HUNG_PIECES : 0) - (BitboardUtils.PopCount(superiorPieceAttacked[1]) >= 2 ? HUNG_PIECES : 0))); logger.Debug("gamePhase = " + gamePhase); logger.Debug("tempo = " + (board.GetTurn() ? TEMPO : -TEMPO)); logger.Debug("value = " + value); } return value; }
/// <summary>Discover attacks to squares using magics: cheap version</summary> public virtual long GetIndexAttacks(Board board, int index) { if (index < 0 || index > 63) { return 0; } long all = board.GetAll(); return ((board.blacks & pawnUpwards[index] | board.whites & pawnDownwards[index]) & board.pawns) | (king[index] & board.kings) | (knight[index] & board.knights) | (GetRookAttacks(index, all) & (board.rooks | board.queens)) | (GetBishopAttacks (index, all) & (board.bishops | board.queens)); }
/// <summary>Board evaluator</summary> public abstract int EvaluateBoard(Board board, int alpha, int beta);
/// <summary>Discover attacks to squares using magics: cheap version</summary> public virtual bool IsIndexAttacked(Board board, byte index, bool white) { if (((sbyte)index) < 0 || index > 63) { return false; } long others = (white ? board.blacks : board.whites); long all = board.GetAll(); if (((white ? pawnUpwards[index] : pawnDownwards[index]) & board.pawns & others) != 0) { return true; } else { if ((king[index] & board.kings & others) != 0) { return true; } else { if ((knight[index] & board.knights & others) != 0) { return true; } else { if ((GetRookAttacks(index, all) & (board.rooks | board.queens) & others) != 0) { return true; } else { if ((GetBishopAttacks(index, all) & (board.bishops | board.queens) & others) != 0) { return true; } } } } } return false; }
/// <summary>Returns true if key matches with key stored</summary> public abstract bool Search(Board board, bool exclusion);
public virtual string GetPgn(Board b, string whiteName, string blackName) { return GetPgn(b, whiteName, blackName, null, null, null); }
public abstract void Set(Board board, int nodeType, int bestMove, int score, byte depthAnalyzed, bool exclusion);
// parses a PGN and does all moves public virtual void SetBoard(Board b, string pgn) { ParsePgn(pgn); b.SetFen(fenStartPosition); foreach (string moveString in moves) { if ("*".Equals(moveString)) { break; } int move = Move.GetFromString(b, moveString, true); if (move == 0 || move == -1) { logger.Error("Move not Parsed: " + moveString); break; } if (!b.DoMove(move)) { logger.Error("Doing move=" + moveString + " " + Move.ToStringExt(move) + " " + b. GetTurn()); break; } } }
private int LastCapturedPieceValue(Board board) { return PieceValue(board.GetLastCapturedPiece()); }