public TankAction[] GetTankActionsFromTankToAttackTankAtPointAlongDirectionOfMovement( int playerIndex, int tankNumber, Point targetPoint, Direction finalMovementDir, EdgeOffset[] edgeOffsets, bool keepMovingCloserOnFiringLastBullet) { Tank tank = Game.Current.Players[playerIndex].Tanks[tankNumber]; MobileState tankState = GameState.GetMobileState(tank.Index); TurnCalculationCache turnCalcCache = Game.Current.Turns[GameState.Tick].CalculationCache; Cell targetCell = turnCalcCache.CellMatrix[targetPoint]; FiringLineMatrix firingLinesForTanksMatrix = GameState.CalculationCache.FiringLinesForTanksMatrix; AttackTargetDistanceCalculator attackCalculator = new AttackTargetDistanceCalculator( ElementType.TANK, firingLinesForTanksMatrix, GameState.CalculationCache, turnCalcCache); attackCalculator.MovementDirections = new Direction[] { finalMovementDir }; attackCalculator.EdgeOffsets = edgeOffsets; CombinedMovementAndFiringDistanceCalculation combinedDistCalc = attackCalculator.GetShortestAttackDistanceFromCurrentTankPosition(tank.Index, targetCell); return(PathCalculator.GetTanksActionsOnOutgoingShortestAttackPathFromCurrentTankPosition( tank.Index, combinedDistCalc, GameState.CalculationCache, keepMovingCloserOnFiringLastBullet)); /* was: * DirectionalMatrix<DistanceCalculation> incomingDistanceMatrix * = attackCalculator.CalculateMatrixOfShortestDistancesToTargetCell(targetCell); * DistanceCalculation distanceCalc = incomingDistanceMatrix[tankState]; * return PathCalculator.GetTankActionsOnIncomingShortestPath(incomingDistanceMatrix, tankState.Dir, tankState.Pos.X, tankState.Pos.Y, * targetPoint.X, targetPoint.Y, firingLinesForTanksMatrix, keepMovingCloserOnFiringLastBullet); */ }
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; } } } } }
public DirectionalMatrix <DistanceCalculation> GetCustomDistanceMatrixFromTank( int playerIndex, int tankNumber, int ticksWithoutFiring, Rectangle restrictedBoardArea) { Tank tank = Game.Current.Players[playerIndex].Tanks[tankNumber]; TurnCalculationCache turnCalcCache = Game.Current.Turns[GameState.Tick].CalculationCache; // Don't ride over your own base! Base @base = tank.Player.Base; TankLocation tankLoc = turnCalcCache.TankLocationMatrix[@base.Pos]; Rectangle[] tabooAreas = new Rectangle[] { tankLoc.TankBody }; DistanceCalculator distanceCalculator = new DistanceCalculator(); distanceCalculator.Walls = GameState.Walls; distanceCalculator.TankOuterEdgeMatrix = GameState.CalculationCache.TankOuterEdgeMatrix; distanceCalculator.CellMatrix = turnCalcCache.CellMatrix; distanceCalculator.TabooAreas = tabooAreas; distanceCalculator.TicksWithoutFiring = ticksWithoutFiring; distanceCalculator.RestrictedMovementArea = restrictedBoardArea; MobileState tankState = GameState.GetMobileState(tank.Index); DirectionalMatrix <DistanceCalculation> distanceMatrix = distanceCalculator.CalculateShortestDistancesFromTank(ref tankState); return(distanceMatrix); }
public int GetAttackDistanceFromTankToTankAtPointAlongDirectionOfMovement( int playerIndex, int tankNumber, Point targetPoint, Direction finalMovementDir, EdgeOffset[] edgeOffsets) { Tank tank = Game.Current.Players[playerIndex].Tanks[tankNumber]; MobileState tankState = GameState.GetMobileState(tank.Index); TurnCalculationCache turnCalcCache = Game.Current.Turns[GameState.Tick].CalculationCache; Cell targetCell = turnCalcCache.CellMatrix[targetPoint]; FiringLineMatrix firingLinesForTanksMatrix = GameState.CalculationCache.FiringLinesForTanksMatrix; AttackTargetDistanceCalculator attackCalculator = new AttackTargetDistanceCalculator( ElementType.TANK, firingLinesForTanksMatrix, GameState.CalculationCache, turnCalcCache); attackCalculator.MovementDirections = new Direction[] { finalMovementDir }; attackCalculator.EdgeOffsets = edgeOffsets; CombinedMovementAndFiringDistanceCalculation combinedDistCalc = attackCalculator.GetShortestAttackDistanceFromCurrentTankPosition(tank.Index, targetCell); if (combinedDistCalc == null) { return(Constants.UNREACHABLE_DISTANCE); } else { return(combinedDistCalc.TicksTillTargetShot); } /* was: * DirectionalMatrix<DistanceCalculation> incomingDistanceMatrix * = attackCalculator.CalculateMatrixOfShortestDistancesToTargetCell(targetCell); * DistanceCalculation distanceCalc = incomingDistanceMatrix[tankState]; * return distanceCalc.Distance; */ }
public TankAction[] GetActionsToReachLineOfFireDefencePointByIncomingAttackDirection( int playerIndex, int tankNumber, Direction finalIncomingDirectionOfAttack) { Player player = Game.Current.Players[playerIndex]; Tank tank = player.Tanks[tankNumber]; MobileState tankState = GetTankState(playerIndex, tankNumber); if (tankState.IsActive) // TODO: Check if locked in a firefight also { DirectionalMatrix <DistanceCalculation> distanceMatrix = GameState.CalculationCache.GetDistanceMatrixFromTankByTankIndex(tank.Index); Direction defenceDir = finalIncomingDirectionOfAttack.GetOpposite(); if (defenceDir == Direction.NONE) { defenceDir = Direction.RIGHT; } int startPosOffsetFromBase = Constants.TANK_OUTER_EDGE_OFFSET; int endPosOffsetFromBase = startPosOffsetFromBase + MAX_POINTS_TO_TRY_FOR_DEFENCE_POS; for (int offsetSize = startPosOffsetFromBase; offsetSize < endPosOffsetFromBase; offsetSize++) { Point defencePos = player.Base.Pos + defenceDir.GetOffset(offsetSize); DistanceCalculation tankDefenceCalc = distanceMatrix[defenceDir, defencePos]; if (tankDefenceCalc.CodedDistance == 0) { // This defence point can't be reached, try further away continue; } return(PathCalculator.GetTankActionsOnOutgoingShortestPath(distanceMatrix, defenceDir, defencePos)); } } return(new TankAction[0]); }
public DirectionalMatrix <DistanceCalculation> GetDistanceMatrixFromTankByTankIndex(int tankIndex) { if (distanceMatricesFromTankByTankIndex == null) { distanceMatricesFromTankByTankIndex = new DirectionalMatrix <DistanceCalculation> [Constants.TANK_COUNT]; } if (distanceMatricesFromTankByTankIndex[tankIndex] == null) { TurnCalculationCache turnCalcCache = TurnCalculationCache; // Don't ride over your own base! Tank tank = Game.Current.Elements[tankIndex] as Tank; Base @base = tank.Player.Base; TankLocation tankLoc = turnCalcCache.TankLocationMatrix[@base.Pos]; Rectangle[] tabooAreas = new Rectangle[] { tankLoc.TankBody }; DistanceCalculator distanceCalculator = new DistanceCalculator(); distanceCalculator.Walls = GameState.Walls; distanceCalculator.TankOuterEdgeMatrix = TankOuterEdgeMatrix; distanceCalculator.CellMatrix = turnCalcCache.CellMatrix; distanceCalculator.TabooAreas = tabooAreas; MobileState tankState = GameState.GetMobileState(tankIndex); distanceMatricesFromTankByTankIndex[tankIndex] = distanceCalculator.CalculateShortestDistancesFromTank(ref tankState); } return(distanceMatricesFromTankByTankIndex[tankIndex]); }
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 }); }
public DirectionalMatrix <DistanceCalculation> GetIncomingAttackMatrixForTankByTankIndex(int tankIndex) { if (incomingAttackMatrixByTankIndex == null) { incomingAttackMatrixByTankIndex = new DirectionalMatrix <DistanceCalculation> [Constants.TANK_COUNT]; } DirectionalMatrix <DistanceCalculation> incomingAttackMatrix = incomingAttackMatrixByTankIndex[tankIndex]; if (incomingAttackMatrix == null) { MobileState tankState = GameState.GetMobileState(tankIndex); if (!tankState.IsActive) { return(null); } TurnCalculationCache turnCalcCache = TurnCalculationCache; Cell tankCell = turnCalcCache.CellMatrix[tankState.Pos]; AttackTargetDistanceCalculator attackCalculator = new AttackTargetDistanceCalculator( ElementType.TANK, FiringLinesForTanksMatrix, this, turnCalcCache); incomingAttackMatrix = attackCalculator.CalculateMatrixOfShortestDistancesToTargetCell(tankCell); incomingAttackMatrixByTankIndex[tankIndex] = incomingAttackMatrix; } return(incomingAttackMatrix); }
public void DrawBullets(Graphics boardGraphics, GameState gameState) { int dirCount = Enum.GetValues(typeof(Direction)).Length; // Load bullets: Bitmap[] bulletImages = new Bitmap[dirCount]; for (int d = 0; d < dirCount; d++) { Direction dir = (Direction)d; string bulletImageName = String.Format("Bullet_{0}.bmp", dir); bulletImages[d] = GetBitmapByName(bulletImageName); } for (int i = Constants.MIN_BULLET_INDEX; i <= Constants.MAX_BULLET_INDEX; i++) { MobileState bulletState = gameState.GetMobileState(i); if (bulletState.IsActive && bulletState.Dir != Direction.NONE) { Image bulletImage = bulletImages[(byte)bulletState.Dir]; boardGraphics.DrawImage( bulletImage, MagnificationFactor * bulletState.Pos.X, MagnificationFactor * bulletState.Pos.Y, MagnificationFactor, MagnificationFactor); } } }
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); }
public int GetAttackDistanceFromTankToTank(int playerIndex, int tankNumber, int targetTankNumber) { Tank targetTank = Game.Current.Players[1 - playerIndex].Tanks[targetTankNumber]; DirectionalMatrix <DistanceCalculation> distanceMatrix = GameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(targetTank.Index); MobileState tankState = GetTankState(playerIndex, tankNumber); return(distanceMatrix[tankState].Distance); }
public DirectionalMatrix <DistanceCalculation> CalculateDistancesForTank(MobileState tankState) { DistanceCalculator distanceCalculator = new DistanceCalculator(); distanceCalculator.Walls = Board; distanceCalculator.TankOuterEdgeMatrix = TankEdgeMatrix; distanceCalculator.CellMatrix = CellMatrix; return(distanceCalculator.CalculateShortestDistancesFromTank(ref tankState)); }
private void AddBulletSurvivalTactic(Move move, int ticksUntil_p_i_CanFireAgain, int ticksToEscape, List <BulletSurvivalTactic> bulletTactics, Point survivalPoint, Direction dir, int tickOffsetWhenTankCanFireAgain, bool isConfrontingBullet) { MobileState survivalState = new MobileState(survivalPoint, dir, isActive: true); AddBulletSurvivalTactic(move, ticksUntil_p_i_CanFireAgain, ticksToEscape, bulletTactics, survivalState, tickOffsetWhenTankCanFireAgain, isConfrontingBullet); }
public int GetAttackDistanceToEnemyBaseFromTankState(int playerIndex, ref MobileState tankState) { if (tankState.IsActive) { DirectionalMatrix <DistanceCalculation> attackDistanceMatrix = GameState.CalculationCache.GetIncomingDistanceMatrixForBase(1 - playerIndex); return(attackDistanceMatrix[tankState].Distance); } return(Constants.UNREACHABLE_DISTANCE); }
public Mobile(string hostName, string deviceId, string deviceAccessKey, TransportType transportType) : base(hostName, deviceId, deviceAccessKey, transportType) { _state = new MobileState { Id = deviceId, }; _consoleState = null; _consoleTelemetry = null; }
public static TankAction[] GetTankActionsOnIncomingShortestPath( DirectionalMatrix <DistanceCalculation> distances, MobileState attackingTankState, Point targetPos, FiringLineMatrix firingLineMatrix, bool keepMovingCloserOnFiringLastBullet = false) { return(GetTankActionsOnIncomingShortestPath(distances, attackingTankState.Dir, attackingTankState.Pos.X, attackingTankState.Pos.Y, targetPos.X, targetPos.Y, firingLineMatrix, keepMovingCloserOnFiringLastBullet)); }
public T this[MobileState mobileState] { get { return(this[mobileState.Dir, mobileState.Pos]); } set { this[mobileState.Dir, mobileState.Pos] = value; } }
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); } }
public int GetAttackDistanceFromHypotheticalTankStateToTank( MobileState attackTankState, int targetPlayerIndex, int targetTankNumber, EdgeOffset[] edgeOffsets) { Tank targetTank = Game.Current.Players[targetPlayerIndex].Tanks[targetTankNumber]; DirectionalMatrix <DistanceCalculation> distanceMatrix = GameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(targetTank.Index); DistanceCalculation distanceCalc = distanceMatrix[attackTankState]; return(distanceCalc.Distance); }
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); }
public TankAction[] GetTankActionsFromTankToAttackTank(int playerIndex, int tankNumber, int targetTankNumber) { Tank targetTank = Game.Current.Players[1 - playerIndex].Tanks[targetTankNumber]; MobileState targetTankState = GetTankState(1 - playerIndex, targetTankNumber); DirectionalMatrix <DistanceCalculation> distanceMatrix = GameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(targetTank.Index); MobileState attackingTankState = GetTankState(playerIndex, tankNumber); return(PathCalculator.GetTankActionsOnIncomingShortestPath(distanceMatrix, attackingTankState, targetTankState.Pos, GameState.CalculationCache.FiringLinesForTanksMatrix, keepMovingCloserOnFiringLastBullet: false)); }
private void FindShortestPathsWithRestrictionsOnFiring(MobileState tankState, DirectionalMatrix <DistanceCalculation> distanceMatrix) { TwoValuedCircularBuffer <Node> bfsQueue = new TwoValuedCircularBuffer <Node>(CircularBufferCapacityRequired); Node currNode = new Node(ActionType.Moving, tankState.Dir, tankState.Pos); int adjDistance = 1; bool nodesToProcess = true; bool canFire = TicksWithoutFiring < adjDistance; while (nodesToProcess) { // Get each node adjacent to the current node: Node[] adjacentNodes = canFire ? currNode.GetAdjacentOutgoingNodes(TankOuterEdgeMatrix[currNode.X, currNode.Y]) : currNode.GetAdjacentOutgoingNodesWithoutFiring(TankOuterEdgeMatrix[currNode.X, currNode.Y]); foreach (Node adj in adjacentNodes) { if (adj.ActionType == ActionType.Moving) { // Check if the node already has a distance i.e. has it already been expanded? if (distanceMatrix[adj.Dir, adj.X, adj.Y].CodedDistance == 0) { // Set the new shortest distance: distanceMatrix[adj.Dir, adj.X, adj.Y] = new DistanceCalculation(adjDistance, currNode); // Add to the queue to be expanded: bfsQueue.Add(adj, adjDistance); } } else { // A firing node can only be reached in one way (from the moving node on the same cell). // So we don't need to check if it is the shortest path to the node (it must be). // And we aren't interested in it, so no need to store it. // Hence just add it to the queue (it is a "convenience" node to allow a BFS): bfsQueue.Add(adj, adjDistance); } } if (bfsQueue.Size == 0) { nodesToProcess = false; } else { CircularBufferItem <Node> nextItem = bfsQueue.Remove(); currNode = nextItem.Item; adjDistance = nextItem.Value + 1; canFire = adjDistance > TicksWithoutFiring; } } }
public int GetDistanceFromTankToTargetTank( int attackPlayerIndex, int attackTankNumber, int targetPlayerIndex, int targetTankNumber) { Tank attackTank = Game.Current.Players[attackPlayerIndex].Tanks[attackTankNumber]; DirectionalMatrix <DistanceCalculation> distanceMatrix = GameState.CalculationCache.GetDistanceMatrixFromTankByTankIndex(attackTank.Index); Tank defenceTank = Game.Current.Players[targetPlayerIndex].Tanks[targetTankNumber]; MobileState targetTankState = GetTankState(targetPlayerIndex, targetTankNumber); DistanceCalculation distanceCalc = distanceMatrix[targetTankState]; return(distanceCalc.Distance); }
public int GetAttackDistanceOfTankToEnemyBaseFromDirection(int playerIndex, int tankNumber, Direction finalDirectionOfMovement) { MobileState tankState = GetTankState(playerIndex, tankNumber); if (tankState.IsActive) { DirectionalMatrix <DistanceCalculation> attackDistanceMatrix = GameState.CalculationCache.GetIncomingDistanceMatrixForBaseWithFinalDirectionOfMovement( 1 - playerIndex, finalDirectionOfMovement); return(attackDistanceMatrix[tankState].Distance); } return(Constants.UNREACHABLE_DISTANCE); }
// TODO: Use or remove... public static void UpdateBulletSituation(GameState gameState, BulletSituation bulletSituation) { MobileState bulletState = gameState.GetMobileState(bulletSituation.BulletIndex); if (!bulletState.IsActive) { bulletSituation.IsActive = false; bulletSituation.BulletCalculationsByTick = new BulletCalculationByTick[0]; } else { // Re-generate the bullet timeline every turn, since the board may have changed: GenerateBulletTimeline(gameState, bulletSituation); } }
/* TODO: Allow easy comparison across actions... * public int[] GetAttackDistanceOfTankToEnemyBasePerTankAction(int playerIndex, int tankNumber) * { * MobileState tankState = GetTankState(playerIndex, tankNumber); * int[] attackDistancesByTankAction = new int[Constants.TANK_ACTION_COUNT]; * foreach (TankAction tankAction in TankHelper.TankActions) * { * if (tankState.IsActive) * { * * * DirectionalMatrix<DistanceCalculation> attackDistanceMatrix * = GameState.CalculationCache.GetIncomingDistanceMatrixForBase(1 - playerIndex); * return attackDistanceMatrix[tankState].Distance; * } * return Constants.UNREACHABLE_DISTANCE; * } * return attackDistancesByTankAction; * } */ public TankAction[] GetActionsToAttackEnemyBase(int playerIndex, int tankNumber) { MobileState tankState = GetTankState(playerIndex, tankNumber); if (tankState.IsActive) { Base enemyBase = GetEnemyBase(playerIndex); FiringLineMatrix firingLineMatrix = GameState.CalculationCache.FiringLinesForPointsMatrix; DirectionalMatrix <DistanceCalculation> attackDistanceMatrix = GameState.CalculationCache.GetIncomingDistanceMatrixForBase(1 - playerIndex); return(PathCalculator.GetTankActionsOnIncomingShortestPath(attackDistanceMatrix, tankState, enemyBase.Pos, firingLineMatrix, keepMovingCloserOnFiringLastBullet: true)); } return(NoTankActions); }
private void LogActionsTaken() { for (int t = 0; t < Constants.TANK_COUNT; t++) { MobileState tankState = NewGameState.GetMobileState(t); if (tankState.IsActive) { Tank tank = Game.Current.Elements[t] as Tank; TankAction actionTaken = TankActionsTaken[t]; LogDebugMessage("Player {0} tank {1} took action {2} and is now at {3}", tank.PlayerNumber, tank.Number, actionTaken, tankState.Pos); } } DebugHelper.WriteLine(); }
public void DoAfterUpdatingTheState(bool stateUpdateCompletedSuccessfully) { // Find any mobile states unaccounted for, and remove them: for (int i = 0; i < AllMobileStatesAccountedFor.Length; i++) { // Ignore if accounted for: if (AllMobileStatesAccountedFor[i]) { continue; } // Ignore if not active: MobileState mobiState = NewGameState.GetMobileState(i); if (!mobiState.IsActive) { continue; } Element element = Game.Current.Elements[i]; mobiState = mobiState.Kill(); NewGameState.SetMobileState(i, ref mobiState); LogDebugMessage("Deactivating {0} {1} @{2}, which was not accounted for", element.ElementType, i, mobiState.Pos); } // Record the actual actions taken by the players: Turn prevTurn = Game.Current.CurrentTurn.PreviousTurn; if (prevTurn != null) { prevTurn.TankActionsTakenAfterPreviousTurn = TankActionsTaken; } Game.Current.CurrentTurn.GameState = NewGameState; LogActionsTaken(); LogDebugMessage("New game state: {0}", NewGameState); DebugHelper.WriteLine(); CheckGameState(); // Clear the variables, so the callback can be used again without risk of debris from the previous time: TankActionsTaken = null; PrevGameState = null; NewGameState = null; }
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 }); }
public void TestDistanceCalculator(string logFilePath, int repetitions, int smallRepetitions) { SegStateCalculator = new CacheBasedSegmentStateCalculator(HorizSegmentStateMatrix, VertSegmentStateMatrix); TankEdgeMatrix = PerformanceTestHelper.TimeFunction( logFilePath, "Calculate tank edge matrix using TankEdgeCalculator", repetitions, CalculateTankOuterEdgeMatrix); MobileState tankState1 = new MobileState(new Point(20, 6), Direction.UP, isActive: true); DistancesFromTank1 = PerformanceTestHelper.TimeFunctionWithArgument(logFilePath, "Test Distance Calculator for tank 1", smallRepetitions, tankState1, CalculateDistancesForTank); MobileState tankState2 = new MobileState(new Point(56, 6), Direction.UP, isActive: true); DistancesFromTank2 = PerformanceTestHelper.TimeFunctionWithArgument(logFilePath, "Test Distance Calculator for tank 2", smallRepetitions, tankState2, CalculateDistancesForTank); }