private bool Damage(LambdaRobot robot, double damage) { robot.Damage += damage; if (robot.Damage >= robot.MaxDamage) { robot.Damage = robot.MaxDamage; robot.Status = LambdaRobotStatus.Dead; robot.TimeOfDeathGameTurn = Game.TotalTurns; return(true); } return(false); }
private void ApplyRobotAction(LambdaRobot robot, LambdaRobotAction action) { // reduce reload time if any is active if (robot.ReloadCoolDown > 0) { robot.ReloadCoolDown = Math.Max(0.0, robot.ReloadCoolDown - Game.SecondsPerTurn); } // check if any actions need to be applied if (action == null) { // robot didn't respond with an action; consider it dead robot.Status = LambdaRobotStatus.Dead; robot.TimeOfDeathGameTurn = Game.TotalTurns; AddMessage($"{robot.Name} (R{robot.Index}) was disqualified by lack of action"); return; } // update speed and heading robot.TargetSpeed = MinMax(0.0, action.Speed ?? robot.TargetSpeed, robot.MaxSpeed); robot.TargetHeading = NormalizeAngle(action.Heading ?? robot.TargetHeading); // fire missile if requested and possible if ((action.FireMissileHeading.HasValue || action.FireMissileDistance.HasValue) && (robot.ReloadCoolDown == 0.0)) { // update robot state ++robot.TotalMissileFiredCount; robot.ReloadCoolDown = robot.MissileReloadCooldown; // add missile var missile = new LambdaRobotMissile { Id = $"{robot.Id}:M{robot.TotalMissileFiredCount}", RobotId = robot.Id, Status = MissileStatus.Flying, X = robot.X, Y = robot.Y, Speed = robot.MissileVelocity, Heading = NormalizeAngle(action.FireMissileHeading ?? robot.Heading), Range = MinMax(0.0, action.FireMissileDistance ?? robot.MissileRange, robot.MissileRange), DirectHitDamageBonus = robot.MissileDirectHitDamageBonus, NearHitDamageBonus = robot.MissileNearHitDamageBonus, FarHitDamageBonus = robot.MissileFarHitDamageBonus }; Game.Missiles.Add(missile); } }
private async Task <LambdaRobotAction> GetRobotActionAsync(Game game, LambdaRobot robot, string lambdaArn) { var stopwatch = System.Diagnostics.Stopwatch.StartNew(); try { var getActionTask = _lambdaClient.InvokeAsync(new InvokeRequest { Payload = SerializeJson(new LambdaRobotRequest { Command = LambdaRobotCommand.GetAction, Game = new GameInfo { Id = game.Id, BoardWidth = game.BoardWidth, BoardHeight = game.BoardHeight, DirectHitRange = game.DirectHitRange, NearHitRange = game.NearHitRange, FarHitRange = game.FarHitRange, CollisionRange = game.CollisionRange, GameTurn = game.TotalTurns, MaxGameTurns = game.MaxTurns, MaxBuildPoints = game.MaxBuildPoints, SecondsPerTurn = game.SecondsPerTurn, ApiUrl = _gameApiUrl }, Robot = robot }), FunctionName = lambdaArn, InvocationType = InvocationType.RequestResponse }); // check if lambda responds within time limit if (await Task.WhenAny(getActionTask, Task.Delay(TimeSpan.FromSeconds(game.RobotTimeoutSeconds))) != getActionTask) { LogInfo($"Robot {robot.Id} GetAction timed out after {stopwatch.Elapsed.TotalSeconds:N2}s"); return(null); } var response = Encoding.UTF8.GetString(getActionTask.Result.Payload.ToArray()); var result = DeserializeJson <LambdaRobotResponse>(response); LogInfo($"Robot {robot.Id} GetAction responded in {stopwatch.Elapsed.TotalSeconds:N2}s:\n{response}"); return(result.RobotAction); } catch (Exception e) { LogErrorAsWarning(e, $"Robot {robot.Id} GetAction failed (arn: {lambdaArn})"); return(null); } }
public LambdaRobot ScanRobots(LambdaRobot robot, double heading, double resolution) { LambdaRobot result = null; resolution = MinMax(0.01, resolution, robot.RadarMaxResolution); FindRobotsByDistance(robot.X, robot.Y, (other, distance) => { // skip ourselves if (other.Id == robot.Id) { return(true); } // compute relative position var deltaX = other.X - robot.X; var deltaY = other.Y - robot.Y; // check if other robot is beyond scan range if (distance > robot.RadarRange) { // no need to enumerate more return(false); } // check if delta angle is within resolution limit var angle = Math.Atan2(deltaX, deltaY) * 180.0 / Math.PI; if (Math.Abs(NormalizeAngle(heading - angle)) <= resolution) { // found a robot within range and resolution; stop enumerating result = other; return(false); } // enumerate more return(true); }); return(result); }
public Task <LambdaRobotAction> GetRobotAction(LambdaRobot robot) => _getAction(robot);
public Task <LambdaRobotBuild> GetRobotBuild(LambdaRobot robot) => _getBuild(robot);
private void MoveRobot(LambdaRobot robot) { // compute new heading if (robot.Heading != robot.TargetHeading) { if (robot.Speed <= robot.MaxTurnSpeed) { robot.Heading = robot.TargetHeading; } else { robot.TargetSpeed = 0; robot.Heading = robot.TargetHeading; AddMessage($"{robot.Name} (R{robot.Index}) stopped by sudden turn"); } } // compute new speed var oldSpeed = robot.Speed; if (robot.TargetSpeed > robot.Speed) { robot.Speed = Math.Min(robot.TargetSpeed, robot.Speed + robot.Acceleration * Game.SecondsPerTurn); } else if (robot.TargetSpeed < robot.Speed) { robot.Speed = Math.Max(robot.TargetSpeed, robot.Speed - robot.Deceleration * Game.SecondsPerTurn); } var effectiveSpeed = (robot.Speed + oldSpeed) / 2.0; // move robot bool collision; Move( robot.X, robot.Y, robot.TotalTravelDistance, effectiveSpeed, robot.Heading, double.MaxValue, out robot.X, out robot.Y, out robot.TotalTravelDistance, out collision ); // check for collision with wall if (collision) { robot.Speed = 0.0; robot.TargetSpeed = 0.0; ++robot.TotalCollisions; if (Damage(robot, robot.CollisionDamage)) { AddMessage($"{robot.Name} (R{robot.Index}) was destroyed by wall collision"); return; } else { AddMessage($"{robot.Name} (R{robot.Index}) received {robot.CollisionDamage:N0} damage by wall collision"); } } // check if robot collides with any other robot FindRobotsByDistance(robot.X, robot.Y, (other, distance) => { if ((other.Id != robot.Id) && (distance < Game.CollisionRange)) { robot.Speed = 0.0; robot.TargetSpeed = 0.0; ++robot.TotalCollisions; if (Damage(robot, robot.CollisionDamage)) { AddMessage($"{robot.Name} (R{robot.Index}) was destroyed by collision with {other.Name}"); } else { AddMessage($"{robot.Name} (R{robot.Index}) was damaged {robot.CollisionDamage:N0} by collision with {other.Name} (R{other.Index})"); } } // keep looking for more collisions unless robot is dead or nearest robot is out of range return((robot.Status == LambdaRobotStatus.Alive) && (distance < Game.CollisionRange)); }); }