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);
        }
Пример #2
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));
        }