Пример #1
0
        public void AttackClosestEnemyTankToOwnBase(GameState currGameState, Tank killerTank, Tank targetTank,
                                                    TankActionSet actionSet, bool[] moveChosenByTankNumber)
        {
            MobileState killerTankState = currGameState.GetMobileState(killerTank.Index);

            if (killerTankState.IsActive)
            {
                MobileState enemyTankState = currGameState.GetMobileState(targetTank.Index);
                if (enemyTankState.IsActive)
                {
                    DirectionalMatrix <DistanceCalculation> attackMatrix
                        = currGameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(targetTank.Index);
                    if (attackMatrix != null)
                    {
                        DistanceCalculation attackCalculation = attackMatrix[killerTankState.Dir, killerTankState.Pos];
                        TankAction[]        tankActions
                            = PathCalculator.GetTankActionsOnIncomingShortestPath(attackMatrix, killerTankState, enemyTankState.Pos,
                                                                                  currGameState.CalculationCache.FiringLinesForTanksMatrix, keepMovingCloserOnFiringLastBullet: true);
                        if (tankActions.Length > 0)
                        {
                            actionSet.Actions[killerTank.Number]      = tankActions[0];
                            moveChosenByTankNumber[killerTank.Number] = true;
                        }
                    }
                }
            }
        }
        private bool TrySetBestMoveSoFar(GameState currGameState, GameSituation gameSituation)
        {
            TankActionSet actionSet
                = gameSituation.GenerateTankActions(YourPlayerIndex, currGameState.Tick);

            Coordinator.SetBestMoveSoFar(actionSet);
            return(true);
        }
Пример #3
0
        public bool TrySetTankActions(TankActionSet actionSet, int timeoutInMilliseconds)
        {
            if (actionSet == null)
            {
                return(true);
            }

            if (actionSet.Tick != Game.Current.CurrentTurn.Tick)
            {
                LogDebugMessage("Tank actions not submitted as tick {0} is in the past", actionSet.Tick);
                return(false);
            }

            int        playerIndex      = actionSet.PlayerIndex;
            GameState  currentGameState = Game.Current.CurrentTurn.GameState;
            int        numberAlive      = 0;
            int        tankId           = -1;
            TankAction tankAction       = TankAction.NONE;
            int        tankNumber       = -1;

            for (int t = 0; t < Constants.TANKS_PER_PLAYER; t++)
            {
                Tank        tank      = Game.Current.Players[actionSet.PlayerIndex].Tanks[t];
                MobileState tankState = currentGameState.GetMobileState(tank.Index);
                if (tankState.IsActive)
                {
                    numberAlive++;
                    tankId     = tank.Id;
                    tankAction = actionSet.Actions[t];
                    tankNumber = tank.Number;
                }
            }

            LogDebugMessage("Sending tank actions for player {0}", Solver.YourPlayerIndex);

            if (numberAlive == 1)
            {
                LogDebugMessage("    Tank {0} action {1} (tank id: {2})", tankNumber, tankAction, tankId);
                return(Communicator.TrySetAction(playerIndex, tankId, tankAction, CommunicatorCallback, timeoutInMilliseconds));
            }
            else
            if (numberAlive == 2)
            {
                TankAction tankAction1 = actionSet.Actions[0];
                TankAction tankAction2 = actionSet.Actions[1];
                LogDebugMessage("    Tank 0 action {0}", tankAction1);
                LogDebugMessage("    Tank 1 action {0}", tankAction2);
                return(Communicator.TrySetActions(playerIndex, tankAction1, tankAction2, CommunicatorCallback, timeoutInMilliseconds));
            }
            else
            {
                return(true);
            }
        }
