Games¶
Typed Game subtypes (knob bundles) and per-game make_<game>(...) builders.
Base¶
orbitalgym.games.base.Game
dataclass
¶
Marker base — subclasses MUST override default_reward_fn/termination_fn.
advance_state ¶
Game-owned bookkeeping on the state leaving a step.
OrbitalGymEnv.step calls this once the dynamics have produced
next_state and before the observations, rewards and termination
read it, so a game that needs history across steps — how long a
vehicle has held a radius, say — can keep it on the state rather
than recomputing it. The default returns the state untouched.
validate ¶
Check the cfg supports this game's knobs. Called by ScenarioConfig.post_init.
Games whose knobs depend on the state layout (a propellant gate needs a mass component, say) reject the incoherent combination here, so the failure lands at config construction rather than mid-rollout.
orbitalgym.games.base.NoGame
dataclass
¶
Bases: Game
Default — for users running custom scenarios with no preset semantics.
advance_state ¶
Game-owned bookkeeping on the state leaving a step.
OrbitalGymEnv.step calls this once the dynamics have produced
next_state and before the observations, rewards and termination
read it, so a game that needs history across steps — how long a
vehicle has held a radius, say — can keep it on the state rather
than recomputing it. The default returns the state untouched.
validate ¶
Check the cfg supports this game's knobs. Called by ScenarioConfig.post_init.
Games whose knobs depend on the state layout (a propellant gate needs a mass component, say) reject the incoherent combination here, so the failure lands at config construction rather than mid-rollout.
orbitalgym.registry.GameKey ¶
Lady-Bandit-Guard¶
orbitalgym.games.lady_bandit_guard.LadyBanditGuard
dataclass
¶
LadyBanditGuard(
breach_radius_m: float = 5.0,
catch_radius_m: float = 50.0,
breach_speed_mps: float = float("inf"),
catch_speed_mps: float = float("inf"),
catch_dwell_steps: int = 0,
breach_dwell_steps: int = 0,
escape_radius_m: float = 0.0,
repel_on_empty_tank: bool = False,
dv_cost: float = 0.0,
shaping_scale_m: float = 300.0,
shaping_gain: float = 50.0,
shaping_discount: float = 1.0,
home_weight: float = 0.0,
guard_separation_m: float = 20.0,
lady_keepout_m: float = 20.0,
separation_cost: float = 10.0,
)
Bases: Game
Guard protects the lady (RTN origin) from bandits.
Knobs
breach_radius_m: bandit-vs-lady distance below which the bandit is
considered to have breached (bandit win).
catch_radius_m: guard-vs-bandit distance below which the guard
catches the bandit (guard win).
breach_speed_mps: bandit-vs-lady relative speed below which a pass
inside breach_radius_m counts as a breach. Infinite gates on
radius alone.
catch_speed_mps: guard-vs-bandit relative speed below which a pass
inside catch_radius_m counts as a catch. Infinite gates on
radius alone.
catch_dwell_steps: consecutive steps a bandit must spend inside the
catch radius of at least one guard — the same guard or not —
before the catch fires. Zero fires on the first step that meets
the radius and speed gates.
breach_dwell_steps: consecutive steps a bandit must spend inside the
breach radius of the lady before the breach fires. Zero fires on
the first such step.
escape_radius_m: bandit-vs-lady distance above which the bandit
counts as repelled. Zero disables the gate.
repel_on_empty_tank: when True, a bandit out of propellant whose
coast cannot reach the lady before the horizon ends counts as
repelled. Requires a mass-tracked bandit in an RTN frame.
dv_cost: reward units charged per m/s of delta-v. Each side pays only
for its own fuel; a side without a MASS component pays nothing.
shaping_scale_m: distance that makes the shaping potential unity.
shaping_gain: scale on the potential-difference shaping term. Zero
leaves a terminal-only reward. The default is large enough that the
shaping steers a horizon-limited planner rather than being lost
under the terminal payoffs.
shaping_discount: discount inside the potential difference. Matching
the planner's per-step discount makes the shaped value exactly
the unshaped value minus the potential.
home_weight: weight on the guard-lady distance inside the potential,
pulling the guard back toward the asset it defends.
guard_separation_m: guard-guard distance below which the guard side
pays a crowding hinge.
lady_keepout_m: guard-lady distance below which the guard side pays
the same hinge.
separation_cost: reward units at the bottom of either hinge.
The episode is a guard win by repulsion once every bandit is repelled.
advance_state ¶
Advance the per-bandit dwell counters onto the state leaving the step.
Runs whatever the dwell knobs are set to, so the counters describe the engagement even when the win conditions do not read them.
orbitalgym.games.lady_bandit_guard.make_lady_bandit_guard ¶
make_lady_bandit_guard(
*,
breach_radius_m: float = 5.0,
catch_radius_m: float = 50.0,
breach_speed_mps: float = float("inf"),
catch_speed_mps: float = float("inf"),
catch_dwell_steps: int = 0,
breach_dwell_steps: int = 0,
escape_radius_m: float = 0.0,
repel_on_empty_tank: bool = False,
dv_cost: float = 0.0,
shaping_scale_m: float = 300.0,
shaping_gain: float = 50.0,
shaping_discount: float = 1.0,
home_weight: float = 0.0,
guard_separation_m: float = 20.0,
lady_keepout_m: float = 20.0,
separation_cost: float = 10.0,
n_guards: int = 1,
n_bandits: int = 1,
dt: float = 10.0,
max_horizon_s: float = 2000.0,
seed: int = 0,
epoch_mjd_utc: float = 60067.0,
reference_orbit: ReferenceOrbitState | None = None,
guard_components: tuple[StateComponentKey, ...] = (
StateComponentKey.RTN,
StateComponentKey.MASS,
),
bandit_components: tuple[StateComponentKey, ...] = (
StateComponentKey.RTN,
),
guard_params: VehicleParamsSpec | None = None,
bandit_params: VehicleParamsSpec | None = None,
ic_sampler: ICSpec | None = None,
truth_dynamics: DynamicsKey = DynamicsKey.HCW_RTN,
policy_dynamics: DynamicsKey = DynamicsKey.HCW_RTN,
guard_observation_fn: Any = None,
bandit_observation_fn: Any = None,
guard_ground_station_network: Any = None,
bandit_ground_station_network: Any = None,
with_communication: bool = False,
comm_cost: float = 5.0,
**config_kwargs: Any,
)
Builder for an LBG scenario.
Wires LadyBanditGuard(breach_radius_m=..., catch_radius_m=...) as
cfg.game; reward and termination are populated from
LadyBanditGuard.default_*_fn by ScenarioConfig.__post_init__.
Defaults assume a 1v1 RTN scenario with mass-tracked guard. To switch
to 2D RT dynamics, pass matching truth_dynamics/policy_dynamics
and corresponding guard_components/bandit_components; otherwise
ScenarioConfig.__post_init__ will reject the incoherent combo.
Additional keyword arguments are forwarded to ScenarioConfig.
The reward these knobs configure — the per-side potential-based shaping term
(shaping_scale_m, shaping_gain, shaping_discount, home_weight), the
guard-side separation charge (guard_separation_m, lady_keepout_m,
separation_cost) and the dv_cost fuel term — is documented under
Extending → Customize rewards.
Pursuit-Evasion¶
orbitalgym.games.pursuit_evasion.PursuitEvasion
dataclass
¶
Bases: Game
1v1 pursuit/evasion.
Knobs
capture_distance_m: episode terminates when relative distance falls below this threshold.
advance_state ¶
Game-owned bookkeeping on the state leaving a step.
OrbitalGymEnv.step calls this once the dynamics have produced
next_state and before the observations, rewards and termination
read it, so a game that needs history across steps — how long a
vehicle has held a radius, say — can keep it on the state rather
than recomputing it. The default returns the state untouched.
validate ¶
Check the cfg supports this game's knobs. Called by ScenarioConfig.post_init.
Games whose knobs depend on the state layout (a propellant gate needs a mass component, say) reject the incoherent combination here, so the failure lands at config construction rather than mid-rollout.
orbitalgym.games.pursuit_evasion.PursuitEvasionReward
dataclass
¶
Zero-sum reward on |r_guard - r_bandit|. Requires cfg.game: PursuitEvasion.
orbitalgym.games.pursuit_evasion.PursuitEvasionTermination
dataclass
¶
Episode ends on max_steps OR capture (relative distance below threshold).
Reads max_steps from params.max_steps and capture_distance_m from
params.game.
orbitalgym.games.pursuit_evasion.make_pursuit_evasion ¶
make_pursuit_evasion(
*,
capture_distance_m: float = 10.0,
n_guards: int = 1,
n_bandits: int = 1,
dt: float = 10.0,
max_horizon_s: float = 2000.0,
seed: int = 0,
epoch_mjd_utc: float = 60067.0,
reference_orbit: ReferenceOrbitState | None = None,
guard_components: tuple[StateComponentKey, ...] = (
StateComponentKey.RTN,
),
bandit_components: tuple[StateComponentKey, ...] = (
StateComponentKey.RTN,
),
guard_params: VehicleParamsSpec | None = None,
bandit_params: VehicleParamsSpec | None = None,
ic_sampler: ICSpec | None = None,
truth_dynamics: DynamicsKey = DynamicsKey.HCW_RTN,
policy_dynamics: DynamicsKey = DynamicsKey.HCW_RTN,
guard_observation_fn: Any = None,
bandit_observation_fn: Any = None,
)
Builder for a PE scenario.
Sun-Blocking¶
orbitalgym.games.sun_blocking.SunBlocking
dataclass
¶
Bases: Game
1v1 sun-blocking game.
Knobs
target_viewing_distance_m: desired bandit-guard standoff at which the range factor peaks (meters). range_decay_coef: Gaussian decay coefficient (1/m²) controlling the range-factor peak width.
advance_state ¶
Game-owned bookkeeping on the state leaving a step.
OrbitalGymEnv.step calls this once the dynamics have produced
next_state and before the observations, rewards and termination
read it, so a game that needs history across steps — how long a
vehicle has held a radius, say — can keep it on the state rather
than recomputing it. The default returns the state untouched.
validate ¶
Check the cfg supports this game's knobs. Called by ScenarioConfig.post_init.
Games whose knobs depend on the state layout (a propellant gate needs a mass component, say) reject the incoherent combination here, so the failure lands at config construction rather than mid-rollout.
orbitalgym.games.sun_blocking.SunBlockingReward
dataclass
¶
KSP-DG-style sun-blocking reward.
Requires cfg.game: SunBlocking. Pulls vehicle ECI positions via
games/_frames.vehicle_eci_position, looks up Sun ECI via
astrojax.sun_position, then calls sun_blocking_kernel.
orbitalgym.games.sun_blocking.make_sun_blocking ¶
make_sun_blocking(
*,
target_viewing_distance_m: float = 500.0,
range_decay_coef: float = 4e-06,
n_guards: int = 1,
n_bandits: int = 1,
dt: float = 10.0,
max_horizon_s: float = 5400.0,
seed: int = 0,
epoch_mjd_utc: float = 60067.0,
reference_orbit: ReferenceOrbitState | None = None,
guard_components: tuple[StateComponentKey, ...] = (
StateComponentKey.RTN,
),
bandit_components: tuple[StateComponentKey, ...] = (
StateComponentKey.RTN,
),
guard_params: VehicleParamsSpec | None = None,
bandit_params: VehicleParamsSpec | None = None,
ic_sampler: ICSpec | None = None,
truth_dynamics: DynamicsKey = DynamicsKey.HCW_RTN,
policy_dynamics: DynamicsKey = DynamicsKey.HCW_RTN,
guard_observation_fn: Any = None,
bandit_observation_fn: Any = None,
)
Builder for an SB scenario.
Observation-Blocking¶
orbitalgym.games.observation_blocking.ObservationBlocking
dataclass
¶
ObservationBlocking(
target_lat_deg: float = 37.4,
target_lon_deg: float = -122.2,
target_alt_m: float = 0.0,
min_elevation_deg: float = 5.0,
target_viewing_distance_m: float = 500.0,
range_decay_coef: float = 4e-06,
)
Bases: Game
Bandit blocks guard's view of an Earth surface target.
Knobs
target_lat_deg, target_lon_deg, target_alt_m: WGS84 geodetic coordinates of the surface target. min_elevation_deg: target visibility threshold (degrees above horizon). Reward is gated to 0 when the target is below this elevation as seen from the guard. target_viewing_distance_m: desired bandit-guard standoff at which the range factor peaks (meters). range_decay_coef: Gaussian decay coefficient (1/m²) controlling the range-factor peak width.
target_ecef_m is precomputed in post_init (one-time geodetic→ECEF conversion) and cached on the instance for use in the reward fn.
advance_state ¶
Game-owned bookkeeping on the state leaving a step.
OrbitalGymEnv.step calls this once the dynamics have produced
next_state and before the observations, rewards and termination
read it, so a game that needs history across steps — how long a
vehicle has held a radius, say — can keep it on the state rather
than recomputing it. The default returns the state untouched.
validate ¶
Check the cfg supports this game's knobs. Called by ScenarioConfig.post_init.
Games whose knobs depend on the state layout (a propellant gate needs a mass component, say) reject the incoherent combination here, so the failure lands at config construction rather than mid-rollout.
orbitalgym.games.observation_blocking.ObservationBlockingReward
dataclass
¶
KSP-DG-style observation-blocking reward, gated on visibility.
Requires cfg.game: ObservationBlocking. Pulls vehicle ECI positions via
games/_frames.vehicle_eci_position, rotates the target ECEF→ECI per
timestep (GMST-only via astrojax.zero_eop), then calls
observation_blocking_kernel.
orbitalgym.games.observation_blocking.make_observation_blocking ¶
make_observation_blocking(
*,
target_lat_deg: float = 37.4,
target_lon_deg: float = -122.2,
target_alt_m: float = 0.0,
min_elevation_deg: float = 5.0,
target_viewing_distance_m: float = 500.0,
range_decay_coef: float = 4e-06,
n_guards: int = 1,
n_bandits: int = 1,
dt: float = 10.0,
max_horizon_s: float = 5400.0,
seed: int = 0,
epoch_mjd_utc: float = 60067.0,
reference_orbit: ReferenceOrbitState | None = None,
guard_components: tuple[StateComponentKey, ...] = (
StateComponentKey.RTN,
),
bandit_components: tuple[StateComponentKey, ...] = (
StateComponentKey.RTN,
),
guard_params: VehicleParamsSpec | None = None,
bandit_params: VehicleParamsSpec | None = None,
ic_sampler: ICSpec | None = None,
truth_dynamics: DynamicsKey = DynamicsKey.HCW_RTN,
policy_dynamics: DynamicsKey = DynamicsKey.HCW_RTN,
guard_observation_fn: Any = None,
bandit_observation_fn: Any = None,
)
Builder for an OB scenario.
Get-Off-My-Lawn¶
orbitalgym.games.get_off_my_lawn.GetOffMyLawn
dataclass
¶
GetOffMyLawn(
r_min_keep_m: float = 100.0,
r_max_keep_m: float = 500.0,
catch_radius_m: float = 50.0,
keep_out_radius_m: float = 1500.0,
r_loiter: float = 1.0,
alpha: float = 0.001,
r_catch: float = 1000.0,
r_pushout: float = 500.0,
alpha_chase: float = 0.001,
)
Bases: Game
Bandit wants to loiter near the lady; guard wants to intercept or repel.
Geometric knobs
r_min_keep_m: lower bound of bandit desired loiter band (m, HCW metric).
r_max_keep_m: upper bound of bandit desired loiter band (m, HCW metric).
catch_radius_m: guard-vs-bandit Euclidean distance below which the
guard intercepts (terminal event).
keep_out_radius_m: HCW standoff beyond which the bandit is considered
"pushed out". Must be > r_max_keep_m so the keep-out shell
sits outside the loiter band; __post_init__ enforces this.
Reward-weight knobs (tune which term dominates):
r_loiter: per-step bonus when at least one bandit is inside the keep
band. Default 1.0.
alpha: dense band-distance shaping coefficient (per meter). Default
1e-3 — a 1000 m gap from the band costs ~1.0 per step.
r_catch: terminal penalty on the bandit (and bonus on the guard) when
the guard catches a bandit. Default 1000.0; raise to make catch
dominate, lower to weight loiter / chase shaping more heavily.
r_pushout: bonus on the guard when every bandit is beyond the
keep-out shell. Default 500.0.
alpha_chase: dense guard-side shaping per meter of guard-bandit
distance (a chase prior). Default 1e-3. Set to 0.0 (along
with r_pushout=0.0) for a strictly zero-sum reward.
advance_state ¶
Game-owned bookkeeping on the state leaving a step.
OrbitalGymEnv.step calls this once the dynamics have produced
next_state and before the observations, rewards and termination
read it, so a game that needs history across steps — how long a
vehicle has held a radius, say — can keep it on the state rather
than recomputing it. The default returns the state untouched.
validate ¶
Check the cfg supports this game's knobs. Called by ScenarioConfig.post_init.
Games whose knobs depend on the state layout (a propellant gate needs a mass component, say) reject the incoherent combination here, so the failure lands at config construction rather than mid-rollout.
orbitalgym.games.get_off_my_lawn.GetOffMyLawnReward
dataclass
¶
GetOffMyLawnReward(
r_min_keep_m: float = 100.0,
r_max_keep_m: float = 500.0,
catch_radius_m: float = 50.0,
keep_out_radius_m: float = 1500.0,
alpha: float = 0.001,
alpha_chase: float = 0.001,
r_loiter: float = 1.0,
r_catch: float = 1000.0,
r_pushout: float = 500.0,
scope: str = "per_side",
)
Dense + terminal reward for Get-Off-My-Lawn.
See :class:GetOffMyLawn module docstring for the full formula.
orbitalgym.games.get_off_my_lawn.GetOffMyLawnTermination
dataclass
¶
Terminate on max_steps OR any bandit caught OR all bandits pushed out.
catch_radius_m=0 disables the catch gate. keep_out_radius_m should
match :class:GetOffMyLawn to keep reward and termination in agreement.
orbitalgym.games.get_off_my_lawn.make_get_off_my_lawn ¶
make_get_off_my_lawn(
*,
r_min_keep_m: float = 100.0,
r_max_keep_m: float = 500.0,
catch_radius_m: float = 50.0,
keep_out_radius_m: float = 1500.0,
r_loiter: float = 1.0,
alpha: float = 0.001,
r_catch: float = 1000.0,
r_pushout: float = 500.0,
alpha_chase: float = 0.001,
n_guards: int = 1,
n_bandits: int = 1,
dt: float = 10.0,
max_horizon_s: float = 3000.0,
seed: int = 0,
epoch_mjd_utc: float = 60067.0,
reference_orbit: ReferenceOrbitState | None = None,
guard_components: tuple[StateComponentKey, ...] = (
StateComponentKey.RTN,
),
bandit_components: tuple[StateComponentKey, ...] = (
StateComponentKey.RTN,
),
guard_params: VehicleParamsSpec | None = None,
bandit_params: VehicleParamsSpec | None = None,
ic_sampler: ICSpec | None = None,
truth_dynamics: DynamicsKey = DynamicsKey.HCW_RTN,
policy_dynamics: DynamicsKey = DynamicsKey.HCW_RTN,
guard_observation_fn: Any = None,
bandit_observation_fn: Any = None,
)
Builder for a Get-Off-My-Lawn scenario.
Defaults place a 1v1 bandit/guard in the RTN frame around a circular LEO reference orbit. The bandit IC sits on a 2 km radial-ellipse co-orbit (well outside the keep band), so a passive bandit will not naturally drift into the loiter window — solving requires control.
Proximity events¶
Closest-approach geometry shared by the Lady-Bandit-Guard reward and termination, so both resolve catch and breach over the whole step, and the dwell counters that turn either event into a hold over several steps.
orbitalgym.games.proximity.positions ¶
Per-vehicle (..., N, 3) positions, zero-padded from a 2D rt layout.
Leading axes pass through, so a time-stacked side state returns
(T, N, 3).
orbitalgym.games.proximity.closest_approach ¶
Minimum distance over a coast of length dt, and the relative speed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
r0
|
Array
|
Relative position at the start of the step, shape |
required |
v
|
Array
|
Constant relative velocity over the step, shape |
required |
dt
|
float
|
Step duration in seconds. |
required |
Returns:
| Type | Description |
|---|---|
Array
|
|
Array
|
|
orbitalgym.games.proximity.proximity_event ¶
Whether the coast passes within radius_m while slower than speed_mps.
orbitalgym.games.proximity.lbg_events ¶
lbg_events(
prev_state,
next_state,
dt: float,
catch_radius_m: float,
catch_speed_mps: float,
breach_radius_m: float,
breach_speed_mps: float,
) -> tuple[jax.Array, jax.Array, jax.Array, jax.Array]
Catch/breach events and closest-approach distances over one step.
Catch geometry is guard minus bandit over every guard-bandit pair;
breach geometry is bandit minus lady, the RTN origin. catch_radius_m
of zero disables the catch event while still reporting d_gb_min.
Returns:
| Type | Description |
|---|---|
Array
|
|
Array
|
the two minimum closest-approach distances over the step. |
orbitalgym.games.proximity.lbg_events_from_positions ¶
lbg_events_from_positions(
guard_prev: Array,
guard_next: Array,
bandit_prev: Array,
bandit_next: Array,
dt: float,
catch_radius_m: float,
catch_speed_mps: float,
breach_radius_m: float,
breach_speed_mps: float,
) -> tuple[jax.Array, jax.Array, jax.Array, jax.Array]
Catch/breach events and closest-approach distances from position arrays.
The events are :func:lbg_proximity_masks reduced over the bandits: an
event holds when some bandit is inside the corresponding radius.
Returns:
| Type | Description |
|---|---|
Array
|
|
Array
|
the inputs. |
orbitalgym.games.proximity.lbg_proximity_masks ¶
lbg_proximity_masks(
guard_prev: Array,
guard_next: Array,
bandit_prev: Array,
bandit_next: Array,
dt: float,
catch_radius_m: float,
catch_speed_mps: float,
breach_radius_m: float,
breach_speed_mps: float,
) -> tuple[jax.Array, jax.Array, jax.Array, jax.Array]
Per-bandit in-radius masks and closest-approach distances.
Positions are (..., n_g, 3) and (..., n_b, 3); leading axes pass
through, so a whole trajectory is scored in one call. A bandit is inside
the catch radius when some guard both passes within catch_radius_m
of it and is slower than catch_speed_mps over the step — the per-pair
conjunction, not the closest pair's speed. It is inside the breach radius
when its own pass at the lady meets the same two conditions.
Returns:
| Type | Description |
|---|---|
Array
|
|
Array
|
|
Array
|
over every bandit, with the leading shape of the inputs. |
orbitalgym.games.proximity.advance_dwell ¶
One step of a consecutive-step counter: increment inside, reset outside.
count and inside are per-bandit arrays of the same shape. The
result counts how many consecutive steps, up to and including this one,
each bandit has spent inside the radius; a single step outside sends it
back to zero.
A step counts as inside when its within-step closest approach is inside, the same test the single-step event uses. The step a bandit departs on therefore still counts — it was inside for part of it — and the first step spent wholly outside is the one that breaks the hold.
orbitalgym.games.proximity.lbg_dwell_step ¶
lbg_dwell_step(
prev_state,
next_state,
dt: float,
catch_radius_m: float,
catch_speed_mps: float,
breach_radius_m: float,
breach_speed_mps: float,
) -> tuple[jax.Array, jax.Array]
The dwell counters leaving a step, from the counters entering it.
Advances prev_state.dwell_catch and prev_state.dwell_breach with
:func:advance_dwell on the per-bandit masks
:func:lbg_proximity_masks reports for the step. A step whose closest
approach fails either the radius or the speed gate resets that counter,
so a positive count means the gate held on every one of those steps.
Returns:
| Type | Description |
|---|---|
tuple[Array, Array]
|
|
orbitalgym.games.proximity.lbg_events_with_dwell ¶
lbg_events_with_dwell(
prev_state,
next_state,
dt: float,
catch_radius_m: float,
catch_speed_mps: float,
breach_radius_m: float,
breach_speed_mps: float,
catch_dwell_steps: int,
breach_dwell_steps: int,
) -> tuple[jax.Array, jax.Array, jax.Array, jax.Array]
Catch/breach events under an optional consecutive-step dwell requirement.
A dwell of zero leaves the event exactly as :func:lbg_events reports
it: the within-step closest approach on this step alone. A positive
dwell replaces it with the requirement that some bandit has held the
radius — and the speed gate, which enters through the counter — for that
many consecutive steps, read off the counters next_state carries.
Returns:
| Type | Description |
|---|---|
Array
|
|
Array
|
step's own closest approaches either way. |
orbitalgym.games.proximity.stm_power_stack ¶
Powers phi^0 ... phi^max_steps of the one-step HCW-RTN STM, (max_steps + 1, 6, 6).
Coasting a state to every step of the horizon is one batched matmul
against this stack rather than a chain of max_steps dependent ones,
so :func:ballistic_breach_possible costs the same whichever step of the
episode calls it. The stack is built with an associative scan under
compile-time evaluation and returned as a concrete NumPy array, so it is
memoised on its three scalar arguments (fixed for a scenario) and is safe
to build from inside a jax.jit trace without leaking a tracer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mean_motion
|
float
|
Reference-orbit mean motion in rad/s. |
required |
dt
|
float
|
Step duration in seconds. |
required |
max_steps
|
int
|
Highest power to build. |
required |
orbitalgym.games.proximity.ballistic_breach_possible ¶
ballistic_breach_possible(
x_rtn: Array,
phi_powers: Array | ndarray,
n_remaining: Array,
dt: float,
radius_m: float,
speed_mps: float,
) -> jax.Array
Whether a coasting RTN state can still reach the lady before the clock runs out.
Coasts x_rtn to every step of the horizon at once through
phi_powers, then tests :func:proximity_event against the origin on
each of the resulting segments, keeping only the first n_remaining of
them. The horizon length is static — it is the length of phi_powers —
while n_remaining is traced, so one compiled evaluation serves every
step of an episode.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x_rtn
|
Array
|
Coasting state |
required |
phi_powers
|
Array | ndarray
|
Powers of the one-step STM, |
required |
n_remaining
|
Array
|
Steps left in the episode; segments beyond it are masked. |
required |
dt
|
float
|
Step duration in seconds, matching |
required |
radius_m
|
float
|
Breach radius about the origin. |
required |
speed_mps
|
float
|
Relative-speed gate for the breach. |
required |
Returns:
| Type | Description |
|---|---|
Array
|
Boolean with the leading shape of |
orbitalgym.games.proximity.lbg_repelled ¶
lbg_repelled(
state,
params,
escape_radius_m: float,
repel_on_empty_tank: bool,
breach_radius_m: float,
breach_speed_mps: float,
) -> jax.Array
Whether every bandit has been repelled — no longer a threat to the lady.
A bandit is repelled when it is farther than escape_radius_m from the
lady (zero disables that gate), or when repel_on_empty_tank is set and
it has burnt its propellant on a coast that cannot reach the lady within
the episode's remaining steps. Both gates off returns False.
params is the scenario config: dt, max_steps and, for the
empty-tank gate, reference_orbit supply the coast model.
Dispatch¶
orbitalgym.games.make_game ¶
Dispatch to the per-game builder by GameKey.
Example
cfg = make_game(GameKey.LADY_BANDIT_GUARD, breach_radius_m=5.0, catch_radius_m=50.0)