Kaggle / Kaggle/kaggle-environments
Bug: OOB check destroys fleets before collision detection runs
- Dominant language
- JavaScript
- Stars
- 452
- Forks
- 190
- Avg merge
- 31m
- Merged PRs (30d)
- 2
Description
Fast fleets near the board edge get destroyed instead of captured. The engine checks out-of-bounds before checking if the fleet's path passed through a planet.
## Reproduction
Seed 62, 2 players. Player 0 accumulates ~1000 ships on planet 8 (static, at (95.4, 63.7)) and sends them at planet 0 (at (98.6, 98.6), radius 1.0 — 0.42 units from the top board edge).
At 1000 ships the fleet travels at speed 6. On the final step it starts 2.28 units from the target center, overshoots 6 units, and lands at y≈102.2 — outside the board.
The fleet's path segment passes within 0.0001 units of the planet center. `point_to_segment_distance` would return a hit. But the OOB check at line 586 destroys the fleet before the collision check at line 598 runs.
Attached: HTML replay showing the fleet vanish at step 206.
[oob_bug_replay.html](https://github.com/user-attachments/files/27088482/oob_bug_replay.html)
## The problem
In `orbit_wars.py`, fleet processing (line 575–601) runs checks in this order:
```python
for fleet in obs0.fleets:
# ... move fleet ...
old_pos = (fleet[2], fleet[3])
fleet[2] += math.cos(angle) * speed
fleet[3] += math.sin(angle) * speed
new_pos = (fleet[2], fleet[3])
# 1. OOB check — destroys fleet immediately
if not (0 <= fleet[2] <= BOARD_SIZE and 0 <= fleet[3] <= BOARD_SIZE):
fleets_to_remove.append(fleet)
continue # <-- skips collision check
# 2. Sun check
if point_to_segment_distance((CENTER, CENTER), old_pos, new_pos) < SUN_RADIUS:
fleets_to_remove.append(fleet)
continue
# 3. Planet collision (continuous — checks full path segment)
for planet in obs0.planets:
planet_pos = (planet[2], planet[3])
if point_to_segment_distance(planet_pos, old_pos, new_pos) < planet[4]:
combat_lists[planet[0]].append(fleet)
fleets_to_remove.append(fleet)
break
```
The `continue` at line 588 skips step 3 entirely.
## Proposed fix
Move the planet collision check before the OOB check. Use `for...else` so OOB only triggers when no planet captured the fleet:
```python
for fleet in obs0.fleets:
# ... move fleet ...
# 1. Sun check (always fatal)
if point_to_segment_distance((CENTER, CENTER), old_pos, new_pos) < SUN_RADIUS:
fleets_to_remove.append(fleet)
continue
# 2. Planet collision (continuous — checks full path segment)
for planet in obs0.planets:
planet_pos = (planet[2], planet[3])
if point_to_segment_distance(planet_pos, old_pos, new_pos) < planet[4]:
combat_lists[planet[0]].append(fleet)
fleets_to_remove.append(fleet)
break
else:
# 3. OOB check — only if no planet was hit
if not (0 <= fleet[2] <= BOARD_SIZE and 0 <= fleet[3] <= BOARD_SIZE):
fleets_to_remove.append(fleet)
```
This preserves all existing behavior except the edge case: a fleet whose path passes through a planet but whose endpoint lands OOB now gets captured instead of destroyed.
Contributor guide
Research direction
Start in orbit_wars.py around lines 575–601 and reproduce the issue with seed 62 using the attached HTML replay as a reference. Trace the fleet movement, sun, planet-collision, and out-of-bounds checks. Done means a fleet whose path crosses a planet but ends outside the board is captured rather than destroyed, while existing behavior remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100