コード例 #1
0
        public override void ChooseMovesAsPBar(MoveResult moveResult)
        {
            Move move = moveResult.Move;

            LogDebugMessage("*** ANTAGONIST (PBar = {0}) ***", move.pBar);
            LogDebugMessage("Slack: {0}", moveResult.Slack);

            double valueOfMove = ScenarioValueFunctions.ClearRunAtBaseScenarioValueFunction.Evaluate(moveResult.Slack);

            LogDebugMessage("Value of move: {0}", valueOfMove);

            // Defend against an enemy attack on your base:
            for (int tankNumber = 0; tankNumber < Constants.TANKS_PER_PLAYER; tankNumber++)
            {
                LogDebugMessage("Tank number: {0}", tankNumber);
                TankActionRecommendation recommendation = moveResult.GetRecommendedTankActionsByPlayerAndTankNumber(move.pBar, tankNumber);
                if (recommendation.IsAMoveRecommended)
                {
                    TankSituation tankSituation
                        = GameSituation.GetTankSituationByPlayerAndTankNumber(move.pBar, tankNumber);
                    TankAction recommendedTankAction = recommendation.RecommendedTankAction;
                    LogDebugMessage("Recommended tank action: {0}", recommendedTankAction);

                    tankSituation.AdjustTankActionValue(recommendedTankAction, valueOfMove);
                }
                else
                {
                    LogDebugMessage("No moves recommended");
                }
            }
        }
コード例 #2
0
        public override MoveResult EvaluateLeafNodeMove(Move move)
        {
            MobileState tankState_i = GetTankState_i(move);
            MobileState tankState_j = GetTankState_j(move);

            // Both tanks must be alive:
            if (!(tankState_i.IsActive && tankState_j.IsActive))
            {
                return(new MoveResult(move)
                {
                    EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
                });
            }

            TankSituation tankSit_i = GetTankSituation(move.p, move.i);
            TankSituation tankSit_j = GetTankSituation(move.pBar, move.j);
            int           ticksUntilFriendlyTankCanFireAgain = tankSit_i.ExpectedNextTickWhenTankCanFireAgain - GameState.Tick;
            int           ticksUntilEnemyTankCanFireAgain    = tankSit_j.ExpectedNextTickWhenTankCanFireAgain - GameState.Tick;

            if (ticksUntilEnemyTankCanFireAgain <= 0 || ticksUntilFriendlyTankCanFireAgain > 0)
            {
                return(new MoveResult(move)
                {
                    EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
                });
            }

            int attackDistance = GetAttackDistanceFromTankToTank(move.p, move.i, move.j);

            if (attackDistance - ticksUntilEnemyTankCanFireAgain > 5)
            {
                return(new MoveResult(move)
                {
                    EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
                });
            }

            foreach (TankActionSituation tankActSit in tankSit_i.TankActionSituationsPerTankAction)
            {
                int A_p_i = GetAttackDistanceFromHypotheticalTankStateToTank(
                    tankActSit.NewTankState, move.pBar, move.j, TankHelper.EdgeOffsets);
                int    slack       = A_p_i - ticksUntilEnemyTankCanFireAgain;
                double attackValue = ScenarioValueFunctions.AttackDisarmedEnemyTankSlackUntilRearmedFunction.Evaluate(slack);
                tankActSit.Value += attackValue;
            }

            // Convert a good attacking position into killing the enemy tank, by weighting the attacking action more highly:
            TankAction[] attackActions = GetTankActionsFromTankToAttackTank(move.p, move.i, move.j);
            if (attackActions.Length > 0)
            {
                TankAction attackAction      = attackActions[0];
                double     attackActionValue = ScenarioValueFunctions.AttackDisarmedEnemyTankAttackActionFunction.Evaluate(attackDistance);
                tankSit_i.TankActionSituationsPerTankAction[(int)attackAction].Value += attackActionValue;
            }

            return(new MoveResult(move)
            {
                EvaluationOutcome = ScenarioEvaluationOutcome.Possible
            });
        }