Пример #4
0
        protected override void ChooseMoves()
        {
            GameState     currGameState = Game.Current.CurrentTurn.GameState;
            TankActionSet actionSet     = new TankActionSet(YourPlayerIndex, currGameState.Tick);

            for (int tankNumber = 0; tankNumber < Constants.TANKS_PER_PLAYER; tankNumber++)
            {
                Tank        tank      = You.Tanks[tankNumber];
                MobileState tankState = currGameState.GetMobileState(tank.Index);
                if (!tankState.IsActive)
                {
                    continue;
                }

                int midX = currGameState.Walls.Width / 2;
                int midY = currGameState.Walls.Height / 2;

                int       targetX;
                int       targetY;
                Direction direction;

                if (tankState.Pos.X > midX)
                {
                    targetX = currGameState.Walls.Width - Constants.SEGMENT_SIZE;
                }
                else
                {
                    targetX = Constants.SEGMENT_SIZE;
                }

                if (tankState.Pos.Y > midY)
                {
                    targetY   = currGameState.Walls.Height - Constants.SEGMENT_SIZE;
                    direction = Direction.UP;
                }
                else
                {
                    targetY   = Constants.SEGMENT_SIZE;
                    direction = Direction.DOWN;
                }

                DirectionalMatrix <DistanceCalculation> distancesFromTank
                    = currGameState.CalculationCache.GetDistanceMatrixFromTankByTankIndex(tank.Index);
                TankAction[] tankActions = PathCalculator.GetTankActionsOnOutgoingShortestPath(
                    distancesFromTank, direction, targetX, targetY);
                if (tankActions.Length > 0)
                {
                    actionSet.Actions[tank.Number] = tankActions[0];
                }
            }

            Coordinator.SetBestMoveSoFar(actionSet);
        }
        private void RespondToBullets(GameState currGameState, TankActionSet actionSet, bool[] moveChosen)
        {
            BulletCalculation bulletCalc = BulletCalculator.GetBulletCalculation(currGameState, You);

            foreach (BulletPathCalculation bulletPathCalc in bulletCalc.BulletPaths)
            {
                BulletThreat[] bulletThreats = bulletPathCalc.BulletThreats;
                for (int i = 0; i < bulletThreats.Length; i++)
                {
                    BulletThreat bulletThreat = bulletThreats[i];
                    if (bulletThreat.TankThreatened.Player == You && !moveChosen[bulletThreat.TankThreatened.Number])
                    {
                        if ((bulletPathCalc.BaseThreatened == You.Base) &&
                            (bulletThreat.NodePathToTakeOnBullet != null) &&
                            (bulletThreat.NodePathToTakeOnBullet.Length > 0))
                        {
                            actionSet.Actions[bulletThreat.TankThreatened.Number]
                                = bulletThreat.TankActionsToTakeOnBullet[0];
                            moveChosen[bulletThreat.TankThreatened.Number] = true;
                            continue;
                        }

                        if (bulletThreat.LateralMoveInOneDirection != null &&
                            bulletThreat.LateralMoveInOneDirection.Length > 0)
                        {
                            actionSet.Actions[bulletThreat.TankThreatened.Number]
                                = bulletThreat.TankActionsForLateralMoveInOneDirection[0];
                            moveChosen[bulletThreat.TankThreatened.Number] = true;
                            continue;
                        }

                        if (bulletThreat.LateralMoveInOtherDirection != null &&
                            bulletThreat.LateralMoveInOtherDirection.Length > 0)
                        {
                            actionSet.Actions[bulletThreat.TankThreatened.Number]
                                = bulletThreat.TankActionsForLateralMoveInOtherDirection[0];
                            moveChosen[bulletThreat.TankThreatened.Number] = true;
                            continue;
                        }

                        if ((bulletThreat.NodePathToTakeOnBullet != null) &&
                            (bulletThreat.NodePathToTakeOnBullet.Length > 0))
                        {
                            actionSet.Actions[bulletThreat.TankThreatened.Number]
                                = bulletThreat.TankActionsToTakeOnBullet[0];
                            moveChosen[bulletThreat.TankThreatened.Number] = true;
                            continue;
                        }
                    }
                }
            }
        }
        protected override void ChooseMoves()
        {
            GameState     currGameState = Game.Current.CurrentTurn.GameState;
            TankActionSet actionSet     = new TankActionSet(YourPlayerIndex, currGameState.Tick);

            for (int t = 0; t < Constants.TANKS_PER_PLAYER; t++)
            {
                int tankAction = rnd.Next(6);
                actionSet.Actions[t] = (TankAction)tankAction;
            }

            Coordinator.SetBestMoveSoFar(actionSet);
        }
        public TankActionSet GenerateTankActions(int yourPlayerIndex, int tick)
        {
            TankActionSet tankActionSet = new TankActionSet(yourPlayerIndex, tick);

            foreach (Tank tank in Game.Current.Players[yourPlayerIndex].Tanks)
            {
                TankSituation tankSituation = TankSituationsByTankIndex[tank.Index];
                TankAction    bestAction    = tankSituation.GetBestTankAction();
                tankActionSet.Actions[tank.Number] = bestAction;
            }

            return(tankActionSet);
        }
