/Puzzles
About
Team
Investments
Research
Research Index
Build
IncubationsOpen Source
Writing
Paradigm Puzzles
Hackathon

Terms, Disclosures, Privacy

LinkedIn, Twitter, Contact

RankAuthorStrategyEloWin%Kill%Attempts
LeaderboardSubmitGitHubAbout
Benedict Brady
Dan RobinsonParadigm
LeaderboardSubmitGitHubAbout
Benedict BradyDan Robinson
← Back to Leaderboard

About the Dogfight Competition

The Arena

Two fighters face off in a 2D arena—1000 meters wide and 600 meters tall. The horizontal boundaries wrap around: fly off the right edge and you emerge from the left. But altitude is unforgiving. The ground (y ≤ 5) is instant death. The ceiling (y > 550) drains your speed, punishing fighters that try to escape upward. Everything happens at 120 Hz—10,800 ticks per 90-second match.

Dogfight arena layout showing boundaries and zoneswrapwrapceiling zone (speed drain)death zone (y ≤ 5)1000m wide × 600m tallaltitudearenabluered

The Challenge

Your neural network controls a fighter plane. Every tick, it observes the battlefield—its own state, the opponent's relative position and velocity, and the positions of up to 8 bullets in flight—and decides three things: how hard to turn, how much throttle to apply, and whether to fire.

The goal is simple: eliminate your opponent or have more HP when the clock runs out. But the tactics are rich. Energy management matters—climbing costs speed, diving gains it. Rear-aspect armor means head-on attacks are risky and tail-chasing is inefficient. Damaged fighters get slower and turn worse, creating a snowball effect.

Train locally against four built-in opponents of increasing difficulty (dogfighter, chaser, ace, brawler), then upload your model as an ONNX file to compete against every other submission on the leaderboard.

How Scoring Works

When you submit a model, it plays 100 matches against every other submission on the leaderboard—50 random seeds, played from both sides (P0 and P1). Each match has one of four outcomes:

  • Elimination win — opponent HP reduced to 0 (Elo weight 1.0)
  • HP win — more HP at timeout (Elo weight 0.75)
  • Draw — equal HP at timeout (Elo weight 0.5)
  • Loss — by HP or by elimination (Elo weight 0.0)

These results are converted to a score and then to an Elo rating:

Elo = 1000 + 400 × log10(score / (1 - score))

where score = (1.0 × elim_wins + 0.75 × hp_wins + 0.5 × draws) / total_matches

A score of 0.5 gives Elo 1000. Consistently winning pushes your rating above 1000; consistently losing drops it below. Decisive eliminations are rewarded more than narrow HP victories.

Elo scoring system showing how win rate converts to rating10006008001200140080925%100050%119175%Elimination Win (3pt)HP Win (2pt)Draw (1pt)Loss (0pt)score = (elim + 0.75 × hp_win + 0.5 × draw) / 100Elo1000 + 400 · log(s/(1-s))

Physics & Energy

The simulation uses a gravity-based energy model. Gravity pulls at 130 m/s²—climbing bleeds speed, and diving converts altitude into velocity. This is the central tactical trade-off: altitude is potential energy you can spend later.

Physics model: climbing costs speed, diving gains speed, stall zonestall zone (<30 m/s)speed ↓speed ↑g = 130 m/s²climbingdivingaltitudeenergy is conserved: trade altitude for speedphysics

If your speed drops below 30 m/s, you stall. The nose drops, you lose control, and you can't recover until speed exceeds 40 m/s. Stalling near the ground is usually fatal. At the other extreme, the ceiling zone (above 550m) actively drains speed, preventing fighters from hiding at the top of the arena.

Damage compounds the problem. Each HP lost reduces your maximum speed by 3% and your turn rate by 2%. A fighter at 2 HP is 9% slower and 6% less maneuverable—often enough to seal the outcome.

Combat Mechanics

Fighters have 5 HP and carry a gun that fires bullets at 400 m/s with an effective range of about 200 meters (bullets despawn after 0.5 seconds). The gun has a 0.75-second cooldown between shots, so every bullet counts.

Combat mechanics: rear-aspect armor, bullet trajectories, attack anglesarmor (45°)glance~200m rangeoptimalHPHPcooldown: 0.75s400 m/s-6% max speed-4% turn rateattack from the side, avoid the rear armor coneattackerdefendercombat

Rear-aspect armor: bullets arriving within 45° of directly behind the target glance off and deal no damage. This means tail-chasing—the most intuitive attack angle—is actually the worst. The best attacks come from the side or from an oblique angle, where you can land hits while staying out of the defender's forward firing arc.

Effective combat requires combining maneuvering and shooting. You need to get into a firing position (close range, off the tail cone), maintain it long enough to fire, then disengage or reposition before the opponent can counter. Energy management determines whether you can execute these maneuvers.

What Your Model Sees

Your model receives a 224-float observation vector—4 stacked frames of 56 floats each. Frame stacking gives temporal context: the model can infer velocities, accelerations, and trends from the differences between frames. The most recent frame occupies indices 168–223.

What the model observes: self state, opponent state, bulletsspeedaltitudeheadinghpcooldownenergyrel_x, rel_ydistanceclosure_rateangle_off_tailopp_hpbullet_posbullet_angleAONopponentselft-3t-2t-1t4 stacked frames × 56 floats = 224selfoppbulletsobservation

Each 56-float frame contains:

Self state [0..8):
  speed, cos(yaw), sin(yaw), hp, gun_cooldown,
  altitude, x_position, energy

Opponent state [8..19):
  rel_x, rel_y, speed, cos(yaw), sin(yaw), hp,
  distance, closure_rate, angular_velocity,
  energy, angle_off_tail

Bullets [19..51):   8 slots × 4 values each
  rel_x, rel_y, is_friendly, angle

Relative geometry [51..55):
  angle_off_nose, opp_angle_off_nose,
  rel_vel_x, rel_vel_y

Meta [55]:
  ticks_remaining

All values are normalized to roughly [-1, 1]. Positions are relative to the observing fighter. Bullet slots are zero-filled when fewer than 8 bullets are in flight.

Model Output

Your model produces 3 continuous values:

Output shape: [1, 3]

[0] yaw_input   — clamped to [-1, 1]
                  -1 = full left turn, +1 = full right turn

[1] throttle    — clamped to [0, 1]
                  0 = idle, 1 = full thrust

[2] shoot       — fires if > 0 (and gun is off cooldown)

The outputs are treated as continuous controls, not discrete actions. Your model can output any float values—they will be clamped to the valid ranges. Subtle throttle and turn inputs enable precise maneuvering.

Rules & Constraints

  • Format: ONNX model file
  • Input shape: [1, 224] (float32)
  • Output shape: [1, 3] (float32)
  • Max file size: 10 MB
  • Max parameters: 250,000
  • Match duration: 90 seconds (10,800 ticks at 120 Hz)
  • Arena: 1000m × 600m, horizontal wrap-around
  • HP: 5 per fighter, 0 = eliminated
  • Scoring: 100 matches per opponent (50 seeds × 2 sides)
  • Submissions are rate-limited to 1 every 10 minutes
Submit Your Model