コード例 #3
0
        public static BulletSituation CreateBulletSituation(GameState gameState,
                                                            TankSituation tankSituation, int bulletIndex, int bulletId)
        {
            MobileState     bulletState = gameState.GetMobileState(bulletIndex);
            MobileState     tankState   = gameState.GetMobileState(bulletIndex - Constants.MIN_BULLET_INDEX);
            BulletSituation bulletSituation;

            if (!bulletState.IsActive)
            {
                bulletSituation = new BulletSituation(tankSituation, bulletIndex, bulletId)
                {
                    IsActive = false,
                    TickOffsetWhenTankCanFireAgain = 0,
                    TankStateAtTimeOfFiring        = tankState,
                    BulletStateAtTimeOfFiring      = bulletState,
                    BulletCalculationsByTick       = new BulletCalculationByTick[0]
                };
                return(bulletSituation);
            }

            // Assume the bullet has just been fired (not correct, but it shouldn't matter):
            bulletSituation = new BulletSituation(tankSituation, bulletIndex, bulletId)
            {
                TickFired = gameState.Tick,
                TankStateAtTimeOfFiring   = tankState,
                BulletStateAtTimeOfFiring = bulletState,
                IsActive = true
            };
            GenerateBulletTimeline(gameState, bulletSituation);
            return(bulletSituation);
        }
コード例 #4
0
        public override void ChooseMovesAsP(MoveResult moveResult)
        {
            Move move = moveResult.Move;

            LogDebugMessage("*** PROTAGONIST (P = {0}) ***", move.p);
            LogDebugMessage("Slack: {0}", moveResult.Slack);

            double valueOfMove = ScenarioValueFunctions.ClearRunAtBaseScenarioValueFunction.Evaluate(moveResult.Slack);

            LogDebugMessage("Value of move: {0}", valueOfMove);

            // Attack the enemy base:
            LogDebugMessage("Tank number: {0}", move.i);
            TankActionRecommendation recommendation
                = moveResult.GetRecommendedTankActionsByPlayerAndTankNumber(move.p, move.i);

            if (recommendation.IsAMoveRecommended)
            {
                TankSituation tankSituation         = GameSituation.GetTankSituationByPlayerAndTankNumber(move.p, move.i);
                TankAction    recommendedTankAction = recommendation.RecommendedTankAction;
                LogDebugMessage("Recommended tank action: {0}", recommendedTankAction);

                tankSituation.AdjustTankActionValue(recommendedTankAction, valueOfMove);
            }
            else
            {
                LogDebugMessage("No moves recommended");
            }
        }
コード例 #5
0
        public override MoveResult EvaluateLeafNodeMove(Move move)
        {
            MobileState   tankState_i = GetTankState_i(move);
            TankSituation tankSit_i   = GetTankSituation(move.p, move.i);

            if (tankSit_i.IsLockedDown || !tankState_i.IsActive)
            {
                return(new MoveResult(move)
                {
                    EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
                });
            }

            foreach (TankActionSituation tankActSit in tankSit_i.TankActionSituationsPerTankAction)
            {
                MobileState newTankState          = tankActSit.NewTankState;
                int         attackDistToEnemyBase = GetAttackDistanceToEnemyBaseFromTankState(YourPlayerIndex, ref newTankState);
                if (tankActSit.TankAction == TankAction.FIRE && tankActSit.IsAdjacentWallRemoved)
                {
                    Point       adjacentPos            = tankActSit.NewTankState.Pos + tankActSit.NewTankState.Dir.GetOffset();
                    MobileState adjacentState          = new MobileState(adjacentPos, tankActSit.NewTankState.Dir, isActive: true);
                    int         attackDistToEnemyBase2 = GetAttackDistanceToEnemyBaseFromTankState(YourPlayerIndex, ref adjacentState) + 1;
                    if (attackDistToEnemyBase2 < attackDistToEnemyBase)
                    {
                        attackDistToEnemyBase = attackDistToEnemyBase2;
                    }
                }
                double value = ScenarioValueFunctions.AttackEnemyBaseFunction.Evaluate(attackDistToEnemyBase);
                tankActSit.Value += value;
            }

            // Convert a good position into killing the enemy base, by weighting the attacking action more highly:
            int attackDistance = GetAttackDistanceToEnemyBaseFromTankState(move.i, ref tankState_i);

            TankAction[] attackActions = GetActionsToAttackEnemyBase(move.p, move.i);
            if (attackActions.Length > 0)
            {
                TankAction attackAction      = attackActions[0];
                double     attackActionValue = ScenarioValueFunctions.AttackEnemyBaseAttackActionFunction.Evaluate(attackDistance);
                tankSit_i.TankActionSituationsPerTankAction[(int)attackAction].Value += attackActionValue;
            }

            return(new MoveResult(move)
            {
                EvaluationOutcome = ScenarioEvaluationOutcome.Possible
            });
        }
コード例 #6
0
        public override MoveResult EvaluateLeafNodeMove(Move move)
        {
            TankSituation tankSituation = GetTankSituation(move.p, move.i);
            int           ticksUntil_p_i_CanFireAgain = tankSituation.ExpectedNextTickWhenTankCanFireAgain - GameState.Tick;
            int           worstSlack = -Constants.UNREACHABLE_DISTANCE;
            TankAction    tankActionToAddressWorstSlack = TankAction.NONE;
            bool          isScenarioApplicable          = false;

            foreach (BulletSituation bulletSituation in GameSituation.BulletSituationsByTankIndex)
            {
                if (bulletSituation == null)
                {
                    continue;
                }

                EvaluateBulletSituation(move, tankSituation, bulletSituation,
                                        ticksUntil_p_i_CanFireAgain, ref worstSlack, ref tankActionToAddressWorstSlack, ref isScenarioApplicable);
            }

            if (isScenarioApplicable)
            {
                MoveResult moveResult = new MoveResult(move)
                {
                    Slack = worstSlack,
                    EvaluationOutcome
                        = worstSlack < -10
                        ? ScenarioEvaluationOutcome.Possible
                        : (worstSlack <= 0
                          ? ScenarioEvaluationOutcome.Close
                          : ScenarioEvaluationOutcome.Current
                           )
                };
                moveResult.RecommendedTankActionsByTankIndex[tankSituation.Tank.Index]
                    = new TankActionRecommendation {
                    IsAMoveRecommended = true, RecommendedTankAction = tankActionToAddressWorstSlack
                    };
                return(moveResult);
            }
            else
            {
                return(new MoveResult(move)
                {
                    EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
                });
            }
        }
        public override MoveResult EvaluateLeafNodeMove(Move move)
        {
            MobileState tankState_i = GetTankState_i(move);
            MobileState tankState_j = GetTankState_j(move);

            // Both tanks must be alive:
            if (!(tankState_i.IsActive && tankState_j.IsActive))
            {
                return(new MoveResult(move)
                {
                    EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
                });
            }

            TankSituation tankSit_i = GetTankSituation(move.p, move.i);

            // Weight for distance to attack enemy over the long haul versus having the upper hand in the encounter in the short term:
            foreach (TankActionSituation tankActSit in tankSit_i.TankActionSituationsPerTankAction)
            {
                int A_p_i = GetAttackDistanceFromHypotheticalTankStateToTank(
                    tankActSit.NewTankState, move.pBar, move.j, TankHelper.EdgeOffsets);
                int A_pBar_j = GetAttackDistanceFromTankToHypotheticalTankAtPoint(
                    move.pBar, move.j, tankActSit.NewTankState.Pos, TankHelper.EdgeOffsets);
                int    attackDiffSlack = A_p_i - A_pBar_j;
                double attackValue     = ScenarioValueFunctions.GrappleWithEnemyTankAttackFunction.Evaluate(A_p_i);
                double grappleValue    = ScenarioValueFunctions.GrappleWithEnemyTankAttackDiffFunction.Evaluate(attackDiffSlack);
                tankActSit.Value += attackValue + grappleValue;
            }

            // Convert a good attacking position into killing the enemy tank, by weighting the attacking action more highly:
            int attackDistance = GetAttackDistanceFromTankToTank(move.p, move.i, move.j);

            TankAction[] attackActions = GetTankActionsFromTankToAttackTank(move.p, move.i, move.j);
            if (attackActions.Length > 0)
            {
                TankAction attackAction      = attackActions[0];
                double     attackActionValue = ScenarioValueFunctions.GrappleWithEnemyTankAttackActionFunction.Evaluate(attackDistance);
                tankSit_i.TankActionSituationsPerTankAction[(int)attackAction].Value += attackActionValue;
            }

            return(new MoveResult(move)
            {
                EvaluationOutcome = ScenarioEvaluationOutcome.Possible
            });
        }
        public override void ChooseMovesAsP(MoveResult moveResult)
        {
            Move        move        = moveResult.Move;
            MobileState tankState_j = GetTankState_j(move);

            TankAction[] attackActions = GetTankActionsFromTankToAttackTankAtPointAlongDirectionOfMovement(
                move.p, move.i, tankState_j.Pos, move.dir1, TankHelper.EdgeOffsets,
                keepMovingCloserOnFiringLastBullet: false);
            if (attackActions.Length > 0)
            {
                int attackDistance = GetAttackDistanceFromTankToTankAtPointAlongDirectionOfMovement(
                    move.p, move.i, tankState_j.Pos, move.dir1, TankHelper.EdgeOffsets);
                TankAction    attackAction      = attackActions[0];
                double        attackActionValue = ScenarioValueFunctions.AttackLockedDownEnemyTankFunction.Evaluate(attackDistance);
                TankSituation tankSit_i         = GetTankSituation(move.p, move.i);
                tankSit_i.TankActionSituationsPerTankAction[(int)attackAction].Value += attackActionValue;
            }
        }
        public override MoveResult EvaluateLeafNodeMove(Move move)
        {
            MobileState tankState_i = GetTankState_i(move);
            MobileState tankState_j = GetTankState_j(move);

            // Both tanks must be alive:
            if (!(tankState_i.IsActive && tankState_j.IsActive))
            {
                return(new MoveResult(move)
                {
                    EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
                });
            }

            TankSituation tankSit_i = GetTankSituation(move.p, move.i);
            TankSituation tankSit_j = GetTankSituation(move.pBar, move.j);

            if (tankSit_i.IsLockedDown || !tankSit_j.IsLockedDown)
            {
                return(new MoveResult(move)
                {
                    EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
                });
            }

            if (move.dir1 == tankSit_j.DirectionOfAttackForLockDown.GetOpposite())
            {
                return(new MoveResult(move)
                {
                    EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
                });
            }

            int attackDistance = GetAttackDistanceFromTankToTankAtPointAlongDirectionOfMovement(
                move.p, move.i, tankState_j.Pos, move.dir1, TankHelper.EdgeOffsets);

            return(new MoveResult(move)
            {
                EvaluationOutcome = ScenarioEvaluationOutcome.Current,
                Slack = attackDistance
            });
        }
コード例 #10
0
        public bool IsValid(Move move)
        {
            // Exclude directions of attack which aren't possible:
            if (!Game.Current.Players[move.pBar].Base.GetPossibleIncomingAttackDirections().Contains(move.dir1))
            {
                return(false);
            }

            if (!GetTankState_i(move).IsActive)
            {
                return(false);
            }

            TankSituation tankSit_i = GetTankSituation(move.p, move.i);

            if (tankSit_i.IsInLineOfFire || tankSit_i.IsLockedDown || tankSit_i.IsShutIntoQuadrant)
            {
                return(false);
            }
            return(true);
        }
コード例 #11
0
        private void EvaluateBulletSituation(Move move, TankSituation tankSituation, BulletSituation bulletSituation,
                                             int ticksUntil_p_i_CanFireAgain, ref int worstSlack, ref TankAction tankActionToAddressWorstSlack,
                                             ref bool isScenarioApplicable)
        {
            bool       isScenarioApplicableForThisBulletSituation = false;
            int        bestSlackForThisBulletSituation            = Constants.UNREACHABLE_DISTANCE;
            TankAction bestTankActionForThisBulletSituation       = TankAction.NONE;

            foreach (BulletCalculationByTick bulletCalc in bulletSituation.BulletCalculationsByTick)
            {
                if (!bulletCalc.AreTanksAtRisk)
                {
                    continue;
                }
                int ticksToEscape = bulletCalc.Tick - GameState.Tick;
                if (ticksToEscape < 0)
                {
                    continue;
                }

                // Are you in the firing line:
                if (bulletCalc.TankCentrePointsThatDie.ContainsPoint(tankSituation.TankState.Pos))
                {
                    List <BulletSurvivalTactic> bulletTactics = new List <BulletSurvivalTactic>();
                    isScenarioApplicableForThisBulletSituation = true;

                    // Suppose the bullet just misses the tank on turn n, with t ticks to escape...
                    int closestEscapeTick  = ticksToEscape * 2 / 3;  // 2t - n + 1 = 2n + 1 so 3n = 2t
                    int furthestEscapeTick = 2 * ticksToEscape + 1;  // 2t + n + 1 = 2n so n = 2t + 1

                    for (int tk = closestEscapeTick; tk <= furthestEscapeTick; tk++)
                    {
                        if (tk >= bulletSituation.BulletCalculationsByTick.Length)
                        {
                            break;
                        }
                        BulletCalculationByTick bulletCalc_tk = bulletSituation.BulletCalculationsByTick[tk];
                        if (!bulletCalc_tk.AreTanksAtRisk)
                        {
                            break;
                        }
                        ticksToEscape = bulletCalc_tk.Tick - GameState.Tick;

                        // Fire at the bullet:
                        foreach (MobileState headOnState in bulletCalc_tk.ClosestTankStatesThatCanShootBulletHeadOn)
                        {
                            // Move into position to confront the bullet:
                            AddBulletSurvivalTactic(move, ticksUntil_p_i_CanFireAgain, ticksToEscape,
                                                    bulletTactics, headOnState, bulletSituation.TickOffsetWhenTankCanFireAgain,
                                                    isConfrontingBullet: true);
                        }

                        // Other moves to dodge the bullet:
                        foreach (Point survivalPoint in bulletCalc_tk.ClosestTankCentrePointsThatSurviveClockwise)
                        {
                            Direction dir = bulletSituation.BulletMovementDir.Clockwise();
                            AddBulletSurvivalTactic(move, ticksUntil_p_i_CanFireAgain, ticksToEscape,
                                                    bulletTactics, survivalPoint, dir, bulletSituation.TickOffsetWhenTankCanFireAgain,
                                                    isConfrontingBullet: false);
                        }

                        foreach (Point survivalPoint in bulletCalc_tk.ClosestTankCentrePointsThatSurviveAntiClockwise)
                        {
                            Direction dir = bulletSituation.BulletMovementDir.AntiClockwise();
                            AddBulletSurvivalTactic(move, ticksUntil_p_i_CanFireAgain, ticksToEscape,
                                                    bulletTactics, survivalPoint, dir, bulletSituation.TickOffsetWhenTankCanFireAgain,
                                                    isConfrontingBullet: false);
                        }
                    }

                    var bulletTacticsByTankAction = bulletTactics.GroupBy(tactic => tactic.InitialTankAction);
                    foreach (var grouping in bulletTacticsByTankAction)
                    {
                        TankAction           tankAction = grouping.Key;
                        BulletSurvivalTactic bestTacticForTankAction = grouping.OrderBy(tactic => tactic.Value).First();
                        tankSituation.TankActionSituationsPerTankAction[(int)tankAction].Value
                            += bestTacticForTankAction.Value;
                        // Note that this is a combination of the slack value and the disarmament value
                        if (bestTacticForTankAction.Slack < bestSlackForThisBulletSituation)
                        {
                            bestSlackForThisBulletSituation      = bestTacticForTankAction.Slack;
                            bestTankActionForThisBulletSituation = tankAction;
                        }
                    }

                    // We've made our escape plans. Don't continue iterating through bullet calculations...
                    break;
                }

                // If any of the danger points are adjacent to your current point,
                // prevent moving into the bullet by add a large negative value to the move,
                // with the size of the value depending on the slack...
                foreach (TankActionSituation tankActionSituation in tankSituation.TankActionSituationsPerTankAction)
                {
                    if (bulletCalc.TankCentrePointsThatDie.ContainsPoint(tankActionSituation.NewTankState.Pos))
                    {
                        // Calculate the slack values and tank action value adjustment...
                        double value = ScenarioValueFunctions.AvoidWalkingIntoABulletFunction.Evaluate(ticksToEscape);
                        tankActionSituation.Value += value;
                    }
                }
            }

            if (isScenarioApplicableForThisBulletSituation)
            {
                if (bestSlackForThisBulletSituation > worstSlack)
                {
                    worstSlack = bestSlackForThisBulletSituation;
                    tankActionToAddressWorstSlack = bestTankActionForThisBulletSituation;
                }
                isScenarioApplicable = true;
            }
        }
        private MoveResult CheckForLockDown(Move move, ref MobileState tankState_i, ref MobileState tankState_j,
                                            Direction attackDir, int distanceBetweenCentrePoints)
        {
            if (distanceBetweenCentrePoints <= LOCKDOWN_FIRING_THRESHOLD)
            {
                if (tankState_i.Dir == attackDir)
                {
                    // Check if there are walls between the tanks:
                    bool wallFound = false;

                    for (int offset = Constants.TANK_OUTER_EDGE_OFFSET;
                         offset <= distanceBetweenCentrePoints - Constants.TANK_OUTER_EDGE_OFFSET;
                         offset++)
                    {
                        Point wallPoint = tankState_i.Pos + attackDir.GetOffset(offset);
                        if (GameState.Walls[wallPoint])
                        {
                            wallFound = true;
                            break;
                        }
                    }

                    if (!wallFound)
                    {
                        TankSituation tankSit_i = GetTankSituation(move.p, move.i);
                        if (tankSit_i.ExpectedNextTickWhenTankCanFireAgain > GameState.Tick)
                        {
                            return(new MoveResult(move)
                            {
                                EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
                            });
                        }

                        tankSit_i.IsLockedDown = true;
                        tankSit_i.DirectionOfAttackForLockDown = attackDir;
                        TankSituation tankSit_j = GetTankSituation(move.pBar, move.j);
                        tankSit_j.IsLockedDown = true;
                        tankSit_j.DirectionOfAttackForLockDown = attackDir.GetOpposite();
                        tankSit_i.TankActionSituationsPerTankAction[(int)TankAction.FIRE].Value = ScenarioValueFunctions.VALUE_OF_A_TANK;

                        if (tankState_j.Dir == attackDir.GetOpposite())
                        {
                            tankSit_j.TankActionSituationsPerTankAction[(int)TankAction.FIRE].Value = ScenarioValueFunctions.VALUE_OF_A_TANK;
                        }
                        else
                        {
                            TankAction tankAction_j = attackDir.GetOpposite().ToTankAction();
                            tankSit_j.TankActionSituationsPerTankAction[(int)tankAction_j].Value = ScenarioValueFunctions.VALUE_OF_A_TANK;
                        }

                        return(new MoveResult(move)
                        {
                            EvaluationOutcome = ScenarioEvaluationOutcome.Current
                        });
                    }
                }
            }
            return(new MoveResult(move)
            {
                EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
            });
        }
        public bool IsValid(Move move)
        {
            // All tanks except t_pBar_j must be alive still:
            MobileState tankState_i    = GetTankState_i(move);
            MobileState tankState_iBar = GetTankState_iBar(move);
            MobileState tankState_j    = GetTankState_j(move);

            if (!(tankState_i.IsActive && tankState_iBar.IsActive && tankState_j.IsActive))
            {
                return(false);
            }

            TankSituation tankSit_i    = GetTankSituation(move.p, move.i);
            TankSituation tankSit_iBar = GetTankSituation(move.p, move.iBar);
            TankSituation tankSit_j    = GetTankSituation(move.pBar, move.j);

            if (tankSit_iBar.IsLockedDown || tankSit_iBar.IsShutIntoQuadrant ||
                tankSit_iBar.IsTankActionDetermined ||  // unless this is just due to being locked down already?
                tankSit_i.IsTankActionDetermined     // unless this is just due to being locked down already?
                )
            {
                return(false);
            }

            if (move.dir2 == move.dir1)
            {
                return(false);
            }

            if (move.dir3 == move.dir1.GetOpposite())
            {
                return(false);
            }

            // Check that directions are compatible with tank positions on the board:
            BoundaryProximity boundaryProximity_j = tankState_j.Pos.GetClosestBoundary(GameState.Walls.BoardBoundary);

            if (boundaryProximity_j.DistanceToBoundary <= Constants.SEGMENT_SIZE + Constants.TANK_OUTER_EDGE_OFFSET)
            {
                Direction invalidMovementDir = boundaryProximity_j.BoundaryDir.GetOpposite();
                if (move.dir1 == invalidMovementDir)
                {
                    return(false);
                }
                if (move.dir2 == invalidMovementDir)
                {
                    return(false);
                }
            }

            BoundaryProximity boundaryProximity_i = tankState_i.Pos.GetClosestBoundary(GameState.Walls.BoardBoundary);

            if (boundaryProximity_i.DistanceToBoundary <= Constants.SEGMENT_SIZE + Constants.TANK_OUTER_EDGE_OFFSET)
            {
                Direction invalidMovementDir = boundaryProximity_i.BoundaryDir.GetOpposite();
                if (move.dir3 == invalidMovementDir)
                {
                    return(false);
                }
            }

            return(true);
        }
        public override MoveResult EvaluateLeafNodeMove(Move move)
        {
            TankSituation tankSituation = GetTankSituation(move.p, move.i);
            MobileState   t_p_i         = GetTankState_i(move);
            MobileState   t_p_iBar      = GetTankState_iBar(move);

            // Not valid if either tank is dead:
            if (!(t_p_i.IsActive && t_p_iBar.IsActive))
            {
                return(new MoveResult(move)
                {
                    EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
                });
            }

            int slackX = Math.Abs(t_p_i.Pos.X - t_p_iBar.Pos.X);
            int slackY = Math.Abs(t_p_i.Pos.Y - t_p_iBar.Pos.Y);
            int slack  = Math.Max(slackX, slackY);

            MoveResult moveResult = new MoveResult(move)
            {
                Slack = slack
            };

            if (slack > 5)
            {
                moveResult.EvaluationOutcome = ScenarioEvaluationOutcome.Possible;
            }
            else
            if (slack <= 2)
            {
                moveResult.EvaluationOutcome = ScenarioEvaluationOutcome.Current;
            }
            else
            {
                moveResult.EvaluationOutcome = ScenarioEvaluationOutcome.Close;
            }

            Direction dirTowards_iBar
                = slackX <= slackY
                ? t_p_i.Pos.GetVerticalDirectionToPoint(t_p_iBar.Pos)
                : t_p_i.Pos.GetHorizontalDirectionToPoint(t_p_iBar.Pos);

            Direction dirAwayFrom_iBar = dirTowards_iBar.GetOpposite();

            TankSituation tankSit_i          = GetTankSituation(move.p, move.i);
            TankSituation tankSit_iBar       = GetTankSituation(move.p, move.iBar);
            double        bestMoveValue_i    = tankSit_i.GetBestTankActionValue();
            double        bestMoveValue_iBar = tankSit_iBar.GetBestTankActionValue();

            bool does_i_have_best_move
                = (bestMoveValue_i == bestMoveValue_iBar)
                ? (move.i < move.iBar)
                : (bestMoveValue_i > bestMoveValue_iBar);

            /*
             * if (does_i_have_best_move)
             * {
             *  return new MoveResult(move)
             *  {
             *      EvaluationOutcome = ScenarioEvaluationOutcome.Invalid
             *  };
             * }
             */

            foreach (Direction dir in BoardHelper.AllRealDirections)
            {
                int slackOffset = 0;
                if (dir == dirTowards_iBar)
                {
                    slackOffset = -1;
                }
                if (dir == dirAwayFrom_iBar)
                {
                    slackOffset = 1;
                }
                Point        point       = t_p_i.Pos + dir.GetOffset();
                Cell         cell        = TurnCalculationCache.CellMatrix[point];
                TankAction[] tankActions = GetTankActionsToMoveToPoint(move.p, move.i, dir, point);
                if (tankActions.Length > 0)
                {
                    int    adjustedSlack = slack + slackOffset;
                    double value         = ScenarioValueFunctions.AvoidBlockingFriendlyTankFunction.Evaluate(adjustedSlack);
                    if (slack <= 8 && (dirTowards_iBar == Direction.LEFT || dirTowards_iBar == Direction.DOWN))
                    {
                        if (dir == dirTowards_iBar)
                        {
                            value -= 100000;
                        }
                        if (dir == dirAwayFrom_iBar)
                        {
                            value += 100000;
                        }
                    }
                    TankAction tankAction = tankActions[0];
                    tankSituation.TankActionSituationsPerTankAction[(int)tankAction].Value += value;
                }
            }

            return(moveResult);
        }
