public static SnakeKeys CalculateNextMove(Settings settings, Circle food, Snake snake, ScoreSetup scoreSetup) { var depth = (int)(snake.Body.Count * scoreSetup.AIDepthScaling + 1); if (depth > scoreSetup.AIMaxDepth) { depth = scoreSetup.AIMaxDepth; } if (depth < scoreSetup.AIMinDepth) { depth = scoreSetup.AIMinDepth; } var route = CalculateRoute(new List <Move>(), settings, food, snake.Clone(), 0, depth, scoreSetup); if (route?.Moves.Any() != true) { return(MoveLogic.GetKey(snake.Direction)); } var nextMove = route.Moves[0]; var key = MoveLogic.GetKey(nextMove.Direction); return(key); }
private static List <Move> GetPossibleMoves(Snake snake) { var head = snake.Body[0]; var leftDirection = MoveLogic.GetLeftDirection(snake.Direction); var left = new Move(MoveLogic.GetNextLocation(head, leftDirection), leftDirection); var forward = new Move(MoveLogic.GetNextLocation(head, snake.Direction), snake.Direction); var rightDirection = MoveLogic.GetRightDirection(snake.Direction); var right = new Move(MoveLogic.GetNextLocation(head, rightDirection), rightDirection); var moves = new List <Move> { left, forward, right }; return(moves); }
private static Route CalculateRoute(List <Move> moves, Settings settings, Circle food, Snake snake, int level, int depth, ScoreSetup scoreSetup) { if (level == depth) { return new Route(scoreSetup) { Moves = moves } } ; level++; var possibleMoves = GetPossibleMoves(snake); var routes = new List <Route>(); foreach (var move in possibleMoves) { var newSnake = snake.Clone(); var head = snake.Body[0]; var lastBody = newSnake.Body.Last(); newSnake.Body.Insert(0, move.Location); if (move.Location.Equals(food)) { move.HasFood = true; food = new Circle(0, 0); } if (moves.LastOrDefault()?.HasFood != true) { newSnake.Body.Remove(lastBody); } newSnake.Direction = MoveLogic.CalculateDirection(head, move.Location); var newMoves = moves.ToList(); newMoves.Add(move); if (HasCrashed(newSnake, settings)) { routes.Add(new Route(scoreSetup) { WillCrash = true, Moves = newMoves, DistanceToFood = GetFoodDistance(move.Location, food) }); continue; } var route = CalculateRoute(newMoves, settings, food, newSnake, level, depth, scoreSetup); if (route is null) { continue; } route.DistanceToFood = GetFoodDistance(move.Location, food); routes.Add(route); } if (!routes.Any()) { return new Route(scoreSetup) { WillCrash = true } } ; var bestMoveFoodDistance = routes.Max(x => x.CalculateScore()); var bestRoute = routes.FirstOrDefault(x => Math.Abs(x.CalculateScore() - bestMoveFoodDistance) < 0.00001); return(bestRoute); }