Skip to content

fix(moonbreak): estimate losses from the real waves, not a pooled average - #58

Merged
rolljee merged 1 commit into
masterfrom
fix/moonbreak-loss-wave-decomposition
Aug 15, 2026
Merged

fix(moonbreak): estimate losses from the real waves, not a pooled average#58
rolljee merged 1 commit into
masterfrom
fix/moonbreak-loss-wave-decomposition

Conversation

@rolljee

@rolljee rolljee commented Aug 15, 2026

Copy link
Copy Markdown
Owner

The inconsistency flagged at the end of #56.

The bug

computeMoonbreak builds its probability from each attacker's own six-wave split — remainder waves of base + 1, the rest of base. Its loss estimate did something else: it pooled the whole attack into one average wave size, totalRip / min(totalRip, attackers × 6).

The two halves of the same calculation therefore modelled different attacks, and the losses came out blind to how the fleet was divided:

fleets total probability mean losses (before) mean losses (after)
[1, 100] 101 78.96 % 22.04 26.74
[50, 50] 100 87.05 % 21.90 22.06

Same answer for two attacks that are nothing alike. Spread evenly, the waves are smaller, the moon falls sooner and fewer waves ever fire — so it should cost less, not the same.

The fix

Walk the same wave sequence the probability is built from: each attacker's six waves, at their own size, in firing order. An attacker with fewer than six Deathstars pads with empty waves, which neither threaten the moon nor lose a ship, so they cost nothing to carry.

Impact on the numbers people already trust

Even fleets — what the module was checked against when it was ported from og-bot-discord — barely move:

case before after
[6] on 8944 km 2.48 2.48
[25, 25] 13.44 13.53
[25, 25, 25, 25] 16.72 16.85
[100] 27.66 27.78

Lopsided ones move a lot, which was the point.

One consequence worth stating

Losses now depend on the order the attackers are listed, because the fleet that opens faces a moon still standing: [100, 1] loses 27.88 where [1, 100] loses 26.74. The probability is unchanged either way. That is real — attackers fly one after the other — and the help text now says so in both languages, rather than leaving it to be discovered.

Not changed

The variance still sums the per-wave variances, treating waves as independent although they share the survival chain, and the spread is still summarised as a gaussian. Both are approximations kept from the model this was ported from; they are now documented as such in the code. Changing them is a separate decision about the statistics, not about which attack is being modelled.

Also here

ogamejs bumped to 4.0.2, which refuses rate terms that cannot describe a trade (rolljee/ogamejs#40) — the follow-up noted in #56.

Tests

New coverage for the wave decomposition (attackerWaves, attackWaves: extras first, empty padding, firing order, every Deathstar accounted for) and for the two behaviours that motivated the change — a lopsided attack costing more than an even one, and the leading fleet costing more than the trailing one. Existing expectations updated where the numbers moved. 415 pass, build OK.

🤖 Generated with Claude Code

…rage

The loss estimate pooled the whole attack into one average wave size
(`totalRip / waves`) while the probability was built from each attacker's
own six-wave split. The two halves of the same calculation therefore
modelled different attacks, and the losses came out blind to how the
fleet was divided: 101 Deathstars sent as 1 + 100 gave the same 22.04
mean losses as 50 + 50, where the chance of breaking the moon was 79 %
against 87 %.

It now walks the same wave sequence the probability is built from —
each attacker's six waves, at their own size, in firing order — so a
lopsided attack and an even one no longer look alike. Attackers with
fewer than six Deathstars pad with empty waves, which neither threaten
the moon nor lose a ship.

Even fleets, which is what the numbers were checked against when this was
ported from the Discord bot, barely move: 6 RIP stays at 2.48, 4x25 goes
from 16.72 to 16.85. Lopsided ones move a lot, which was the point.

One consequence worth stating: losses now depend on the order the
attackers are listed, because the fleet that opens faces a moon still
standing. The probability does not. The help text says so.

Also bumps ogamejs to 4.0.2, which refuses rate terms that cannot
describe a trade (rolljee/ogamejs#40).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rolljee
rolljee merged commit 680334b into master Aug 15, 2026
1 check passed
@rolljee
rolljee deleted the fix/moonbreak-loss-wave-decomposition branch August 15, 2026 06:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant