One generator, so a citation names one fight (R-265)
tools/playthrough.mjs exists to show a reader why a measured number is what it is. I cited it to another session — read seed 2, see the wipe the 45% row is made of — and the reproduction failed in front of them. They reported different outcomes at both seeds and guessed the cause correctly from outside: the two tools were not drawing from the same stream. They were not. simulate.mjs used a private mulberry32 makeRng; playthrough.mjs had its own LCG written to look like it. Both deterministic, both reproducible alone, and "seed 2" named a different fight in each — which breaks the only thing the tool is for. Its own comment claimed a seed here names the same fight there. check-focus carried a third copy of that LCG, so the two guards described the same game with different dice. makeRng is exported and both files use it. A playthrough seed is now exactly the first fight of simulate.mjs --seed <n>: --runs 1 --seed 2 and the playthrough give 9 rounds, 4 of 4 down, 1 dead, both. The other half was my citation rather than the code: the command I sent omitted --mode, so it plays both targeting arms and prints two fights. They read the last line, I quoted the first. The summary line now names the arm. check-focus re-recorded under the shared stream; figures move a point or two. What it buys is that the bimodality analysis now reproduces the published means exactly — 2.31, 3.03, 0.40, 0.42 against the four rows CLEAN GROUND publishes. Under the old LCG it agreed to within a decimal, which looked like corroboration and was two experiments landing near each other. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
796bb7df73
commit
8627fa3536
@@ -187,12 +187,12 @@ check-kits: OK — 25 roles, 10 trades, 218 catalogue items, every kit key resol
|
||||
check-lang: OK — en.json, 1018 keys, no leaf/branch collisions
|
||||
check-templates: OK — 19 templates compile
|
||||
check-behaviour: OK — 76 behavioural tests
|
||||
check-scenarios: OK — 12 scenario files, 79 mechanic tags, every skill named resolves against 62 catalogue entries
|
||||
check-rollable: OK — 78 rolls across 12 scenario files, every one reachable at 25% or better by somebody present
|
||||
check-scenarios: OK — 13 scenario files, 80 mechanic tags, every skill named resolves against 62 catalogue entries
|
||||
check-rollable: OK — 79 rolls across 13 scenario files, every one reachable at 25% or better by somebody present
|
||||
check-creatures: OK — 102 actor specs across 8 sources, every characteristic, skill, kit key, talent, species and style resolves, no duplicate keys
|
||||
check-anatomy: OK — 5 body plans, 36 locations, d20 complete in both modes, every location drawn, every kind handled and destructible, 20 plan changes carried 432 wounds with their severity intact, 1 flyer(s) with a survivable landing
|
||||
check-lethality: OK — 47 creatures, every one fighting exactly as recorded against the frozen party
|
||||
check-focus: OK — focus fire measured against 30 packs, helps in all of them, 28 of them by more than their own noise
|
||||
check-focus: OK — focus fire measured against 31 packs, helps in all of them, 31 of them by more than their own noise
|
||||
check-bestiary: OK — 47 creatures, the document matches the game
|
||||
```
|
||||
<!-- guards:end -->
|
||||
|
||||
+6
-6
@@ -87,12 +87,12 @@ rule for holding an action. Arranging the party so its best weapon fires last wa
|
||||
measured in the simulator and came to nothing distinguishable from noise.
|
||||
|
||||
**What you can do is kill them one at a time.** Against a pack, every agent putting
|
||||
their attacks into the same creature beats spreading them — in 30 of the
|
||||
30 fights in this book whose outcome was ever in doubt, and by more
|
||||
than the measurement’s own noise in 28 of them. It is worth about
|
||||
**8 points** of win rate against a pair and
|
||||
**12 points** against three or more; the best case in the book is
|
||||
3 × Spriggan, which goes 38.9% to 55.5%. Most of that is not the ladder
|
||||
their attacks into the same creature beats spreading them — in **every one** of the
|
||||
31 fights in this book whose outcome was ever in doubt, without exception, and by more
|
||||
than the measurement’s own noise each time. It is worth about
|
||||
**7 points** of win rate against a pair and
|
||||
**11 points** against three or more; the best case in the book is
|
||||
3 × Kelpie, which goes 52.0% to 67.1%. Most of that is not the ladder
|
||||
above: a creature that is dead stops attacking, and one on half its hit points does not
|
||||
attack any less. Held at a fixed pack size the dodge ladder is worth a point or two.
|
||||
|
||||
|
||||
@@ -5765,3 +5765,47 @@ than the page needs to: the bestiary prints the above-noise COUNT from the artif
|
||||
cannot overstate it however it moves, and what the page actually asserts outright is that
|
||||
concentrating fire helps. The guard now checks exactly that, and the page rewrote itself
|
||||
to "in 28 of them" on regeneration.
|
||||
|
||||
## R-265 — two generators, so a citation named two different fights
|
||||
|
||||
`tools/playthrough.mjs` exists to show a reader WHY a measured number is what it is. I
|
||||
cited it to another session — read seed 2, see the wipe the 45% row is made of — and the
|
||||
reproduction failed in front of them. They reported different outcomes at both seeds and
|
||||
guessed the cause correctly from the outside: the two tools were not drawing from the same
|
||||
stream.
|
||||
|
||||
They were not. `simulate.mjs` used a private mulberry32 `makeRng`; `playthrough.mjs` had
|
||||
its own linear congruential generator, written to look like it. Both deterministic, both
|
||||
reproducible on their own, and **"seed 2" named a different fight in each** — which
|
||||
quietly breaks the only thing the tool is for. Its own comment claimed "a seed here names
|
||||
the same fight there". `check-focus` had a third copy of the same LCG, so the two lethality
|
||||
guards described the same game with different dice.
|
||||
|
||||
`makeRng` is exported, and both files use it. A playthrough seed is now exactly the first
|
||||
fight of `simulate.mjs --seed <n>`: verified by running `--runs 1 --seed 2` and the
|
||||
playthrough side by side — 9 rounds, 4 of 4 down, 1 dead, both.
|
||||
|
||||
**The other half was my citation, not the code.** The command I sent omitted `--mode`, so
|
||||
it plays BOTH targeting arms and prints two fights; they read the last line, I quoted the
|
||||
first. The summary line now names the arm — `→ [random] PARTY WIPED …` — so a quotation
|
||||
cannot be ambiguous.
|
||||
|
||||
**What it cost.** check-focus re-recorded under the shared stream: 31 of 47 measurable
|
||||
again, and the numbers move by a point or two each. What it buys is that every figure in
|
||||
the focus baseline is now drawn from the same dice as the lethality baseline, and the
|
||||
bimodality analysis below reproduces the published means **exactly** — 2.31, 3.03, 0.40 and
|
||||
0.42 of 4 or 6 down, against the four rows CLEAN GROUND publishes. Under the old LCG it
|
||||
agreed to within a decimal, which looked like corroboration and was really two different
|
||||
experiments landing near each other.
|
||||
|
||||
**The finding that started it survives, and is now checkable.** The four-player cut against
|
||||
three of the column is bimodal: 23.1% of fights end with nobody down, 45.0% with everybody
|
||||
down, and 11% land on the published mean of 2.31. Six players against six of the column is
|
||||
not bimodal at all — 10 to 18% at every outcome — so this is a property of the cut rather
|
||||
than of the creature. The mechanism is a race: put one of the three down inside five rounds
|
||||
and the wipe rate falls from 58.5% to 19.7%; put down two and it is zero in 2000 fights.
|
||||
68% of fights reach round five with none of them down.
|
||||
|
||||
**The lesson is the one this log keeps recording, one layer out.** A number that cannot be
|
||||
reproduced is a claim, whoever holds it. It was caught because another session tried the
|
||||
citation rather than trusting it, which is exactly what a citation is for.
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"id": "ringbrp",
|
||||
"title": "The Custodians",
|
||||
"description": "A Basic Roleplaying game of agents who cross the crossing to contain what should not be there — and who come back a little less from here each time.",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"compatibility": {
|
||||
"minimum": 13,
|
||||
"verified": "14.364"
|
||||
|
||||
@@ -31,7 +31,7 @@ import { existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { NPCS } from "./content.mjs";
|
||||
import { ROSTER } from "./roster.mjs";
|
||||
import { runFight, seedFor } from "./simulate.mjs";
|
||||
import { runFight, seedFor, makeRng } from "./simulate.mjs";
|
||||
|
||||
const ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, "$1")), "..");
|
||||
const BASELINE = path.join(ROOT, "tools", "focus-baseline.json");
|
||||
@@ -67,7 +67,10 @@ const party = PARTY_KEYS.map(k => {
|
||||
|
||||
/* One generator per arm, derived from the creature's own key, so inserting a creature
|
||||
cannot perturb its neighbours — R-252, learned the hard way. */
|
||||
const rngFor = seed => { let s = seed >>> 0; return () => ((s = (1664525 * s + 1013904223) >>> 0) / 4294967296); };
|
||||
/* R-265: the harness's own generator, not a second one of the same shape. This file used
|
||||
to roll its own LCG, so the two guards described the same game with different dice and
|
||||
no figure here could be reproduced from simulate.mjs. */
|
||||
const rngFor = makeRng;
|
||||
const winRate = (foes, targets, seed) => {
|
||||
let won = 0;
|
||||
for (let i = 0; i < RUNS; i++) {
|
||||
|
||||
+132
-129
@@ -20,66 +20,66 @@
|
||||
"creatures": {
|
||||
"quiet_neighbours_npc": {
|
||||
"n": 6,
|
||||
"spread": 47.4,
|
||||
"focus": 55.7,
|
||||
"gain": 8.3,
|
||||
"noise": 2.5
|
||||
"spread": 47,
|
||||
"focus": 54.9,
|
||||
"gain": 7.9,
|
||||
"noise": 2.7
|
||||
},
|
||||
"keepers": {
|
||||
"n": 5,
|
||||
"spread": 59.9,
|
||||
"focus": 70,
|
||||
"gain": 10.1,
|
||||
"noise": 0.5
|
||||
"spread": 60,
|
||||
"focus": 69.8,
|
||||
"gain": 9.8,
|
||||
"noise": 2.7
|
||||
},
|
||||
"cleaner": {
|
||||
"n": 6,
|
||||
"spread": 57.8,
|
||||
"focus": 71,
|
||||
"gain": 13.2,
|
||||
"noise": 6.8
|
||||
"spread": 59.4,
|
||||
"focus": 70.1,
|
||||
"gain": 10.7,
|
||||
"noise": 1.4
|
||||
},
|
||||
"cleaner_marksman": {
|
||||
"n": 5,
|
||||
"spread": 51.2,
|
||||
"focus": 62.1,
|
||||
"gain": 10.9,
|
||||
"noise": 0.7
|
||||
"spread": 51.8,
|
||||
"focus": 61.9,
|
||||
"gain": 10.1,
|
||||
"noise": 0.5
|
||||
},
|
||||
"revenant": {
|
||||
"n": 3,
|
||||
"spread": 63.1,
|
||||
"focus": 73.3,
|
||||
"gain": 10.2,
|
||||
"noise": 1.6
|
||||
"spread": 61.9,
|
||||
"focus": 75.4,
|
||||
"gain": 13.5,
|
||||
"noise": 2.2
|
||||
},
|
||||
"duplicate": {
|
||||
"n": 5,
|
||||
"spread": 58.4,
|
||||
"focus": 69.3,
|
||||
"gain": 10.9,
|
||||
"noise": 3.2
|
||||
"spread": 60.5,
|
||||
"focus": 69.7,
|
||||
"gain": 9.2,
|
||||
"noise": 2.4
|
||||
},
|
||||
"barghest": {
|
||||
"n": 3,
|
||||
"spread": 26.2,
|
||||
"focus": 36.8,
|
||||
"gain": 10.5,
|
||||
"noise": 2.2
|
||||
"spread": 24.8,
|
||||
"focus": 36.5,
|
||||
"gain": 11.8,
|
||||
"noise": 3.5
|
||||
},
|
||||
"kelpie": {
|
||||
"n": 3,
|
||||
"spread": 54.6,
|
||||
"focus": 67.3,
|
||||
"gain": 12.8,
|
||||
"noise": 1.8
|
||||
"spread": 52,
|
||||
"focus": 67.1,
|
||||
"gain": 15.1,
|
||||
"noise": 2.8
|
||||
},
|
||||
"redcap": {
|
||||
"n": 3,
|
||||
"spread": 31.4,
|
||||
"focus": 44,
|
||||
"gain": 12.6,
|
||||
"noise": 2
|
||||
"spread": 31.1,
|
||||
"focus": 41.9,
|
||||
"gain": 10.9,
|
||||
"noise": 1.8
|
||||
},
|
||||
"boggart": {
|
||||
"n": 2,
|
||||
@@ -87,18 +87,18 @@
|
||||
},
|
||||
"churchgrim": {
|
||||
"n": 3,
|
||||
"spread": 42.1,
|
||||
"focus": 54.7,
|
||||
"gain": 12.6,
|
||||
"noise": 3.4
|
||||
"spread": 43.7,
|
||||
"focus": 55.7,
|
||||
"gain": 12,
|
||||
"noise": 2.1
|
||||
},
|
||||
"supporter": {
|
||||
"n": 2,
|
||||
"pinned": 3.8
|
||||
"pinned": 4
|
||||
},
|
||||
"hollow_man": {
|
||||
"n": 6,
|
||||
"pinned": 92.4
|
||||
"pinned": 91.8
|
||||
},
|
||||
"the_tenant": {
|
||||
"n": 2,
|
||||
@@ -106,57 +106,57 @@
|
||||
},
|
||||
"the_choir": {
|
||||
"n": 6,
|
||||
"pinned": 99.1
|
||||
"pinned": 99.4
|
||||
},
|
||||
"precedent": {
|
||||
"n": 3,
|
||||
"spread": 59.2,
|
||||
"focus": 71.1,
|
||||
"gain": 11.9,
|
||||
"spread": 61,
|
||||
"focus": 72.2,
|
||||
"gain": 11.2,
|
||||
"noise": 0.7
|
||||
},
|
||||
"carrion_file": {
|
||||
"n": 4,
|
||||
"spread": 45.8,
|
||||
"focus": 58.4,
|
||||
"gain": 12.7,
|
||||
"noise": 3.6
|
||||
"spread": 45.2,
|
||||
"focus": 57.3,
|
||||
"gain": 12.1,
|
||||
"noise": 1.3
|
||||
},
|
||||
"the_understudy": {
|
||||
"n": 5,
|
||||
"spread": 60.2,
|
||||
"focus": 71.8,
|
||||
"gain": 11.7,
|
||||
"noise": 0.8
|
||||
"spread": 61.5,
|
||||
"focus": 73,
|
||||
"gain": 11.5,
|
||||
"noise": 6.3
|
||||
},
|
||||
"surveyor": {
|
||||
"n": 2,
|
||||
"spread": 27.5,
|
||||
"focus": 34.5,
|
||||
"gain": 7,
|
||||
"noise": 3.7
|
||||
"spread": 28.8,
|
||||
"focus": 34.4,
|
||||
"gain": 5.6,
|
||||
"noise": 1.9
|
||||
},
|
||||
"quarantine_unit": {
|
||||
"n": 2,
|
||||
"pinned": 0.1
|
||||
"pinned": 0.2
|
||||
},
|
||||
"cuckoo_array": {
|
||||
"n": 2,
|
||||
"spread": 58.3,
|
||||
"spread": 58.6,
|
||||
"focus": 66.2,
|
||||
"gain": 7.9,
|
||||
"noise": 2.1
|
||||
"gain": 7.7,
|
||||
"noise": 3.8
|
||||
},
|
||||
"long_walker": {
|
||||
"n": 2,
|
||||
"pinned": 0.6
|
||||
"pinned": 0.1
|
||||
},
|
||||
"auditor": {
|
||||
"n": 4,
|
||||
"spread": 52,
|
||||
"focus": 64.5,
|
||||
"gain": 12.5,
|
||||
"noise": 1.6
|
||||
"spread": 49.4,
|
||||
"focus": 62.3,
|
||||
"gain": 12.9,
|
||||
"noise": 2.5
|
||||
},
|
||||
"washer_ford": {
|
||||
"n": 2,
|
||||
@@ -167,37 +167,37 @@
|
||||
"pinned": 100
|
||||
},
|
||||
"grindylow": {
|
||||
"n": 3,
|
||||
"spread": 70.6,
|
||||
"focus": 80.1,
|
||||
"gain": 9.4,
|
||||
"noise": 2.9
|
||||
"n": 4,
|
||||
"spread": 30.5,
|
||||
"focus": 42.1,
|
||||
"gain": 11.6,
|
||||
"noise": 1.5
|
||||
},
|
||||
"knockers": {
|
||||
"n": 2,
|
||||
"pinned": 100
|
||||
"n": 6,
|
||||
"pinned": 99.7
|
||||
},
|
||||
"spriggan": {
|
||||
"n": 3,
|
||||
"spread": 38.9,
|
||||
"focus": 55.5,
|
||||
"gain": 16.6,
|
||||
"noise": 3.4
|
||||
"spread": 42.5,
|
||||
"focus": 55.4,
|
||||
"gain": 12.9,
|
||||
"noise": 5.7
|
||||
},
|
||||
"nuckelavee": {
|
||||
"n": 2,
|
||||
"pinned": 8.5
|
||||
"pinned": 8.2
|
||||
},
|
||||
"hedley_kow": {
|
||||
"n": 6,
|
||||
"pinned": 97.6
|
||||
"pinned": 97.8
|
||||
},
|
||||
"apple_man": {
|
||||
"n": 2,
|
||||
"spread": 36.8,
|
||||
"focus": 42.5,
|
||||
"gain": 5.7,
|
||||
"noise": 7.2
|
||||
"spread": 36.6,
|
||||
"focus": 42.1,
|
||||
"gain": 5.5,
|
||||
"noise": 0.8
|
||||
},
|
||||
"the_committee": {
|
||||
"n": 2,
|
||||
@@ -205,24 +205,24 @@
|
||||
},
|
||||
"night_registry": {
|
||||
"n": 4,
|
||||
"spread": 62.1,
|
||||
"focus": 76.2,
|
||||
"gain": 14,
|
||||
"spread": 63.1,
|
||||
"focus": 73.9,
|
||||
"gain": 10.7,
|
||||
"noise": 2.5
|
||||
},
|
||||
"the_locum": {
|
||||
"n": 5,
|
||||
"spread": 49.3,
|
||||
"focus": 61.5,
|
||||
"gain": 12.2,
|
||||
"noise": 2.4
|
||||
"spread": 49.2,
|
||||
"focus": 63.1,
|
||||
"gain": 13.9,
|
||||
"noise": 1.9
|
||||
},
|
||||
"lost_property": {
|
||||
"n": 2,
|
||||
"spread": 54.9,
|
||||
"focus": 64.1,
|
||||
"gain": 9.2,
|
||||
"noise": 2.1
|
||||
"spread": 54.3,
|
||||
"focus": 63.2,
|
||||
"gain": 8.9,
|
||||
"noise": 1.3
|
||||
},
|
||||
"the_minutes": {
|
||||
"n": 2,
|
||||
@@ -230,71 +230,74 @@
|
||||
},
|
||||
"waiting_room": {
|
||||
"n": 3,
|
||||
"spread": 63.2,
|
||||
"focus": 71.8,
|
||||
"gain": 8.6,
|
||||
"noise": 2.1
|
||||
"spread": 63.4,
|
||||
"focus": 70.8,
|
||||
"gain": 7.4,
|
||||
"noise": 0.3
|
||||
},
|
||||
"the_predecessor": {
|
||||
"n": 4,
|
||||
"spread": 55.5,
|
||||
"focus": 69.2,
|
||||
"gain": 13.7,
|
||||
"noise": 6.7
|
||||
"spread": 58.6,
|
||||
"focus": 71,
|
||||
"gain": 12.5,
|
||||
"noise": 5.1
|
||||
},
|
||||
"switchboard": {
|
||||
"n": 6,
|
||||
"pinned": 86.1
|
||||
"pinned": 86.9
|
||||
},
|
||||
"the_census": {
|
||||
"n": 3,
|
||||
"spread": 64.3,
|
||||
"focus": 75.3,
|
||||
"gain": 11,
|
||||
"noise": 4.2
|
||||
"focus": 76.5,
|
||||
"gain": 12.1,
|
||||
"noise": 1
|
||||
},
|
||||
"the_courier": {
|
||||
"n": 2,
|
||||
"spread": 17.5,
|
||||
"focus": 25.2,
|
||||
"gain": 7.7,
|
||||
"noise": 4
|
||||
"spread": 17.8,
|
||||
"focus": 25,
|
||||
"gain": 7.2,
|
||||
"noise": 1.8
|
||||
},
|
||||
"the_relay": {
|
||||
"n": 2,
|
||||
"spread": 52.6,
|
||||
"focus": 58,
|
||||
"gain": 5.4,
|
||||
"noise": 6.7
|
||||
"spread": 52.7,
|
||||
"focus": 58.9,
|
||||
"gain": 6.2,
|
||||
"noise": 2.8
|
||||
},
|
||||
"the_stanchion": {
|
||||
"n": 2,
|
||||
"pinned": 4
|
||||
"pinned": 5.8
|
||||
},
|
||||
"the_yield": {
|
||||
"n": 2,
|
||||
"spread": 48.7,
|
||||
"focus": 62,
|
||||
"gain": 13.3,
|
||||
"noise": 3.8
|
||||
"spread": 46.8,
|
||||
"focus": 57.8,
|
||||
"gain": 11,
|
||||
"noise": 1.5
|
||||
},
|
||||
"the_overwriter": {
|
||||
"n": 3,
|
||||
"spread": 62.6,
|
||||
"focus": 71.7,
|
||||
"gain": 9.2,
|
||||
"noise": 3.9
|
||||
"spread": 64.1,
|
||||
"focus": 72.7,
|
||||
"gain": 8.6,
|
||||
"noise": 1.9
|
||||
},
|
||||
"the_arrears": {
|
||||
"n": 2,
|
||||
"pinned": 14.3
|
||||
"spread": 14.7,
|
||||
"focus": 21,
|
||||
"gain": 6.3,
|
||||
"noise": 1.5
|
||||
},
|
||||
"the_margin": {
|
||||
"n": 5,
|
||||
"spread": 46.7,
|
||||
"focus": 59.6,
|
||||
"gain": 12.8,
|
||||
"noise": 6.2
|
||||
"spread": 45.3,
|
||||
"focus": 59.3,
|
||||
"gain": 14.1,
|
||||
"noise": 2.3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import { readFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { NPCS } from "./content.mjs";
|
||||
import { ROSTER } from "./roster.mjs";
|
||||
import { runFight } from "./simulate.mjs";
|
||||
import { runFight, makeRng } from "./simulate.mjs";
|
||||
|
||||
const ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, "$1")), "..");
|
||||
const base = JSON.parse(readFileSync(path.join(ROOT, "tools", "lethality-baseline.json"), "utf8"));
|
||||
@@ -59,8 +59,9 @@ const rec = focus.creatures[KEY];
|
||||
defect this file exists to help find. Solo also matches what check-lethality records. */
|
||||
const N = Number(opt("--count", 0)) || (rec?.gain !== undefined ? rec.n : 1);
|
||||
|
||||
/* The same generator shape the guards use, so a seed here names the same fight there. */
|
||||
const mk = seed => { let s = seed >>> 0; return () => ((s = (1664525 * s + 1013904223) >>> 0) / 4294967296); };
|
||||
/* THE generator the guards use, not merely one of the same shape. A seed here names the
|
||||
first fight of `simulate.mjs --seed <n>` exactly. */
|
||||
const mk = makeRng;
|
||||
const firstName = c => (c.name ?? "?").split(" ")[0];
|
||||
const hp = c => `${Math.max(0, c.hp)}/${c.hpMax}`;
|
||||
|
||||
@@ -116,7 +117,7 @@ for (const mode of MODES) {
|
||||
: " — party picking targets at random";
|
||||
console.log(`\n${"=".repeat(78)}\n${N} × ${spec.name.toUpperCase()}${how}\n${"=".repeat(78)}`);
|
||||
console.log(lines.join("\n"));
|
||||
console.log(`\n → ${r.won ? "PARTY WINS" : r.wiped ? "PARTY WIPED" : "neither side finished it"}`
|
||||
console.log(`\n → [${N > 1 ? mode : "solo"}] ${r.won ? "PARTY WINS" : r.wiped ? "PARTY WIPED" : "neither side finished it"}`
|
||||
+ ` in ${r.rounds} rounds · ${r.partyDown} of ${party.length} down · ${r.dead} dead`);
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -98,7 +98,11 @@ export function seedFor(base, key = "") {
|
||||
}
|
||||
|
||||
/** mulberry32 — small, fast, and seedable, which is the only property that matters. */
|
||||
function makeRng(seed) {
|
||||
/* R-265. Exported because anything that cites a measured fight has to draw from the same
|
||||
stream to name the same fight. tools/playthrough.mjs had its own LCG, so "seed 2" meant
|
||||
one fight there and a different one here, which quietly broke the only thing that tool
|
||||
exists for. */
|
||||
export function makeRng(seed) {
|
||||
let a = seed >>> 0;
|
||||
return () => {
|
||||
a = (a + 0x6D2B79F5) >>> 0;
|
||||
|
||||
Reference in New Issue
Block a user