public static int Heuristic(ulong board, bool max_for_white, List <ulong> possible_moves = null) { if (!Board.IsPlacementPhase(board)) { if (Board.IsWhiteTurn(board) && Board.WhitePiecesOnBoard(board) < 3) { if (max_for_white) { return(-1000); } else { return(1000); } } else if (!Board.IsWhiteTurn(board) && Board.BlackPiecesOnBoard(board) < 3) { if (max_for_white) { return(1000); } else { return(-1000); } } } if (possible_moves == null) { possible_moves = Board.GetMoves(board); } if (possible_moves.Count == 0) { if (Board.IsWhiteTurn(board)) { if (max_for_white) { return(-1000); } else { return(1000); } } else { if (max_for_white) { return(1000); } else { return(-1000); } } } /* We score +1 for a move, +2 if it forms a mill */ int score = 0; var old_runs = Board.GetRunPieces(board); foreach (var move in possible_moves) { var new_runs = Board.GetRunPieces(move); if (new_runs != old_runs && Board.CountBits(new_runs) >= Board.CountBits(old_runs)) { score += 5; } else { score++; } } if (Board.IsWhiteTurn(board)) { if (max_for_white) { return(score); } else { return(-score); } } else { if (max_for_white) { return(-score); } else { return(score); } } }
int alphabeta(ulong board, int depth, int alpha, int beta, bool maximizingPlayer, out ulong move) { if (cache_v[depth].TryGetValue(board, out var cached)) { move = cache_move[depth][board]; return(cached); } var children = Board.GetMoves(board); if (depth == 0 || Board.CurrentPlayerHasLessThanThree(board) || children.Count == 0) { move = 0UL; return(Heuristic(board, IsWhite, children)); } if (maximizingPlayer) { var bestValue = int.MinValue; ulong best_move = 0UL; foreach (var child in children) { var v = alphabeta(child, depth - 1, alpha, beta, false, out var unused); if (v > bestValue) { if (v > alpha) { alpha = v; } bestValue = v; best_move = child; } if (beta <= alpha) { break; } } move = best_move; cache_v[depth][board] = bestValue; cache_move[depth][board] = move; return(bestValue); } else { // minimizing player var bestValue = int.MaxValue; ulong best_move = 0UL; foreach (var child in children) { var v = alphabeta(child, depth - 1, alpha, beta, true, out var unused); if (v < bestValue) { if (v < beta) { beta = v; } bestValue = v; best_move = child; } if (beta <= alpha) { break; } } move = best_move; cache_v[depth][board] = bestValue; cache_move[depth][board] = move; return(bestValue); } }