public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { if (_useOpeningBook) { if (maxSeconds <= _book.Seconds) { var bookMove = _book.GetMove(state.Transcript); if (bookMove >= 0) { return(new SearchResult { BestMove = bookMove }); } } } timer = Stopwatch.StartNew(); statusUpdate = Stopwatch.StartNew(); visitedNodes = 0; simulationCount = 0; cancel = new EngineCancellationToken(() => token.Cancelled || timer.ElapsedMilliseconds >= maxSeconds * 1000L - bufferMilliseconds); int best = MonteCarloTreeSearch(state); return(new SearchResult { BestMove = best, Evaluations = visitedNodes, Simulations = simulationCount, Milliseconds = timer.ElapsedMilliseconds }); }
public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { timer = Stopwatch.StartNew(); evaluations = 0; SearchResult result = new SearchResult(); result.Score = int.MinValue; Player player = state.Player; // Get a list of all possible moves, randomly shuffled List <int> moves = Shuffle(state.GetMoves()); foreach (int move in moves) { Board copy = new Board(state); copy.MakeMove(move); var eval = EvaluateLongestPath(copy, player, move); if (eval > result.Score) { result.BestMove = move; result.Score = eval; } } result.Evaluations = evaluations; result.Milliseconds = timer.ElapsedMilliseconds; return(result); }
public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { List <int> moves = state.GetMoves(); return(new SearchResult { BestMove = moves[_random.Next(moves.Count)] }); }
public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { Stopwatch timer = Stopwatch.StartNew(); evaluations = 0; SearchResult result = AlphaBetaSearch(state, searchDepth, int.MinValue, int.MaxValue); result.Evaluations = evaluations; result.Milliseconds = timer.ElapsedMilliseconds; return(result); }
public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { Stopwatch timer = Stopwatch.StartNew(); evaluations = 0; cancellationToken = token; var result = MonteCarlo(state, _initialDepth, 0); result.Result.Evaluations = evaluations; result.Result.Milliseconds = timer.ElapsedMilliseconds; return(result.Result); }
public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { SearchResult result = new SearchResult(); for (int i = 0; i < 80; i++) { // Start from a tile we don't own if (state.Tiles[i] == 0) { List <int> neighbors = new List <int>(); foreach (int adjacent in Constants.AdjacentIndexes[i]) { foreach (int twoStepsAway in Constants.AdjacentIndexes[adjacent]) { // If the tile is exactly two steps away from a tile we own if (twoStepsAway != i && !Constants.AdjacentIndexes[i].Contains(twoStepsAway) && ((state.Tiles[twoStepsAway] > 0 && state.Player == Player.One) || (state.Tiles[twoStepsAway] < 0 && state.Player == Player.Two))) { if (!neighbors.Contains(twoStepsAway)) { neighbors.Add(twoStepsAway); } } } } result.BestMove = i; // This tile is two steps away from one and only one of our other tiles, then it's an amazing move if (neighbors.Count == 1) { return(result); } } } if (result.BestMove >= 0) { return(result); } else { List <int> moves = state.GetMoves(); result.BestMove = moves[random.Next(moves.Count)]; return(result); } }
public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { Stopwatch timer = Stopwatch.StartNew(); evaluations = 0; hashHits = 0; hashMisses = 0; cancellationToken = token; SearchResult result = AlphaBetaSearch(state, searchDepth, int.MinValue, int.MaxValue); result.Evaluations = evaluations; result.Milliseconds = timer.ElapsedMilliseconds; result.HashPercentage = hashHits + hashMisses > 0 ? hashHits / ((decimal)hashHits + hashMisses) : 0m; return(result); }
public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { Stopwatch timer = Stopwatch.StartNew(); statusUpdate = Stopwatch.StartNew(); visitedNodes = 0; simulationCount = 0; cancel = new EngineCancellationToken(() => token.Cancelled || timer.ElapsedMilliseconds >= maxSeconds * 1000 - bufferMilliseconds); int best = MonteCarloTreeSearch(state); return(new SearchResult { BestMove = best, Evaluations = visitedNodes, Simulations = simulationCount, Milliseconds = timer.ElapsedMilliseconds }); }
public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { List <int> moves = state.GetMoves(); // Use old tile names since the new system isn't named like this List <int> alphaMoves = moves.Where(x => Constants.OldTileNames[x].EndsWith("A")).ToList(); if (alphaMoves.Count > 0) { return(new SearchResult { BestMove = alphaMoves[random.Next(alphaMoves.Count)] }); } else { return(new SearchResult { BestMove = moves[random.Next(moves.Count)] }); } }
public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { List <int> moves = state.GetMoves(); // If we've played at lest once, find a suggested antipode path and try that if (bestPathStart >= 0) { if ((state.Tiles[bestPathStart] > 0 && state.Player == Player.One) || (state.Tiles[bestPathStart] < 0 && state.Player == Player.Two)) { List <int> suggestedPath = GetSuggestedAntipodePath(state, bestPathStart); suggestedPath = Shuffle(suggestedPath); foreach (int tile in suggestedPath) { if (((state.Tiles[tile] > 0 && state.Player == Player.One) || (state.Tiles[tile] < 0 && state.Player == Player.Two)) || state.Tiles[tile] == 0) { if (moves.Any(x => x == tile && state.Tiles[x] == 0)) { // Return the next move in the path to the antipode return(new SearchResult(tile)); } } else { break; } } } } // If all else fails, pick a random move int best = moves[random.Next(moves.Count)]; bestPathStart = best; return(new SearchResult(best)); }
public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { List <int> moves = state.GetMoves(); int best = -3; // For each tile we own, figure out how long it'll take to get to it's antipode PathResult[] selfPaths = new PathResult[80]; PathResult[] enemyPaths = new PathResult[80]; for (int i = 0; i < 80; i++) { if ((state.Tiles[i] > 0 && state.Player == Player.One) || (state.Tiles[i] < 0 && state.Player == Player.Two)) { selfPaths[i] = pathFinder.FindPath(state, i, Constants.Antipodes[i]); } else if (state.Tiles[i] != 0) { enemyPaths[i] = pathFinder.FindPath(state, i, Constants.Antipodes[i]); } } // Of all the calculated paths, find the one that's fastest PathResult bestSelfPath = selfPaths.Where(x => x != null && x.Distance != 0).OrderBy(x => x.Distance).FirstOrDefault(); PathResult bestEnemyPath = enemyPaths.Where(x => x != null && x.Distance != 0).OrderBy(x => x.Distance).FirstOrDefault(); if (bestSelfPath != null && bestEnemyPath != null) { if (bestSelfPath.Distance <= bestEnemyPath.Distance - 2) { // If we're two moves ahead of our opponent, then run to the finish line foreach (int tile in bestSelfPath.Path) { if (state.Tiles[tile] == 0 && moves.Contains(tile)) { best = tile; break; } } } else { // Try to obstruct our opponent's path foreach (int tile in bestEnemyPath.Path) { if (state.Tiles[tile] == 0 && moves.Contains(tile)) { best = tile; break; } } } } // When all else fails, pick a random move if (best < 0) { best = moves[random.Next(moves.Count)]; } return(new SearchResult(best)); }
public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { throw new Exception("Just making sure that an exception results in a resignation, not a crash!"); }
public SearchResult GetBestMove(Board state, int maxSeconds, EngineCancellationToken token) { List <int> moves = state.GetMoves(); // See if we have any pair of points that are antipodes connected by kitty corners List <int> antipodePath = new List <int>(); for (int i = 0; i < 80; i++) { if ((state.Tiles[i] > 0 && state.Player == Player.One) || (state.Tiles[i] < 0 && state.Player == Player.Two)) { List <int> path = GetAntipodePath(state, i); if (path.Count > 0) { antipodePath = path; break; } } } // If we have an antipode path, fill in tiles around the path if (antipodePath.Count > 0) { // Find a move in a tile adjacent to a tile in our antipode path List <int> adjacentAntipodePath = new List <int>(); foreach (int i in antipodePath) { adjacentAntipodePath.AddRange(Constants.AdjacentIndexes[i]); } List <int> antipodeSupport = moves.Where(x => adjacentAntipodePath.Contains(x) && state.Tiles[x] == 0).ToList(); if (antipodeSupport.Count > 0) { // There are no more antipode support tiles, so just buff the main path antipodeSupport = moves.Where(x => adjacentAntipodePath.Contains(x)).ToList(); } if (antipodeSupport.Count > 0) { // Pick a random antipode path support tile return(new SearchResult(antipodeSupport[random.Next(antipodeSupport.Count)])); } } else { // If we've played at lest once, find a suggested antipode path and try that if (bestPathStart >= 0) { if ((state.Tiles[bestPathStart] > 0 && state.Player == Player.One) || (state.Tiles[bestPathStart] < 0 && state.Player == Player.Two)) { List <int> suggestedPath = GetSuggestedAntipodePath(state, bestPathStart); foreach (int tile in suggestedPath) { if (((state.Tiles[tile] > 0 && state.Player == Player.One) || (state.Tiles[tile] < 0 && state.Player == Player.Two)) || state.Tiles[tile] == 0) { if (moves.Any(x => x == tile && state.Tiles[x] == 0)) { // Return the next move in the path to the antipode return(new SearchResult(tile)); } } else { break; } } } } // If we don't have an antipode path, continue connecting A tiles kitty corner until we do // Use old tile names since new ones don't have As List <int> alphaMoves = moves.Where(x => Constants.OldTileNames[x].EndsWith("A")).ToList(); if (alphaMoves.Count > 0) { List <int> primaryKittyCornerMoves = new List <int>(); List <int> kittyCornerMoves = new List <int>(); foreach (int move in alphaMoves) { if (state.Tiles[move] == 0) { int adjacentCount = 0; foreach (int i in Constants.KittyCornerTiles[move]) { if (state.Tiles[i] == 0) { adjacentCount++; if (!kittyCornerMoves.Contains(move)) { kittyCornerMoves.Add(move); } } } if (adjacentCount == 1) { // Only one adjacent kitty corner, so this is good primaryKittyCornerMoves.Add(move); } } } if (primaryKittyCornerMoves.Count > 0) { // Pick a random primary kitty corner move int best = primaryKittyCornerMoves[random.Next(primaryKittyCornerMoves.Count)]; bestPathStart = best; return(new SearchResult(best)); } else if (kittyCornerMoves.Count > 0) { // Pick a random kitty corner move int best = kittyCornerMoves[random.Next(kittyCornerMoves.Count)]; bestPathStart = best; return(new SearchResult(best)); } else { // Pick a random A tile int best = alphaMoves[random.Next(alphaMoves.Count)]; bestPathStart = best; return(new SearchResult(best)); } } } // If all else fails, pick a random move return(new SearchResult(moves[random.Next(moves.Count)])); }