private static GameStateInternal GetNextState(GameStateInternal lastState, GameStateInternal initialState) { var currentState = lastState; while (currentState.PreviousState != initialState) { currentState = currentState.PreviousState; } return(currentState); }
public GameStateInternal(int tickNumber, PlayerInternal me, PlayerInternal[] enemies, BonusInfo[] bonuses, GameStateInternal previousState, int[,] dangerousMap) { _dangerousMap = dangerousMap; TickNumber = tickNumber; Me = me; Enemies = enemies; Bonuses = bonuses; PreviousState = previousState; }
public GameStateInternal FindBestState(GameStateInternal initialState) { int depth; if (initialState.Enemies.Length == 0) { depth = 1; } else { int stepsLeft = initialState.Me.GetPathLengthForTime(Constants.MaxTickCount - initialState.TickNumber); depth = stepsLeft == 0 ? 1 : Math.Min(_depth, stepsLeft); } var simulationQueue = new Queue <(GameStateInternal State, int Depth)>(); simulationQueue.Enqueue((initialState, 0)); int startTickNumber = initialState.TickNumber; GameStateInternal bestState = null; int bestScore = Int32.MinValue; while (simulationQueue.Count > 0) { (var currentState, int currentDepth) = simulationQueue.Dequeue(); foreach (var move in EnumValues.GetAll <Move>()) { var nextState = _simulator.Simulate(currentState, currentState.TickNumber - startTickNumber, move); if (nextState == null) { continue; } if (currentDepth == depth - 1) { int score = _scorer.Score(nextState); if (score > bestScore) { bestScore = score; bestState = nextState; } } else { simulationQueue.Enqueue((nextState, currentDepth + 1)); } } } return(bestState); }
public int Score(GameStateInternal state) { #if DEBUG GameDebugData.Current.ScoringsCount++; #endif if (state.Me == null) { return(-1000); } if (state.Me.Direction == null) { return(-800); } const int scoresMultiplicator = 10; if (state.Me.Tail.Length == 0) { if (state.Me.Territory.Count == GameParams.MapSize.Width * GameParams.MapSize.Height) { return(state.Me.Score * scoresMultiplicator); } int pathToOutsideLength = PathFinder.GetShortestPathToOutsideLength(state.Me.Position, state.Me.Direction.Value, state.Me.Territory); int pathToOutsidePenalty = 1 - pathToOutsideLength; return(state.Me.Score * scoresMultiplicator + pathToOutsidePenalty); } if (state.Me.PathToHome == null) { return(-900); } if (state.Me.GetTimeForPath(state.Me.PathToHome.Length) >= Constants.MaxTickCount - state.TickNumber) { return(-500); } int potentialScore = CalcPotentialTerritoryCaptureScore(state); int potentialScoreBonus = (int)(potentialScore * 0.9); int bonusScore = state.Me.NitroStepsLeft > state.Me.SlowdownStepsLeft ? NitroInScores : state.Me.SlowdownStepsLeft > state.Me.NitroStepsLeft ? SlowdownInScores : 0; return((state.Me.Score + potentialScoreBonus + bonusScore) * scoresMultiplicator); }
private static List <GameStateInternal> GetStates(GameStateInternal lastState, GameStateInternal initialState) { var states = new List <GameStateInternal>(); var currentState = lastState; while (currentState != initialState) { states.Add(currentState); currentState = currentState.PreviousState; } states.Reverse(); return(states); }
public Direction GetNextDirection(GameState state) { #if DEBUG var stopwatch = new Stopwatch();; stopwatch.Start(); GameDebugData.Current.Reset(); #endif if (state.TickNumber == 1) { return(GetStartDirection(state)); } var currentState = _lastState == null ? new GameStateInternal(state) : new GameStateInternal(state, _lastState); var bestState = _bestTrajectoryFinder.FindBestState(currentState); _lastState = currentState; Direction nextDirection; if (bestState != null) { var nextState = GetNextState(bestState, currentState); nextDirection = nextState.Me.Direction.Value; } else if (currentState.Me.PathToHome != null && currentState.Me.PathToHome.Length > 0) { nextDirection = currentState.Me.Position.GetDirectionTo(currentState.Me.PathToHome[0]); } else { nextDirection = currentState.Me.Direction ?? Direction.Left; } #if DEBUG stopwatch.Stop(); GameDebugData.Current.UsedTime = stopwatch.Elapsed; GameDebugData.Current.DangerousMap = currentState.DangerousMap; GameDebugData.Current.BestTrajectory = bestState != null ? GetStates(bestState, currentState).Select(s => s.Me.Position.ConvertToReal(GameParams.CellSize)).ToArray() : currentState.Me.PathToHome.Select(p => p.ConvertToReal(GameParams.CellSize)).ToArray(); #endif return(nextDirection); }
public int CalcPotentialTerritoryCaptureScore(GameStateInternal state) { if (state.Me.Tail.Length == 0) { return(0); } var tailWithPathToHome = new Point[state.Me.Tail.Length + state.Me.PathToHome.Length - 1]; for (int i = 0; i < state.Me.Tail.Length; i++) { tailWithPathToHome[i] = state.Me.Tail[i]; } for (int i = 0; i < state.Me.PathToHome.Length - 1; i++) { tailWithPathToHome[state.Me.Tail.Length + i] = state.Me.PathToHome[i]; } var capturedTerritory = _territoryCapturer.Capture(state.Me.Territory, tailWithPathToHome); int score = capturedTerritory.Count * Constants.NeutralTerritoryScore; int enemyTerritoryPoints = 0; foreach (var point in capturedTerritory) { foreach (var enemy in state.Enemies) { if (enemy.Territory.Contains(point)) { enemyTerritoryPoints++; break; } } } score += enemyTerritoryPoints * (Constants.EnemyTerritoryScore - Constants.NeutralTerritoryScore); int nitroCount = 0; int slowdownCount = 0; foreach (var bonus in state.Bonuses) { if (capturedTerritory.Contains(bonus.Position)) { switch (bonus.Type) { case BonusType.Nitro: nitroCount++; break; case BonusType.Slowdown: slowdownCount++; break; case BonusType.Saw: break; default: throw new ArgumentOutOfRangeException(); } } } int bonusScore = nitroCount > slowdownCount ? NitroInScores : slowdownCount > nitroCount ? SlowdownInScores : 0; return(score + bonusScore); }
public GameStateInternal(GameState state, GameStateInternal previousState) : this(state) { PreviousState = previousState; }
public GameStateInternal Simulate(GameStateInternal state, int simulationTicks, Move move) { #if DEBUG GameDebugData.Current.SimulationsCount++; #endif int timeToNextPos = GameParams.CellSize / state.Me.GetSpeed(0); int nextTickNumber = state.TickNumber + timeToNextPos; var me = (PlayerInternal)state.Me.Clone(); if (me.NitroStepsLeft > 0) { me.NitroStepsLeft--; } if (me.SlowdownStepsLeft > 0) { me.SlowdownStepsLeft--; } me.Direction = me.Direction?.GetMoved(move); if (me.Direction != null) { me.Position = me.Position.MoveLogic(me.Direction.Value); } if (!GameParams.MapSize.ContainsPoint(me.Position) || // Выехал за пределы карты me.Tail.Contains(me.Position)) // Наехал сам себе на хвост { return(null); } var nextBonuses = state.Bonuses; foreach (var bonus in state.Bonuses) { if (bonus.Position == me.Position) { switch (bonus.Type) { case BonusType.Nitro: me.NitroStepsLeft += bonus.Steps; break; case BonusType.Slowdown: me.SlowdownStepsLeft += bonus.Steps; break; case BonusType.Saw: break; default: throw new ArgumentOutOfRangeException(); } nextBonuses = state.Bonuses.Where(b => b != bonus).ToArray(); break; } } var enemies = (PlayerInternal[])state.Enemies.Clone(); foreach (var enemy in enemies) { if (enemy.Tail.Length == 0 || enemy.Territory.Count == 0) { continue; } if (enemy.TimeToGetHome > simulationTicks + timeToNextPos) { continue; } if (enemy.CapturedOnPathToHome != null) { if (enemy.TimeToGetHome > simulationTicks) { me.Territory = me.Territory.ExceptWith(enemy.CapturedOnPathToHome); } continue; } var tailWithPathToHome = new Point[enemy.Tail.Length + enemy.PathToHome.Length - 1]; for (int i = 0; i < enemy.Tail.Length; i++) { tailWithPathToHome[i] = enemy.Tail[i]; } for (int i = 0; i < enemy.PathToHome.Length - 1; i++) { tailWithPathToHome[enemy.Tail.Length + i] = enemy.PathToHome[i]; } enemy.CapturedOnPathToHome = _territoryCapturer.Capture(enemy.Territory, tailWithPathToHome); if (enemy.CapturedOnPathToHome.Contains(state.Me.Position)) { return(null); } me.Territory = me.Territory.ExceptWith(enemy.CapturedOnPathToHome); } if (me.Territory.Contains(me.Position)) { if (me.Tail.Length > 0) // Заезд на свою территорию { if (state.DangerousMap[me.Position.X, me.Position.Y] - GameParams.CellSize / GameParams.SlowDownSpeed * 2 < simulationTicks + timeToNextPos) // Упрощенная оценка возможных столкновений { if (enemies.Any(enemy => CheckIsCollisionPossible(me, enemy, state.Me.Position, simulationTicks, timeToNextPos))) // Лобовое столкновение с противником { return(null); } } var capturedTerritory = _territoryCapturer.Capture(me.Territory, me.Tail); me.Tail = Path.Empty; me.Territory = me.Territory.UnionWith(capturedTerritory); me.Score += capturedTerritory.Count * Constants.NeutralTerritoryScore; for (int i = 0; i < enemies.Length; i++) { var enemy = enemies[i]; int srcCount = enemy.Territory.Count; var enemyCroppedTerritory = enemy.Territory.ExceptWith(capturedTerritory); int croppedCount = enemyCroppedTerritory.Count; if (srcCount != croppedCount) { var clonedEnemy = (PlayerInternal)enemy.Clone(); clonedEnemy.Territory = enemyCroppedTerritory; enemies[i] = clonedEnemy; me.Score += (srcCount - croppedCount) * (Constants.EnemyTerritoryScore - Constants.NeutralTerritoryScore); } } bool gotBonus = false; for (int i = 0; i < nextBonuses.Length; i++) { var bonus = nextBonuses[i]; if (capturedTerritory.Contains(bonus.Position)) { switch (bonus.Type) { case BonusType.Nitro: me.NitroStepsLeft += bonus.Steps; break; case BonusType.Slowdown: me.SlowdownStepsLeft += bonus.Steps; break; case BonusType.Saw: break; default: throw new ArgumentOutOfRangeException(); } gotBonus = true; if (nextBonuses == state.Bonuses) { nextBonuses = (BonusInfo[])state.Bonuses.Clone(); } nextBonuses[i] = null; } } if (gotBonus) { nextBonuses = nextBonuses.Where(b => b != null).ToArray(); } } } else { me.Tail = me.Tail.Append(me.Position); if (me.PathToHome == null) // Зашел в тупик { return(null); } if (me.Tail.Any(p => state.DangerousMap[p.X, p.Y] < simulationTicks + timeToNextPos + me.GetTimeForPath(me.PathToHome.Length))) // Потенциально могут наехать на мой хвост { return(null); } } bool hasLosers = false; for (int i = 0; i < enemies.Length; i++) { var enemy = enemies[i]; if (enemy.Tail.AsPointsSet().Contains(me.Position) && enemy.TimeToGetHome > simulationTicks + timeToNextPos + 1) // Противник умирает, только если мы переехали его хвост и он гарантированно не успел вернуться домой { hasLosers = true; enemies[i] = null; me.Score += Constants.LineKillScore; break; } } enemies = hasLosers ? enemies.Where(e => e != null).ToArray() : enemies; return(new GameStateInternal(nextTickNumber, me, enemies, nextBonuses, state, hasLosers ? null : state.DangerousMap)); }