feat(base): 0.R4 - a queue keeps its own count, so every package verb takes only its own state; ludic migrate state --prune

ludic.base's Queue<T> carries a QueueTag (its name and pending count): queue_new(name), q_push(q, v),
q_drain(q), q_clear(q) take no BaseState, and core_undrained(tags) names the given queues still holding
facts. A reducer on a package's state can now call that package's verbs (wallet_earn(wallet_st, n)).

ludic migrate state --prune (ludicc --migrate-prune) takes out each state parameter a function no
longer uses, nor anything it calls, and the argument that fills it - including an argument for a
parameter the callee has dropped, which is taken out before the call is checked, so a generic's T is
told by the argument that says it. A reducer keeps its state. --dry-run now counts the edits it would
make. Every package was moved with it: 608 base_st parameters and their arguments, 1889 edits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-26 04:19:56 +03:00
parent 8cf4b3fed6
commit 71735b10a2
151 changed files with 58668 additions and 54719 deletions

View file

@ -28,9 +28,9 @@ program FishingTest {
bind FishingWorld { depth: fn depth, afloat: fn afloat, has_bait: fn has_bait, has_lure: fn has_lure, skill: fn fake_skill, level: fn fake_level }
function fresh(base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) -> void {
function fresh(fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) -> void {
fishing_config(fishing_st, 0.15, 2.5, 99)
fishing_reset(base_st, fishing_st)
fishing_reset(fishing_st)
fishing_test_st.bait = false
fishing_test_st.lure = false
fishing_test_st.boat = false
@ -38,89 +38,89 @@ program FishingTest {
fishing_test_st.skill = 0.0
}
function facts(base_st: mut BaseState, fishing_st: mut FishingState) -> []FishingFact { return q_drain(base_st, fishing_facts(base_st, fishing_st)) }
function facts(fishing_st: mut FishingState) -> []FishingFact { return q_drain(fishing_facts(fishing_st)) }
function saw(fs: []FishingFact, what: int) -> bool {
for i in 0 .. len(fs) { if fs[i].what == what { return true } }
return false
}
# run until it bites, then strike
function hook(base_st: mut BaseState, fishing_st: mut FishingState) -> void {
function hook(fishing_st: mut FishingState) -> void {
fishing_set_wait(fishing_st, 0.0)
fishing_run(base_st, fishing_st, 0.02)
fishing_press(base_st, fishing_st)
fishing_run(fishing_st, 0.02)
fishing_press(fishing_st)
}
# hold the marker in the green and press, until it is landed or `n` presses are spent
function play(base_st: mut BaseState, fishing_st: mut FishingState, n: int) -> void {
function play(fishing_st: mut FishingState, n: int) -> void {
for i in 0 .. n {
if fishing_state(fishing_st) != FISHING_REEL { return }
var guard = 0
while (fishing_running(fishing_st) or fishing_marker(fishing_st) <= fishing_window_lo(fishing_st) or fishing_marker(fishing_st) >= fishing_window_hi(fishing_st)) and guard < 4000 {
fishing_run(base_st, fishing_st, 0.005)
fishing_run(fishing_st, 0.005)
guard += 1
}
if fishing_state(fishing_st) == FISHING_REEL { fishing_press(base_st, fishing_st) }
if fishing_state(fishing_st) == FISHING_REEL { fishing_press(fishing_st) }
}
}
test "a cast lands only in water, and never twice" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
expect_eq(fishing_cast(base_st, fishing_st, 5.0, 0.0), FISHING_NOT_WATER)
test "a cast lands only in water, and never twice" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
expect_eq(fishing_cast(fishing_st, 5.0, 0.0), FISHING_NOT_WATER)
expect(not fishing_active(fishing_st))
expect_eq(fishing_cast(base_st, fishing_st, 20.0, 0.0), FISHING_CAST_OK)
expect_eq(fishing_cast(fishing_st, 20.0, 0.0), FISHING_CAST_OK)
expect_eq(fishing_state(fishing_st), FISHING_WAIT)
expect_eq(fishing_cast(base_st, fishing_st, 20.0, 0.0), FISHING_BUSY)
expect_eq(fishing_cast(fishing_st, 20.0, 0.0), FISHING_BUSY)
fishing_test_st.boat = true
fishing_stop(fishing_st)
expect_eq(fishing_cast(base_st, fishing_st, 0.0, 0.0), FISHING_CAST_OK)
expect_eq(fishing_cast(fishing_st, 0.0, 0.0), FISHING_CAST_OK)
}
test "bait is used and said, and halves the wait" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
fishing_cast(base_st, fishing_st, 20.0, 0.0)
expect(not saw(facts(base_st, fishing_st), FISHING_BAIT_USED))
test "bait is used and said, and halves the wait" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
fishing_cast(fishing_st, 20.0, 0.0)
expect(not saw(facts(fishing_st), FISHING_BAIT_USED))
var plain = 0
while fishing_state(fishing_st) == FISHING_WAIT {
fishing_run(base_st, fishing_st, 0.1)
fishing_run(fishing_st, 0.1)
plain += 1
}
expect(plain <= 201)
fresh(base_st, fishing_st, fishing_test_st)
fresh(fishing_st, fishing_test_st)
fishing_test_st.bait = true
fishing_cast(base_st, fishing_st, 20.0, 0.0)
let fs = facts(base_st, fishing_st)
fishing_cast(fishing_st, 20.0, 0.0)
let fs = facts(fishing_st)
expect(saw(fs, FISHING_BAIT_USED))
expect(fs[0].bait)
var baited = 0
while fishing_state(fishing_st) == FISHING_WAIT {
fishing_run(base_st, fishing_st, 0.1)
fishing_run(fishing_st, 0.1)
baited += 1
}
expect(baited <= 101)
}
test "a bite missed is gone, a bite struck is hooked" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
fishing_cast(base_st, fishing_st, 20.0, 0.0)
test "a bite missed is gone, a bite struck is hooked" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
fishing_cast(fishing_st, 20.0, 0.0)
fishing_set_wait(fishing_st, 0.0)
fishing_run(base_st, fishing_st, 0.02)
fishing_run(fishing_st, 0.02)
expect_eq(fishing_state(fishing_st), FISHING_BITE_ON)
expect(fishing_species(fishing_st) >= 0)
fishing_run(base_st, fishing_st, 2.0)
fishing_run(fishing_st, 2.0)
expect(not fishing_active(fishing_st))
expect(saw(facts(base_st, fishing_st), FISHING_MISSED))
fishing_cast(base_st, fishing_st, 20.0, 0.0)
hook(base_st, fishing_st)
expect(saw(facts(fishing_st), FISHING_MISSED))
fishing_cast(fishing_st, 20.0, 0.0)
hook(fishing_st)
expect_eq(fishing_state(fishing_st), FISHING_REEL)
expect(saw(facts(base_st, fishing_st), FISHING_HOOKED))
expect(saw(facts(fishing_st), FISHING_HOOKED))
}
test "everyday fish only without a lure, sized and weighed from the data" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
test "everyday fish only without a lure, sized and weighed from the data" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
for i in 0 .. 40 {
fishing_cast(base_st, fishing_st, 20.0, 0.0)
hook(base_st, fishing_st)
fishing_cast(fishing_st, 20.0, 0.0)
hook(fishing_st)
let s = fishing_species(fishing_st)
expect(s != FISH_OLD_MAROON)
let k = FishSpecies[s]
@ -130,13 +130,13 @@ program FishingTest {
expect(fishing_weight_of(FISH_CUTTHROAT, 50) > fishing_weight_of(FISH_CUTTHROAT, 30))
}
test "reeled in the green three times, it is landed and counted" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
fishing_cast(base_st, fishing_st, 20.0, 0.0)
hook(base_st, fishing_st)
facts(base_st, fishing_st)
play(base_st, fishing_st, 3)
let fs = facts(base_st, fishing_st)
test "reeled in the green three times, it is landed and counted" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
fishing_cast(fishing_st, 20.0, 0.0)
hook(fishing_st)
facts(fishing_st)
play(fishing_st, 3)
let fs = facts(fishing_st)
expect(saw(fs, FISHING_CAUGHT))
expect_eq(fishing_caught(fishing_st), 1)
expect(fishing_biggest(fishing_st) > 0)
@ -146,109 +146,109 @@ program FishingTest {
expect(last.x == 20.0)
}
test "a press outside the green throws the hook" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
fishing_cast(base_st, fishing_st, 20.0, 0.0)
hook(base_st, fishing_st)
while fishing_marker(fishing_st) < fishing_window_hi(fishing_st) + 0.01 { fishing_run(base_st, fishing_st, 0.005) }
fishing_press(base_st, fishing_st)
expect(saw(facts(base_st, fishing_st), FISHING_LINE_SNAPPED))
test "a press outside the green throws the hook" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
fishing_cast(fishing_st, 20.0, 0.0)
hook(fishing_st)
while fishing_marker(fishing_st) < fishing_window_hi(fishing_st) + 0.01 { fishing_run(fishing_st, 0.005) }
fishing_press(fishing_st)
expect(saw(facts(fishing_st), FISHING_LINE_SNAPPED))
expect(not fishing_active(fishing_st))
}
test "a fight left alone goes slack" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
fishing_cast(base_st, fishing_st, 20.0, 0.0)
hook(base_st, fishing_st)
for i in 0 .. 700 { fishing_run(base_st, fishing_st, 0.02) }
expect(saw(facts(base_st, fishing_st), FISHING_SLACK))
test "a fight left alone goes slack" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
fishing_cast(fishing_st, 20.0, 0.0)
hook(fishing_st)
for i in 0 .. 700 { fishing_run(fishing_st, 0.02) }
expect(saw(facts(fishing_st), FISHING_SLACK))
expect_eq(fishing_caught(fishing_st), 0)
}
test "a legend takes the lure, runs, turns, and is landed at five" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
test "a legend takes the lure, runs, turns, and is landed at five" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
fishing_test_st.lure = true
fishing_cast(base_st, fishing_st, 20.0, 0.0)
hook(base_st, fishing_st)
fishing_cast(fishing_st, 20.0, 0.0)
hook(fishing_st)
expect_eq(fishing_species(fishing_st), FISH_OLD_MAROON)
expect_eq(fishing_need(fishing_st), 5)
let w0 = fishing_window(fishing_st)
play(base_st, fishing_st, 2)
play(fishing_st, 2)
expect(fishing_window(fishing_st) < w0)
for i in 0 .. 400 {
if not fishing_running(fishing_st) { fishing_run(base_st, fishing_st, 0.02) }
if not fishing_running(fishing_st) { fishing_run(fishing_st, 0.02) }
}
let fs = facts(base_st, fishing_st)
let fs = facts(fishing_st)
expect(saw(fs, FISHING_RUNS))
if fishing_running(fishing_st) {
let before = fishing_hits(fishing_st)
fishing_press(base_st, fishing_st)
fishing_press(fishing_st)
expect_eq(fishing_hits(fishing_st), before - 1)
}
play(base_st, fishing_st, 40)
play(fishing_st, 40)
expect(fishing_legend_caught(fishing_st))
let last = facts(base_st, fishing_st)
let last = facts(fishing_st)
expect(last[len(last) - 1].lure)
}
test "gentle: one press inside the ring, and the ring closes" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
test "gentle: one press inside the ring, and the ring closes" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
fishing_test_st.level = FISHING_GENTLE
fishing_cast(base_st, fishing_st, 20.0, 0.0)
hook(base_st, fishing_st)
fishing_cast(fishing_st, 20.0, 0.0)
hook(fishing_st)
expect(fishing_gentle(fishing_st))
expect_eq(fishing_need(fishing_st), 1)
fishing_press(base_st, fishing_st)
fishing_press(fishing_st)
expect_eq(fishing_caught(fishing_st), 1)
fishing_cast(base_st, fishing_st, 20.0, 0.0)
hook(base_st, fishing_st)
fishing_run(base_st, fishing_st, 2.1)
expect(saw(facts(base_st, fishing_st), FISHING_LINE_SNAPPED))
fishing_cast(fishing_st, 20.0, 0.0)
hook(fishing_st)
fishing_run(fishing_st, 2.1)
expect(saw(facts(fishing_st), FISHING_LINE_SNAPPED))
}
test "a legend fights on gentle too" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
test "a legend fights on gentle too" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
fishing_test_st.level = FISHING_GENTLE
fishing_test_st.lure = true
fishing_cast(base_st, fishing_st, 20.0, 0.0)
hook(base_st, fishing_st)
fishing_cast(fishing_st, 20.0, 0.0)
hook(fishing_st)
expect(not fishing_gentle(fishing_st))
expect_eq(fishing_need(fishing_st), 5)
}
test "hard closes the window for everyday fish, relaxed keeps it centred" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
fishing_cast(base_st, fishing_st, 20.0, 0.0)
hook(base_st, fishing_st)
test "hard closes the window for everyday fish, relaxed keeps it centred" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
fishing_cast(fishing_st, 20.0, 0.0)
hook(fishing_st)
expect(fishing_window_lo(fishing_st) + fishing_window_hi(fishing_st) > 0.999 and fishing_window_lo(fishing_st) + fishing_window_hi(fishing_st) < 1.001)
fishing_stop(fishing_st)
fishing_test_st.level = FISHING_HARD
fishing_cast(base_st, fishing_st, 20.0, 0.0)
hook(base_st, fishing_st)
fishing_cast(fishing_st, 20.0, 0.0)
hook(fishing_st)
let w0 = fishing_window(fishing_st)
play(base_st, fishing_st, 1)
play(fishing_st, 1)
expect(fishing_window(fishing_st) < w0)
}
test "skill makes a fish bigger" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
test "skill makes a fish bigger" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
fishing_test_st.skill = 1.0
fishing_cast(base_st, fishing_st, 20.0, 0.0)
hook(base_st, fishing_st)
fishing_cast(fishing_st, 20.0, 0.0)
hook(fishing_st)
let k = FishSpecies[fishing_species(fishing_st)]
expect(fishing_cm(fishing_st) >= k.cm_min + 60)
}
test "the record is saved, and a line in the water is not" (base_st: mut BaseState, fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(base_st, fishing_st, fishing_test_st)
test "the record is saved, and a line in the water is not" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
fresh(fishing_st, fishing_test_st)
fishing_record_set(fishing_st, 7, 52, true)
fishing_cast(base_st, fishing_st, 20.0, 0.0)
fishing_cast(fishing_st, 20.0, 0.0)
let root = save_tree()
save_section(root, "fishing", 1, fishing_save(fishing_st))
let text = save_encode(root)
fishing_reset(base_st, fishing_st)
fishing_reset(fishing_st)
let n = load_section(save_decode(text), "fishing")
fishing_load(base_st, fishing_st, n.data, n.version)
fishing_load(fishing_st, n.data, n.version)
expect_eq(fishing_caught(fishing_st), 7)
expect_eq(fishing_biggest(fishing_st), 52)
expect(fishing_legend_caught(fishing_st))