feat(ludic.steps): chapters of steps, their kinds, progress and a party's pooled shares

A step is (kind, param, need) and a question about state: a kind has a
shape (yes, a count, a mask counted, every bit of a mask) and a pool
(world, any, sum, or, max, each), handed in by the game as StepsKind
records. An arc is chapters of up to STEPS_PER_CHAPTER steps; steps_check
sticks each met step of the current chapter (STEPS_MET) and opens the
next when all are (STEPS_CHAPTER), so a step met before its chapter
ticks at once. With company each seat's shares are held per chapter,
pooled as the kind says (steps_met, steps_party_got), counted for an
EACH step (steps_each, steps_lacking), and a leaver takes theirs along.

Port: StepsWorld { value(kind, param, player) (required), party,
present }. The package knows no kind's meaning and no chapter's words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-25 06:02:39 +03:00
parent 4318adc98c
commit 31e6740033
10 changed files with 719 additions and 0 deletions

View file

@ -0,0 +1,78 @@
# arc.ludic - an arc is a table of chapters, each a table of up to STEPS_PER_CHAPTER steps. The
# game builds one with steps_chapter_add / steps_add; what a chapter is called is the game's.
# empty the tables for another arc (the progress goes back to the first chapter)
export function steps_arc_clear() -> void {
steps__n = new []int
steps__kind = new []int
steps__param = new []int
steps__need = new []int
steps__cur = 0
steps__done = 0
}
function steps__ready() -> void { if steps__n == null { steps_arc_clear() } }
# open the next chapter; its number
export function steps_chapter_add() -> int {
steps__ready()
push(steps__n, 0)
for i in 0 .. STEPS_PER_CHAPTER {
push(steps__kind, -1)
push(steps__param, 0)
push(steps__need, 0)
}
return len(steps__n) - 1
}
# a step in the chapter just opened; false when there is no chapter or it is full
export function steps_add(kind: int, param: int, need: int) -> bool {
steps__ready()
let c = len(steps__n) - 1
if c < 0 or steps__n[c] >= STEPS_PER_CHAPTER { return false }
let k = c * STEPS_PER_CHAPTER + steps__n[c]
steps__kind[k] = kind
steps__param[k] = param
steps__need[k] = need
steps__n[c] += 1
return true
}
export function steps_count() -> int {
if steps__n == null { return 0 }
return len(steps__n)
}
export function steps_in(ch: int) -> int {
if ch < 0 or ch >= steps_count() { return 0 }
return steps__n[ch]
}
# a step by its flat index, ch * STEPS_PER_CHAPTER + i (-1, 0, 0 past the table)
export function steps_kind_at(k: int) -> int {
if steps__kind == null or k < 0 or k >= len(steps__kind) { return -1 }
return steps__kind[k]
}
export function steps_param_at(k: int) -> int {
if steps__param == null or k < 0 or k >= len(steps__param) { return 0 }
return steps__param[k]
}
export function steps_need_at(k: int) -> int {
if steps__need == null or k < 0 or k >= len(steps__need) { return 0 }
return steps__need[k]
}
export function steps_kind(ch: int, i: int) -> int { return steps_kind_at(ch * STEPS_PER_CHAPTER + i) }
export function steps_param(ch: int, i: int) -> int { return steps_param_at(ch * STEPS_PER_CHAPTER + i) }
export function steps_need(ch: int, i: int) -> int { return steps_need_at(ch * STEPS_PER_CHAPTER + i) }
# the chapter being played, and which of its steps are done (sticky)
export function steps_current() -> int { return steps__cur }
export function steps_done_mask() -> int { return steps__done }
export function steps_done(i: int) -> bool { return (steps__done & (1 << i)) != 0 }
export function steps_finished() -> bool { return steps__cur >= steps_count() }
# the progress outright: a load, the host's word, a test
export function steps_set_current(ch: int) -> void { steps__cur = ch }
export function steps_set_done(mask: int) -> void { steps__done = mask }