Пример #8
0
 public void SetBestMoveSoFar(TankActionSet bestMove)
 {
     PerformActionInALock <TankActionSet>(bestMove, BestMoveLock, "Lock timeout with best move lock",
                                          delegate(TankActionSet bm)
     {
         if (CanMovesBeChosen)
         {
             /* Get a static copy of the CurrentGameState in case of concurrency issues
              * (i.e. the tick advances, and a new CurrentGameState is set):
              */
             if (bestMove.Tick >= Game.Current.CurrentTurn.Tick)
             {
                 BestMoveSoFar = bm;
             }
         }
     });
 }
Пример #9
0
        protected override void ChooseMoves()
        {
            try
            {
                GameState currGameState = Game.Current.CurrentTurn.GameState;

                TankActionSet actionSet = new TankActionSet(YourPlayerIndex, currGameState.Tick);
                bool[]        moveChosenByTankNumber = new bool[Constants.TANKS_PER_PLAYER];

                RespondToBullets(currGameState, actionSet, moveChosenByTankNumber);
                ChooseActions(currGameState, actionSet, moveChosenByTankNumber);
                Coordinator.SetBestMoveSoFar(actionSet);
                return;
            }
            catch (Exception exc)
            {
                // Swallow errors
            }

            // Shortest Path Bot code:
            ChooseShortestPathBotMoves();
        }
        private void ChooseShortestPathBotMoves()
        {
            GameState     currGameState = Game.Current.CurrentTurn.GameState;
            TankActionSet actionSet     = new TankActionSet(YourPlayerIndex, currGameState.Tick);

            bool[] moveChosen = new bool[Constants.TANKS_PER_PLAYER];

            RespondToBullets(currGameState, actionSet, moveChosen);

            Tuple <int, int, TankAction>[] tankNumberDistanceAndActionArray = new Tuple <int, int, TankAction> [Constants.TANKS_PER_PLAYER];

            // The closest bot can attack the base:
            for (int tankNumber = 0; tankNumber < Constants.TANKS_PER_PLAYER; tankNumber++)
            {
                Tank        tank      = You.Tanks[tankNumber];
                MobileState tankState = currGameState.GetMobileState(tank.Index);
                if (!tankState.IsActive)
                {
                    tankNumberDistanceAndActionArray[tankNumber]
                        = new Tuple <int, int, TankAction>(tankNumber, Constants.UNREACHABLE_DISTANCE, TankAction.NONE);
                    continue;
                }

                Base enemyBase = Opponent.Base;
                DirectionalMatrix <DistanceCalculation> distancesToEnemyBase
                    = currGameState.CalculationCache.GetIncomingDistanceMatrixForBase(Opponent.Index);
                DistanceCalculation distanceCalc = distancesToEnemyBase[tankState.Dir, tankState.Pos];

                FiringLineMatrix firingLineMatrix = currGameState.CalculationCache.FiringLinesForPointsMatrix;
                TankAction[]     tankActions      = PathCalculator.GetTankActionsOnIncomingShortestPath(distancesToEnemyBase,
                                                                                                        tankState.Dir, tankState.Pos.X, tankState.Pos.Y, enemyBase.Pos.X, enemyBase.Pos.Y,
                                                                                                        firingLineMatrix, keepMovingCloserOnFiringLastBullet: false);

                if (tankActions.Length == 0)
                {
                    tankNumberDistanceAndActionArray[tankNumber]
                        = new Tuple <int, int, TankAction>(tankNumber, Constants.UNREACHABLE_DISTANCE, TankAction.NONE);
                }
                else
                {
                    tankNumberDistanceAndActionArray[tankNumber]
                        = new Tuple <int, int, TankAction>(tankNumber, distanceCalc.Distance, tankActions[0]);
                }
            }

            int chosenTank;

            if (tankNumberDistanceAndActionArray[1].Item2 < tankNumberDistanceAndActionArray[0].Item2)
            {
                chosenTank = 1;
            }
            else
            {
                chosenTank = 0;
            }
            actionSet.Actions[chosenTank] = tankNumberDistanceAndActionArray[chosenTank].Item3;

            // The other bot can attack the closest enemy tank:
            Tank        killerTank      = You.Tanks[1 - chosenTank];
            MobileState killerTankState = currGameState.GetMobileState(killerTank.Index);

            if (killerTankState.IsActive)
            {
                Tank        enemyTank1      = Opponent.Tanks[0];
                MobileState enemyTankState1 = currGameState.GetMobileState(enemyTank1.Index);

                int        killerDistance1 = Constants.UNREACHABLE_DISTANCE;
                TankAction killerAction1   = TankAction.NONE;

                if (enemyTankState1.IsActive)
                {
                    DirectionalMatrix <DistanceCalculation> attackMatrix1
                        = currGameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(enemyTank1.Index);
                    if (attackMatrix1 != null)
                    {
                        DistanceCalculation attackCalculation1 = attackMatrix1[killerTankState.Dir, killerTankState.Pos];
                        killerDistance1 = attackCalculation1.Distance;
                        TankAction[] tankActions
                            = PathCalculator.GetTankActionsOnIncomingShortestPath(attackMatrix1, killerTankState, enemyTankState1.Pos,
                                                                                  currGameState.CalculationCache.FiringLinesForTanksMatrix, keepMovingCloserOnFiringLastBullet: true);
                        if (tankActions.Length > 0)
                        {
                            killerAction1 = tankActions[0];
                        }
                    }
                }

                Tank        enemyTank2      = Opponent.Tanks[1];
                MobileState enemyTankState2 = currGameState.GetMobileState(enemyTank2.Index);

                int        killerDistance2 = Constants.UNREACHABLE_DISTANCE;
                TankAction killerAction2   = TankAction.NONE;

                if (enemyTankState2.IsActive)
                {
                    DirectionalMatrix <DistanceCalculation> attackMatrix2
                        = currGameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(enemyTank2.Index);
                    if (attackMatrix2 != null)
                    {
                        DistanceCalculation attackCalculation2 = attackMatrix2[killerTankState.Dir, killerTankState.Pos];
                        killerDistance2 = attackCalculation2.Distance;
                        TankAction[] tankActions
                            = PathCalculator.GetTankActionsOnIncomingShortestPath(attackMatrix2, killerTankState, enemyTankState2.Pos,
                                                                                  currGameState.CalculationCache.FiringLinesForTanksMatrix, keepMovingCloserOnFiringLastBullet: true);
                        if (tankActions.Length > 0)
                        {
                            killerAction2 = tankActions[0];
                        }
                    }
                }

                actionSet.Actions[1 - chosenTank]
                    = (killerDistance1 <= killerDistance2)
                    ? killerAction1
                    : killerAction2;
            }

            Coordinator.SetBestMoveSoFar(actionSet);
        }
        public virtual void Start()
        {
            if (Coordinator == null)
            {
                throw new ApplicationException("The solver has no coordinator");
            }

            Initialize();

            while (SolverState != SolverState.Stopping)
            {
                // Wait for the solver state to change:
                while ((SolverState != SolverState.CanChooseMoves) &&
                       (SolverState != SolverState.Stopping))
                {
                    Thread.Sleep(10);
                }

                bool replayingMoves = false;
                int  currentTick    = Game.Current.CurrentTurn.Tick;

                SolverState = SolverState.ChoosingMoves;
                try
                {
                    if (GameToReplay != null &&
                        currentTick <= TickToReplayTo &&
                        GameToReplay.Turns[currentTick].TankActionsTakenAfterPreviousTurn != null)
                    {
                        replayingMoves = true;
                        LogDebugMessage("Replaying saved moves on turn {0}", currentTick);

                        TankActionSet tankActionSet    = new TankActionSet(YourPlayerIndex, currentTick);
                        TankAction[]  tankActionsTaken = GameToReplay.Turns[currentTick].TankActionsTakenAfterPreviousTurn;
                        for (int tNum = 0; tNum < Constants.TANKS_PER_PLAYER; tNum++)
                        {
                            Tank       tank         = You.Tanks[tNum];
                            TankAction actionToTake = tankActionsTaken[tank.Index];
                            tankActionSet.Actions[tNum] = actionToTake;
                        }
                        Coordinator.SetBestMoveSoFar(tankActionSet);
                    }
                    else
                    {
                        LogDebugMessage("Choosing moves on turn {0}", currentTick);
#if DEBUG
                        Stopwatch swatch = Stopwatch.StartNew();
#endif
                        ChooseMoves();
#if DEBUG
                        swatch.Stop();
                        LogDebugMessage("Finished choosing moves. Duration: {0}", swatch.Elapsed);
#endif
                    }
                }
                catch (Exception exc)
                {
                    LogDebugError(exc, exc.Message);

                    System.Diagnostics.Debug.WriteLine(
                        "Error while choosing moves: {0}", exc);
                    System.Diagnostics.Debug.WriteLine("Stack trace:");
                    System.Diagnostics.Debug.WriteLine(exc.StackTrace);
                }

                if (SolverState == SolverState.Stopping)
                {
                    break;
                }

                SolverState = SolverState.Thinking;
                try
                {
                    if (!replayingMoves)
                    {
                        LogDebugMessage("Thinking on turn {0}", currentTick);
#if DEBUG
                        Stopwatch swatch = Stopwatch.StartNew();
#endif
                        Think();
                        // If this method returns due to finishing its work, then the next state can be set to WaitingToChooseMoves.
                        // Otherwise it must return when the state is changed to CanChooseMoves or Stopping.
#if DEBUG
                        swatch.Stop();
                        LogDebugMessage("Finished thinking. Duration: {0}", swatch.Elapsed);
#endif
                    }
                }
                catch (Exception exc)
                {
                    System.Diagnostics.Debug.WriteLine(
                        "Error while thinking: {0}", exc);
                    System.Diagnostics.Debug.WriteLine("Stack trace:");
                    System.Diagnostics.Debug.WriteLine(exc.StackTrace);
                }

                if (SolverState == SolverState.Stopping)
                {
                    break;
                }

                if (SolverState != SolverState.CanChooseMoves)
                {
                    SolverState = SolverState.WaitingToChooseMoves;
                    // The SolverState setter will ignore this if in a CanChooseMoves state,
                    // thus preventing a nasty race condition that would lead to an endless loop.
                }
            }
            SolverState = SolverState.Stopped;
        }
