-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscore_function.cpp
More file actions
97 lines (81 loc) · 3.9 KB
/
Copy pathscore_function.cpp
File metadata and controls
97 lines (81 loc) · 3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include "score_function.h"
#include <algorithm>
#include <cassert>
#include <cmath>
#include "mars_lander_rules.h"
#include "physics.h"
using namespace std;
/**
* Scoring tiers (higher is better, max 300 points):
*
* 0-100: didn't reach the landing zone.
* Distance-based: linear down to 67 within the first third of the max
* terrain distance, quadratic falloff to 0 beyond that. Speeds above
* 100 m/s cost an extra 0.1 per m/s.
*
* 100-200: touched down in the zone, but broke a landing rule.
* Combined penalty sqrt(h_pen^2 + v_pen^2) + 1.5 * |rotation| for the
* speed/attitude violations, mapped to 100 + 100 * exp(-penalty / 30) so
* the score decays smoothly from 200 towards 100.
*
* 200-300: safe landing.
* 200 + fuel bonus 100 * fuel_left / fuel_start.
*/
double computeScore(const Spacecraft &final_state,
const Spacecraft &init_status,
const DistanceCalculator &distance_calc) {
// Range 0-100: crashed somewhere (didn't hit landing area)
if (!final_state.grounded_in_landing_zone) {
// Use crash-point surface walk when segment is known (accurate),
// fall back to general projection for in-flight scoring states
double distance = distance_calc.computeDistanceToLandingZone(final_state.x,
final_state.y,
final_state.collision_segment);
double ratio = distance / distance_calc.getMaxDistance();
double score = 0.0;
if (ratio <= 0.33) {
// Linear: 100 at ratio=0, 67 at ratio=0.33
score = 100.0 - 100.0 * ratio;
} else {
// Quadratic: 67 at ratio=0.33, 0 at ratio=1.0
double shifted = (ratio - 0.33) / 0.67;
score = 67.0 * (1.0 - shifted * shifted);
}
score = std::clamp(score, 0.0, 100.0);
double current_speed = std::sqrt(final_state.h_speed * final_state.h_speed +
final_state.v_speed * final_state.v_speed);
// High speeds are bad, they decrease maneuvrability
double speed_pen = 0.1 * std::max(current_speed - 100.0, 0.0);
score -= speed_pen;
return score;
}
// Range 100-200: reached the landing zone but violated at least one game landing rule.
if (!MarsLanderRules::hasSafeLandingSpeed(final_state.h_speed, final_state.v_speed) ||
!MarsLanderRules::hasSafeLandingAttitude(final_state.rotate)) {
// x-speed penalty
double x_pen = 0.0;
if (std::abs(final_state.h_speed) > MarsLanderRules::kSafeLandingMaxHorizontalSpeed) {
x_pen = std::abs(final_state.h_speed) - MarsLanderRules::kSafeLandingMaxHorizontalSpeed;
}
// y-speed penalty
double y_pen = 0.0;
if (final_state.v_speed < MarsLanderRules::kSafeLandingMinVerticalSpeed) {
y_pen = MarsLanderRules::kSafeLandingMinVerticalSpeed - final_state.v_speed;
}
// rotation penalty for non-upright touchdowns
double rotation_pen =
std::abs(final_state.rotate - MarsLanderRules::kRequiredLandingRotate) * 1.5;
// Calculate a combined linear penalty
double total_pen = std::sqrt(x_pen * x_pen + y_pen * y_pen) + rotation_pen;
// Use exponential decay so the score scales smoothly from 200 down to ~100
// As the penalty grows to infinity, score asymptotically approaches 100
double score = 100.0 + 100.0 * std::exp(-total_pen / 30.0);
return score;
}
// Range 200-300: landed safely; rank safe landings by fuel economy.
// (A safe landing implies rotate == 0.)
assert(init_status.fuel > 0 &&
"Safe-landing fuel normalization assumes a strictly positive initial fuel load");
double fuel_bonus = 100.0 * final_state.fuel / init_status.fuel;
return 200.0 + fuel_bonus;
}