namespace GameCli; /// /// Reward = -distance_to_target /// - λ_v · speed /// - λ_θ · |wrap(angle)| /// - λ_fuel · engine_on /// The angle is wrapped to [-π, π] so a ship that has completed N revolutions /// gets the same upright-penalty as a physically identical pose that hasn't. /// Coefficients are public so training scripts can log/inspect them. /// public static class Reward { public const float LambdaVelocity = 0.10f; public const float LambdaAngle = 0.10f; public const float LambdaFuel = 0.03f; public static float Compute(ShipState s, (float X, float Y) target, int action) { float dx = target.X - s.X; float dy = target.Y - s.Y; float distance = MathF.Sqrt(dx * dx + dy * dy); float speed = MathF.Sqrt(s.VX * s.VX + s.VY * s.VY); float wrapped = MathF.Atan2(MathF.Sin(s.Angle), MathF.Cos(s.Angle)); float engineOn = action == Physics.ActionNoop ? 0f : 1f; return -distance - LambdaVelocity * speed - LambdaAngle * MathF.Abs(wrapped) - LambdaFuel * engineOn; } }