Пример #12
0
 protected Turn()
 {
     BulletIds = new int[Constants.TANK_COUNT];
     TankActionsTakenAfterPreviousTurn = new TankAction[Constants.TANK_COUNT];
     TankActionSetsSent = new TankActionSet[Constants.PLAYERS_PER_GAME];
 }
Пример #13
0
        public void ChooseActions(GameState currGameState, TankActionSet actionSet, bool[] moveChosenByTankNumber)
        {
            int[]       minDistanceToAttackEnemyBaseByPlayerIndex = new int[Constants.PLAYERS_PER_GAME];
            int[]       minDistanceToDefendOwnBaseByPlayerIndex   = new int[Constants.PLAYERS_PER_GAME];
            bool[]      isUnmarked = new bool[Constants.PLAYERS_PER_GAME];
            Direction[] attackDirOnEnemyBaseByPlayerIndex = new Direction[Constants.PLAYERS_PER_GAME];
            for (int p = 0; p < 2; p++)
            {
                attackDirOnEnemyBaseByPlayerIndex[p] = Direction.NONE;
            }
            Tank closestFriendlyTankToAttackEnemyBase = null;
            Tank closestFriendlyTankToDefendOwnBase   = null;
            Tank closestEnemyTankToAttackYourBase     = null;

            TankAction[] tankActionsForClosestFriendlyTankToAttackEnemyBase = null;
            TankAction[] tankActionsForClosestFriendlyTankToDefendOwnBase   = null;

            foreach (Player player in Game.Current.Players)
            {
                int minDistanceToEnemyBase = Constants.UNREACHABLE_DISTANCE;

                foreach (Tank tank in player.Tanks)
                {
                    MobileState tankState = currGameState.GetMobileState(tank.Index);
                    if (!tankState.IsActive)  // TODO: Check if locked in a firefight also
                    {
                        continue;
                    }

                    DirectionalMatrix <DistanceCalculation> distanceCalcMatrix
                        = currGameState.CalculationCache.GetIncomingDistanceMatrixForBase(1 - player.Index);
                    DistanceCalculation baseAttackCalc = distanceCalcMatrix[tankState];

                    int distanceToEnemyBase = baseAttackCalc.Distance;
                    if (distanceToEnemyBase < minDistanceToEnemyBase)
                    {
                        minDistanceToEnemyBase = distanceToEnemyBase;
                        attackDirOnEnemyBaseByPlayerIndex[player.Index] = baseAttackCalc.AdjacentNode.Dir;
                        if (player == You)
                        {
                            closestFriendlyTankToAttackEnemyBase = tank;
                            Base             enemyBase        = Game.Current.Players[1 - You.Index].Base;
                            FiringLineMatrix firingLineMatrix = currGameState.CalculationCache.FiringLinesForPointsMatrix;
                            tankActionsForClosestFriendlyTankToAttackEnemyBase = PathCalculator.GetTankActionsOnIncomingShortestPath(
                                distanceCalcMatrix, tankState, enemyBase.Pos, firingLineMatrix, true);
                        }
                        else
                        {
                            closestEnemyTankToAttackYourBase = tank;
                        }
                    }
                }
                minDistanceToAttackEnemyBaseByPlayerIndex[player.Index] = minDistanceToEnemyBase;
            }

            foreach (Player player in Game.Current.Players)
            {
                int minDistanceToDefendOwnBase = Constants.UNREACHABLE_DISTANCE;

                foreach (Tank tank in player.Tanks)
                {
                    MobileState tankState = currGameState.GetMobileState(tank.Index);
                    if (tankState.IsActive)  // TODO: Check if locked in a firefight also
                    {
                        DirectionalMatrix <DistanceCalculation> distanceMatrix
                            = currGameState.CalculationCache.GetDistanceMatrixFromTankByTankIndex(tank.Index);
                        Direction attackDir  = attackDirOnEnemyBaseByPlayerIndex[1 - player.Index];
                        Direction defenceDir = attackDir.GetOpposite();
                        if (defenceDir == Direction.NONE)
                        {
                            defenceDir = Direction.RIGHT;
                        }
                        Point defencePos = player.Base.Pos + (Constants.SEGMENT_SIZE + 1) * defenceDir.GetOffset();
                        DistanceCalculation tankDefenceCalc = distanceMatrix[
                            defenceDir, defencePos];

                        int distance = tankDefenceCalc.Distance;
                        if (distance < minDistanceToDefendOwnBase)
                        {
                            minDistanceToDefendOwnBase = distance;
                            if (player == You)
                            {
                                closestFriendlyTankToDefendOwnBase = tank;
                                tankActionsForClosestFriendlyTankToDefendOwnBase = PathCalculator.GetTankActionsOnOutgoingShortestPath(
                                    distanceMatrix, defenceDir, defencePos.X, defencePos.Y);
                            }
                        }
                    }
                }
                minDistanceToDefendOwnBaseByPlayerIndex[player.Index] = minDistanceToDefendOwnBase;
                if (minDistanceToAttackEnemyBaseByPlayerIndex[1 - player.Index] < minDistanceToDefendOwnBase)
                {
                    isUnmarked[1 - player.Index] = true;
                }
            }

            /*
             * int minAttackDistance = minDistanceToAttackEnemyBaseByPlayerIndex[You.Index];
             * if (Game.Current.CurrentTurn.Tick + minAttackDistance > Game.Current.FinalTickInGame)
             * {
             *  // Can't attack in time, rather defend...
             *  return;
             * }
             */

            // You're unmarked...
            Tank attackTank = closestFriendlyTankToAttackEnemyBase;

            if (isUnmarked[You.Index] && attackTank != null)
            {
                bool shouldAttack = true;

                // Enemy is marked...
                if (!isUnmarked[1 - You.Index])
                {
                    int minAttackDistance      = minDistanceToAttackEnemyBaseByPlayerIndex[You.Index];
                    int minEnemyAttackDistance = minDistanceToAttackEnemyBaseByPlayerIndex[1 - You.Index];

                    // But if you stop marking them, by going for their base, they can get there first...
                    if ((minAttackDistance > minEnemyAttackDistance) &&
                        (closestFriendlyTankToDefendOwnBase == attackTank))
                    {
                        shouldAttack = false;
                        // TODO: See if your other tank can do defence duty instead...
                    }
                }

                if (shouldAttack && !moveChosenByTankNumber[attackTank.Number])
                {
                    actionSet.Actions[attackTank.Number]      = tankActionsForClosestFriendlyTankToAttackEnemyBase[0];
                    moveChosenByTankNumber[attackTank.Number] = true;
                }
            }

            // If there is a slack of less than 5 ticks to defend your base, get back to defend it:
            Tank defenceTank = closestFriendlyTankToDefendOwnBase;

            if ((defenceTank != null) &&
                (minDistanceToAttackEnemyBaseByPlayerIndex[1 - You.Index] < minDistanceToDefendOwnBaseByPlayerIndex[You.Index] + 5))
            {
                if (!moveChosenByTankNumber[defenceTank.Number])
                {
                    actionSet.Actions[defenceTank.Number]      = tankActionsForClosestFriendlyTankToAttackEnemyBase[0];
                    moveChosenByTankNumber[defenceTank.Number] = true;
                }
            }

            // Otherwise choose an enemy tank to attack:
            for (int t = 0; t < Constants.TANKS_PER_PLAYER; t++)
            {
                if ((closestEnemyTankToAttackYourBase != null) && (!moveChosenByTankNumber[t]))
                {
                    // Rather attack an enemy tank in a firefight with own tank..
                    Tank killerTank = You.Tanks[t];
                    AttackClosestEnemyTankToOwnBase(currGameState, killerTank,
                                                    closestEnemyTankToAttackYourBase, actionSet,
                                                    moveChosenByTankNumber);
                }
            }
        }
