flygammon-handout.tgz

Ровный робот 853 points / 58 solvers misc сыграй в нарды против Искусственного Интеллекта©®℗! тебе нужно выиграть его 15 раз подряд. чтобы всё было честно, игра проходит на блокчейне, чтобы точно никто не смог никого обмануть. тут все ребята ровные, ничего не сломается

заходит как то клод кодекс и дипсик на борду а там таска на нарды...

flygammon-handout.tgz 184 KiB ctfcup{...} submit destroy instance extended https://zkls7g1p1hosw2f0.instances.ctfcup.online expires: 31.10.2026 21:42:58(1796 seconds)

Dr.Binary
todo_write
run_sandbox
read_file
run_sandbox
read_file
read_file
read_file
read_file
read_file
read_file
read_file
read_file
read_file
read_file
read_file
run_sandbox
run_sandbox
run_sandbox
write_file
run_sandbox
list_files
run_sandbox
run_sandbox

Instance is live. Key facts: N=15, tokens=80, fresh game, G=2, H=g^s mod p. The title "Ровный" (smooth/even) hints at a smooth prime — let me factor p-1.

write_file
run_sandbox

p−1 is fully smooth (2 × 13 primes of ~20 bits) — Pohlig–Hellman recovers the oracle's secret s trivially. Then we can compute every dice roll (present and future) ourselves. Let me recover s:

write_file
run_sandbox

s recovered and verified. Now I can compute any future dice roll. Next: replicate the oracle bot exactly (model weights + engine) to simulate games before committing. Let me parse model.fly:

run_sandbox
run_sandbox

The model file layout is unclear — rather than guess float formats, I'll compile the handout's own Rust crate to get a bit-exact oracle policy. Let me check the Cargo setup:

run_sandbox
run_sandbox
run_sandbox
run_sandbox
run_sandbox

No ASCII keys — need burn 0.21's exact CompactRecorder format. Let me fetch its source:

run_sandbox
run_sandbox

The stats (31% zero / 31% denormal / 38% normal, uniformly) smell like a periodic byte pattern. Let me check for structural periodicity:

run_sandbox

Let me test decodings systematically — I'll port the feature encoder + forward pass and score candidate decodings against sanity benchmarks (opening ≈ 0.5 win-prob, near-win ≈ 1.0):

write_file
run_sandbox
run_sandbox
run_sandbox
run_sandbox
run_sandbox
run_sandbox
run_sandbox
run_sandbox

The denormals are likely decay-killed weights of rarely-active input features (unary slots that are almost always 0) — plain f32 may be right after all. Let me sweep layouts using a strong signal: outputs must vary across random-play positions and correlate with race progress:

write_file
run_sandbox

tr=True (weights stored [in,out]) stands out. Let me refine — per-layer transpose combos + a cleaner benchmark (mover with k checkers off vs untouched opponent):

write_file
run_sandbox

I need certainty on the format — installing Rust to test-load model.fly with burn 0.21's actual recorders:

run_sandbox
run_sandbox
run_sandbox
run_sandbox
run_sandbox
run_sandbox

All burn formats ruled out — it's a custom dump. Let me fix the sweep crash and complete the grid, plus check u16 pair relations:

run_sandbox

Let me re-read train.rs carefully — it may reveal how weights were produced/dumped:

run_sandbox
run_sandbox
run_sandbox
run_sandbox
run_sandbox

The zero-density spike in the l2 region suggests a real trained net with dead weights. Let me build a mirror-symmetry test (a trained evaluator must satisfy r0(board) + r0(flip(board)) ≈ 1) across all layouts:

write_file
run_sandbox
run_sandbox

Time is limited (instance expires soon). New approach: use the blockchain itself as ground truth — the bot's observed moves will identify the correct model decode. Let me build the full player framework:

write_file

Now the bot-replica (exact port of choose_2ply) and the observation-based decode tester:

write_file
write_file
run_sandbox
edit_file
run_sandbox
run_sandbox
run_sandbox

Dice predictions confirmed live — turn 14 predicted (5,4) = actual (5,4). The sacrifice game is mid-flight; let me resume it to collect more observations, then run decode tests:

write_file
run_sandbox
run_sandbox
edit_file
run_sandbox
run_sandbox
write_file
run_sandbox

No matches — but I spotted a bug in my recorder: I recorded the bot's input board as flip(pre-my-move) instead of the board during the bot's turn. Let me fix and also sanity-check that observed ends are reachable per my engine:

write_file
run_sandbox

My recorder captured the wrong board (pre-my-move instead of during-bot-turn). The on-chain boardPacked() read while it's the bot's turn is already the bot's perspective. Fixing the collector:

write_file
run_sandbox
run_sandbox
run_sandbox
run_sandbox

RPC is heavily rate-limited (~2.5s/read → a full state() costs 23s). I need batched JSON-RPC — one HTTP round trip per state read:

edit_file
run_sandbox

Batched reads: 0.82s. Now collect observations properly:

run_sandbox
run_sandbox

Rather than burn tokens, let me extract structural evidence: in a row-major weight matrix, dead hidden units create contiguous runs of near-zero weights whose length reveals the orientation (runs≈203 → [out,in], runs≈80 → [in,out]):

run_sandbox
run_sandbox
run_sandbox

What if it's a byte-plane dump (all 1st bytes, then all 2nd bytes, ...)? Testing plane permutations:

run_sandbox

Let me collect clean observations efficiently (deriving the bot's input board offline from my own move):

write_file
run_sandbox

Engine verified (6/6 reachable). Testing decodes against clean observations:

run_sandbox

Two decodes replicate the bot 6/6: W1=[in,out], W3=[in,out], W2 either orientation (square). Let me quantify whether the W2 ambiguity even matters, and check chain state:

run_sandbox

Let me check chain state and build the winner engine — policy: my 1-ply greedy with known future dice vs exact bot replica, full-game simulation before committing, skip otherwise:

run_sandbox
write_file
run_sandbox
run_sandbox

Simulation works — 3/4 wins with greedy play. With skip-filtering (only commit winning sims), nearly every committed game should win. Let me check win margins, then write the live winner:

run_sandbox

Found a critical bug in my simulator: after each move I forgot to flip() the board for the next player's perspective. Fixing and re-measuring:

edit_file
run_sandbox

Realistic now: 6/8 wins, games ~24-34 plies. Time to write the live winner loop:

write_file
run_sandbox
[stopped: the account is out of credit]
Out of credits — this response was cut short.