コード例 #1
0
ファイル: Game.cs プロジェクト: voidmain02/miniaicup.paperio
        private static GameStateInternal GetNextState(GameStateInternal lastState, GameStateInternal initialState)
        {
            var currentState = lastState;

            while (currentState.PreviousState != initialState)
            {
                currentState = currentState.PreviousState;
            }

            return(currentState);
        }
コード例 #2
0
        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;
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        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);
        }
コード例 #5
0
ファイル: Game.cs プロジェクト: voidmain02/miniaicup.paperio
        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);
        }
コード例 #6
0
ファイル: Game.cs プロジェクト: voidmain02/miniaicup.paperio
        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);
        }
コード例 #7
0
        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);
        }
コード例 #8
0
 public GameStateInternal(GameState state, GameStateInternal previousState) : this(state)
 {
     PreviousState = previousState;
 }
コード例 #9
0
        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));
        }