Пример #14
0
        protected override void ChooseMoves()
        {
            GameState currGameState = Game.Current.CurrentTurn.GameState;

            TankAction[] tankActionsForLiveTank = new TankAction[]
            {
                TankAction.UP,
                TankAction.DOWN,
                TankAction.FIRE,
                TankAction.LEFT,
                TankAction.RIGHT,
                TankAction.NONE
            };
            TankAction[] tankActionsForDeadTank = new TankAction[]
            {
                TankAction.NONE
            };

            TankAction[][] tankActionsPerTank = new TankAction[Constants.TANK_COUNT][];

            foreach (Tank tank in You.Tanks)
            {
                MobileState mobileState = currGameState.GetMobileState(tank.Index);
                if (mobileState.IsActive)
                {
                    // Check if needing to avoid a bullet or shoot a bullet on the path to the base or the tank itself
                    // If so, limit the actions to only those that allow avoiding the bullet

                    tankActionsPerTank[tank.Number] = tankActionsForLiveTank;
                }
                else
                {
                    tankActionsPerTank[tank.Number] = tankActionsForDeadTank;
                }
            }

            double[,] valueEstimates = new double[tankActionsPerTank[0].Length, tankActionsPerTank[1].Length];
            GameStateValueEstimator valueEstimator = new GameStateValueEstimator();

            valueEstimator.Player = You;

            Tank   tank0     = You.Tanks[0];
            Tank   tank1     = You.Tanks[1];
            double bestValue = double.NegativeInfinity;

            TankAction[] bestTankActions = null;

            for (int ta0 = 0; ta0 < tankActionsPerTank[0].Length; ta0++)
            {
                TankAction tankAction0 = tankActionsPerTank[0][ta0];

                for (int ta1 = 0; ta1 < Constants.TANK_COUNT; ta1++)
                {
                    TankAction tankAction1 = tankActionsPerTank[1][ta1];

                    GameState gameStateClone = currGameState.Clone();
                    gameStateClone.Tick++;

                    TankAction[] tankActions = new TankAction[Constants.TANK_COUNT];
                    tankActions[tank0.Index] = tankAction0;
                    tankActions[tank1.Index] = tankAction1;
                    MutableGameStateEngine.ApplyAllActions(gameStateClone as MutableGameState, tankActions);
                    valueEstimator.GameState = gameStateClone;
                    double value = valueEstimator.Evaluate();
                    if (value > bestValue)
                    {
                        bestValue       = value;
                        bestTankActions = tankActions;
                    }
                }
            }
            TankActionSet actionSet = new TankActionSet(YourPlayerIndex, currGameState.Tick);

            if (bestTankActions != null)
            {
                actionSet.Actions[tank0.Number] = bestTankActions[tank0.Number];
                actionSet.Actions[tank1.Number] = bestTankActions[tank1.Number];
            }

            Coordinator.SetBestMoveSoFar(actionSet);
        }