コード例 #15
0
        /// <summary>
        /// Create a hypothetical bullet situation for firing a bullet
        /// </summary>
        /// <param name="gameState"></param>
        /// <param name="hypotheticalTankSituation">
        /// This must be a hypothetical tank situation in a hypothetical game situation.
        /// It may not be the real situation, otherwise actual data will get overwritten.
        /// </param>
        /// <param name="tickFired"></param>
        /// <param name="bulletIndex"></param>
        /// <param name="bulletId"></param>
        /// <returns></returns>
        public static BulletSituation CreateHypotheticalBulletSituationForNewlyFiredBullet(GameState gameState,
                                                                                           TankSituation hypotheticalTankSituation, int tickFired, int bulletIndex, int bulletId)
        {
            MobileState bulletState = gameState.GetMobileState(bulletIndex);
            MobileState tankState   = gameState.GetMobileState(bulletIndex - Constants.MIN_BULLET_INDEX);

            BulletSituation bulletSituation = new BulletSituation(hypotheticalTankSituation, bulletIndex, bulletId)
            {
                TickFired = tickFired,
                TankStateAtTimeOfFiring   = tankState,
                BulletStateAtTimeOfFiring = bulletState,
                IsActive = true
            };

            GenerateBulletTimeline(gameState, bulletSituation);

            return(bulletSituation);
        }