public static void DrawBoard(Position inputBoard) { for (int i = 0; i < 6; i++) { if (i == 0) { Console.WriteLine("┌───┬───┬───┬───┬───┬───┬───┐"); } else if (i >= 1) { Console.WriteLine("├───┼───┼───┼───┼───┼───┼───┤"); } for (int j = 0; j < 7; j++) { int shiftNumber = 5 - i + (7*j); String piece; if ((0x1UL << shiftNumber & inputBoard.arrayOfBitboard[0]) != 0) { piece = "O"; } else if ((0x1UL << shiftNumber & inputBoard.arrayOfBitboard[1]) != 0) { piece = "X"; } else { piece = " "; } Console.Write("│ " + piece + " "); } Console.WriteLine("│"); } Console.WriteLine("└───┴───┴───┴───┴───┴───┴───┘"); Console.WriteLine(" 1 2 3 4 5 6 7"); Console.WriteLine(""); Console.WriteLine("Key: " + inputBoard.key); Console.WriteLine(""); }
public static UInt64 perft(int depth, Position inputBoard) { UInt64 nodes = 0; if (inputBoard.HasWon(inputBoard.arrayOfBitboard[(inputBoard.nPlies-1) & 1]) || inputBoard.nPlies == 42) { return 1; } else if (depth == 1) { for (int i = 0; i < 7; i++) { if (inputBoard.height[i] - 7 * i <= 5) { nodes++; } } return nodes; } for (int i = 0; i < 7; i++) { if (inputBoard.height[i] - 7 * i <= 5) { inputBoard.MakeMove(inputBoard.height[i]); nodes += perft(depth - 1, inputBoard); inputBoard.UnmakeMove(); } } return nodes; }
public static int solve(int nodeType, Position inputBoard, int ply, int alpha, int beta, int depth) { // return score for terminal state if (inputBoard.HasWon(inputBoard.arrayOfBitboard[(inputBoard.nPlies - 1) & 1])) { return -Constants.WIN + ply; } else if (inputBoard.nPlies == 42) { Debug.Assert(depth == 0); return Constants.DRAW; } // "Mate" distance pruning //if (nodeType != Constants.ROOT) { alpha = Math.Max(ply-Constants.WIN, alpha); beta = Math.Min(Constants.WIN - (ply + 1), beta); if (alpha >= beta) { return alpha; } //} // probe transposition table TTEntry entry = Solve.TranspositionTable.probeTTable(inputBoard.key); // If entry has a flag type, then key will match (probe function performs check), only empty entries will have a key that doesn't match if (entry.flag == Constants.EXACT || entry.flag == Constants.L_BOUND && entry.evaluationScore >= beta || entry.flag == Constants.U_BOUND && entry.evaluationScore <= alpha) { Debug.Assert(entry.key == inputBoard.key && entry.depth == depth); // Only exact and lower bound entries can satisfy this condition and they all have valid moves stored, so don't have to check if move == -1 (only the case with upper bound entries) if (entry.evaluationScore >= beta) { Debug.Assert(entry.move != Constants.NO_MOVE); updateKillers(entry.move, ply); } return entry.evaluationScore; } // hash move, if entry is exact then code will not be reached and if entry is an upper bound then it will have no move int hashMove = (entry.flag == Constants.L_BOUND && entry.evaluationScore < beta) ? entry.move : Constants.NO_MOVE; int bestScore = -Constants.INF; int movesMade = 0; bool raisedAlpha = false; movePicker mPicker = new movePicker(inputBoard, ply, hashMove); int bestMove = Constants.NO_MOVE; // loop through all moves while (true) { int move = mPicker.getNextMove(); if (move == Constants.NO_MOVE) { break; } inputBoard.MakeMove(move); int score = -solve(Constants.NON_ROOT, inputBoard, ply + 1, -beta, -alpha, depth - 1); inputBoard.UnmakeMove(); nodesVisited++; movesMade++; if (score >= beta) { TTEntry newEntry = new TTEntry(inputBoard.key, Constants.L_BOUND, depth, score, move); Solve.TranspositionTable.storeTTable(inputBoard.key, newEntry); updateKillers(move, ply); updateHistory(depth, ply, move); if (movesMade == 1) { fh1++; } else { fh++; } return score; } else if (score > bestScore) { bestScore = score; bestMove = move; if (score > alpha) { alpha = score; raisedAlpha = true; } } } // Store in transposition table if (raisedAlpha) { TTEntry newEntry = new TTEntry(inputBoard.key, Constants.EXACT, depth, alpha, bestMove); Solve.TranspositionTable.storeTTable(inputBoard.key, newEntry); } else { TTEntry newEntry = new TTEntry(inputBoard.key, Constants.U_BOUND, depth, bestScore, Constants.NO_MOVE); // no best move Solve.TranspositionTable.storeTTable(inputBoard.key, newEntry); } return bestScore; }
public static void PerftTest() { for (int i = 1; i < 14; i++) { Position test = new Position(""); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); UInt64 nodeCount = Constants.perft(i, test); stopwatch.Stop(); Console.WriteLine("Depth: " + i + "\t\tNodes: " + nodeCount.ToString("#,##0") + "\t\tTime: " + stopwatch.ElapsedMilliseconds.ToString("#,##0") + "\t\tNPS: " + (nodeCount/((UInt64)stopwatch.ElapsedMilliseconds+1)*1000).ToString("#,##0")); } }
public movePicker(Position inputBoard, int ply, int hashMove) { board = inputBoard; this.ply = ply; this.hashMove = hashMove; moveList = this.moveGenerator(); }