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"); } } }
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 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 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"); } }
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 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 }); }
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); }
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); }
/// <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); }