wip(0.S3): packages and examples migrated again from their pre-0.S sources in one run

ludic migrate state packages <every example program> packages/ludic.lab/example/plate.ludic
  1804 vars into 126 states, 64 into lets; 23498 edits in 460 files

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-25 15:31:34 +03:00
parent 5ffe50ed02
commit 19fcf60599
459 changed files with 17862 additions and 17603 deletions

View file

@ -1,48 +1,45 @@
# calendar.ludic - where a day falls: its month, its year, and its season, a pure function of the
# day. The game says how long a month is, how many make a year, and which season each month is.
var cal_month_days: int = 30
var cal_year_months: int = 12
var cal_season: []int = null
export function clock_calendar(month_days: int, season_of_month: []int) -> void {
cal_month_days = month_days
cal_year_months = len(season_of_month)
cal_season = season_of_month
export function clock_calendar(clock_st: mut ClockState, month_days: int, season_of_month: []int) -> void {
clock_st.cal_month_days = month_days
clock_st.cal_year_months = len(season_of_month)
clock_st.cal_season = season_of_month
}
export function clock_month_days() -> int { return cal_month_days }
export function clock_year_months() -> int { return cal_year_months }
export function clock_month_days(clock_st: ClockState) -> int { return clock_st.cal_month_days }
export function clock_year_months(clock_st: ClockState) -> int { return clock_st.cal_year_months }
# the month a day falls in, 0 .. months - 1
export function clock_month_of(day: int) -> int { return ((day - 1) / cal_month_days) % cal_year_months }
export function clock_year_of(day: int) -> int { return (day - 1) / (cal_month_days * cal_year_months) + 1 }
export function clock_day_of_month_of(day: int) -> int { return (day - 1) % cal_month_days + 1 }
export function clock_month_of(clock_st: ClockState, day: int) -> int { return ((day - 1) / clock_st.cal_month_days) % clock_st.cal_year_months }
export function clock_year_of(clock_st: ClockState, day: int) -> int { return (day - 1) / (clock_st.cal_month_days * clock_st.cal_year_months) + 1 }
export function clock_day_of_month_of(clock_st: ClockState, day: int) -> int { return (day - 1) % clock_st.cal_month_days + 1 }
export function clock_season_of(day: int) -> int {
if cal_season == null { return 0 }
return cal_season[clock_month_of(day)]
export function clock_season_of(clock_st: ClockState, day: int) -> int {
if clock_st.cal_season == null { return 0 }
return clock_st.cal_season[clock_month_of(clock_st, day)]
}
export function clock_month() -> int { return clock_month_of(ck_day) }
export function clock_year() -> int { return clock_year_of(ck_day) }
export function clock_day_of_month() -> int { return clock_day_of_month_of(ck_day) }
export function clock_season() -> int { return clock_season_of(ck_day) }
export function clock_month(clock_st: ClockState) -> int { return clock_month_of(clock_st, clock_st.ck_day) }
export function clock_year(clock_st: ClockState) -> int { return clock_year_of(clock_st, clock_st.ck_day) }
export function clock_day_of_month(clock_st: ClockState) -> int { return clock_day_of_month_of(clock_st, clock_st.ck_day) }
export function clock_season(clock_st: ClockState) -> int { return clock_season_of(clock_st, clock_st.ck_day) }
# days from `day` until the season is another; 0 when a year has only one
export function clock_days_to_change_from(day: int) -> int {
let here = clock_season_of(day)
for d in 1 .. cal_month_days * cal_year_months {
if clock_season_of(day + d) != here { return d }
export function clock_days_to_change_from(clock_st: ClockState, day: int) -> int {
let here = clock_season_of(clock_st, day)
for d in 1 .. clock_st.cal_month_days * clock_st.cal_year_months {
if clock_season_of(clock_st, day + d) != here { return d }
}
return 0
}
export function clock_days_to_change() -> int { return clock_days_to_change_from(ck_day) }
export function clock_days_to_change(clock_st: ClockState) -> int { return clock_days_to_change_from(clock_st, clock_st.ck_day) }
# the first day (counted from day one) that falls in a season; -1 when none does
export function clock_first_day_of(season: int) -> int {
for d in 1 .. cal_month_days * cal_year_months + 1 {
if clock_season_of(d) == season { return d }
export function clock_first_day_of(clock_st: ClockState, season: int) -> int {
for d in 1 .. clock_st.cal_month_days * clock_st.cal_year_months + 1 {
if clock_season_of(clock_st, d) == season { return d }
}
return -1
}

View file

@ -1,21 +1,21 @@
# queries.ludic - what the world asks the clock
export function clock_day() -> int { return ck_day }
export function clock_hours() -> float { return ck_hours }
export function clock_moon() -> float { return ck_moon }
export function clock_scale() -> float { return ck_scale }
export function clock_day(clock_st: ClockState) -> int { return clock_st.ck_day }
export function clock_hours(clock_st: ClockState) -> float { return clock_st.ck_hours }
export function clock_moon(clock_st: ClockState) -> float { return clock_st.ck_moon }
export function clock_scale(clock_st: ClockState) -> float { return clock_st.ck_scale }
# game seconds per real second right now, the rest speed-up included
export function clock_rate() -> float { return ck_scale * ck_rest() }
export function clock_rate(clock_st: ClockState) -> float { return clock_st.ck_scale * ck_rest() }
# the game hours `dt` real seconds are worth at the current rate
export function clock_hours_in(dt: float) -> float { return dt * clock_rate() / 3600.0 }
export function clock_hours_in(clock_st: ClockState, dt: float) -> float { return dt * clock_rate(clock_st) / 3600.0 }
export function clock_is_night() -> bool { return ck_hours > ck_night_from or ck_hours < ck_night_to }
export function clock_is_night(clock_st: ClockState) -> bool { return clock_st.ck_hours > clock_st.ck_night_from or clock_st.ck_hours < clock_st.ck_night_to }
# "07:05"
export function clock_hhmm() -> string {
let h = int(Math.floor(ck_hours))
let m = int(Math.floor((ck_hours - float(h)) * 60.0))
export function clock_hhmm(clock_st: ClockState) -> string {
let h = int(Math.floor(clock_st.ck_hours))
let m = int(Math.floor((clock_st.ck_hours - float(h)) * 60.0))
var hs = `{h}`
var ms = `{m}`
if h < 10 { hs = `0{h}` }

View file

@ -20,23 +20,28 @@ export property DayTurned {
how: int = 0
}
var ck_day: int = 1
var ck_hours: float = 0.0
var ck_moon: float = 0.0
var ck_scale: float = 60.0 # game seconds per real second
var ck_start_hours: float = 8.0
var ck_night_from: float = 20.0
var ck_night_to: float = 6.0
var ck_moon_days: float = 29.5
var ck_moon_lo: float = 0.0
var ck_moon_hi: float = 1.0
var ck_dice: Rng = null
var ck_days: Queue<DayTurned> = null
export state ClockState {
cal_month_days: int = 30
cal_year_months: int = 12
cal_season: []int = null
ck_day: int = 1
ck_hours: float = 0.0
ck_moon: float = 0.0
ck_scale: float = 60.0 # game seconds per real second
ck_start_hours: float = 8.0
ck_night_from: float = 20.0
ck_night_to: float = 6.0
ck_moon_days: float = 29.5
ck_moon_lo: float = 0.0
ck_moon_hi: float = 1.0
ck_dice: Rng = null
ck_days: Queue<DayTurned> = null
}
# the facts: each day that turned, in order; the game drains it and runs its morning
export function clock_days() -> Queue<DayTurned> {
if ck_days == null { ck_days = queue_new("clock.days") }
return ck_days
export function clock_days(base_st: mut BaseState, clock_st: mut ClockState) -> Queue<DayTurned> {
if clock_st.ck_days == null { clock_st.ck_days = queue_new(base_st, "clock.days") }
return clock_st.ck_days
}
function ck_owns() -> bool { return ClockWorld.owns_world() }
@ -44,15 +49,15 @@ function ck_owns() -> bool { return ClockWorld.owns_world() }
function ck_rest() -> float { return ClockWorld.rest_scale() }
# when a trip starts, when the night is, and how long the moon's month is
export function clock_config(start_hours: float, night_from: float, night_to: float) -> void {
ck_start_hours = start_hours
ck_night_from = night_from
ck_night_to = night_to
export function clock_config(clock_st: mut ClockState, start_hours: float, night_from: float, night_to: float) -> void {
clock_st.ck_start_hours = start_hours
clock_st.ck_night_from = night_from
clock_st.ck_night_to = night_to
}
# a new trip's moon falls in [lo, hi) of its month; the month is `days` long
export function clock_config_moon(days: float, lo: float, hi: float) -> void {
ck_moon_days = days
ck_moon_lo = lo
ck_moon_hi = hi
export function clock_config_moon(clock_st: mut ClockState, days: float, lo: float, hi: float) -> void {
clock_st.ck_moon_days = days
clock_st.ck_moon_lo = lo
clock_st.ck_moon_hi = hi
}

View file

@ -1,20 +1,20 @@
# system.ludic - the clock as a system: it runs first (PH_INPUT) so every later system reads this
# frame's hour, and it saves its own section
function clock_tick(t: Tick) -> void { clock_advance(t.hours) }
function clock_tick(base_st: mut BaseState, clock_st: mut ClockState, t: Tick) -> void { clock_advance(base_st, clock_st, t.hours) }
export function clock_save() -> Val {
export function clock_save(clock_st: ClockState) -> Val {
let v = Value.object()
sv_put_int(v, "day", ck_day)
sv_put_float(v, "hours", ck_hours)
sv_put_float(v, "moon", ck_moon)
sv_put_int(v, "day", clock_st.ck_day)
sv_put_float(v, "hours", clock_st.ck_hours)
sv_put_float(v, "moon", clock_st.ck_moon)
return v
}
export function clock_load(v: Val, version: int) -> void {
ck_day = sv_int(v, "day", 1)
clock_set_hours(sv_float(v, "hours", ck_start_hours))
ck_moon = sv_float(v, "moon", 0.5)
q_clear(clock_days())
export function clock_load(base_st: mut BaseState, clock_st: mut ClockState, v: Val, version: int) -> void {
clock_st.ck_day = sv_int(v, "day", 1)
clock_set_hours(clock_st, sv_float(v, "hours", clock_st.ck_start_hours))
clock_st.ck_moon = sv_float(v, "moon", 0.5)
q_clear(base_st, clock_days(base_st, clock_st))
}
export function clock_system() -> System {

View file

@ -4,123 +4,125 @@ import "ludic.clock"
import "ludic.base"
program ClockTest {
numbers float
var owns: bool = true
var rest: float = 1.0
state ClockTestState {
owns: bool = true
rest: float = 1.0
}
function fake_owns() -> bool { return owns }
function fake_rest() -> float { return rest }
function fake_owns(clock_test_st: ClockTestState) -> bool { return clock_test_st.owns }
function fake_rest(clock_test_st: ClockTestState) -> float { return clock_test_st.rest }
function fake_seed() -> int { return 42 }
bind ClockWorld { owns_world: fn fake_owns, rest_scale: fn fake_rest, seed: fn fake_seed }
function fresh() -> void {
owns = true
rest = 1.0
clock_config(8.0, 20.0, 6.0)
clock_config_moon(29.5, 0.2, 0.8)
clock_set_scale(60.0)
function fresh(base_st: mut BaseState, clock_st: mut ClockState, clock_test_st: mut ClockTestState) -> void {
clock_test_st.owns = true
clock_test_st.rest = 1.0
clock_config(clock_st, 8.0, 20.0, 6.0)
clock_config_moon(clock_st, 29.5, 0.2, 0.8)
clock_set_scale(clock_st, 60.0)
let seasons = new []int
for m in 0 .. 12 { push(seasons, m / 3) }
clock_calendar(10, seasons)
clock_reset()
clock_calendar(clock_st, 10, seasons)
clock_reset(base_st, clock_st)
}
function turned() -> []DayTurned { return q_drain(clock_days()) }
function waiting() -> int { return q_len(clock_days()) }
function turned(base_st: mut BaseState, clock_st: mut ClockState) -> []DayTurned { return q_drain(base_st, clock_days(base_st, clock_st)) }
function waiting(base_st: mut BaseState, clock_st: mut ClockState) -> int { return q_len(clock_days(base_st, clock_st)) }
function run_hours(h: float) -> void {
let s = clock_system()
s.tick(tick_new(0.016, 0, h))
}
test "a trip starts on day one at the start hour, the moon inside its range" {
fresh()
expect_eq(clock_day(), 1)
expect(clock_hours() == 8.0)
expect(clock_moon() >= 0.2 and clock_moon() < 0.8)
expect(clock_hhmm() == "08:00")
test "a trip starts on day one at the start hour, the moon inside its range" (base_st: mut BaseState, clock_st: mut ClockState, clock_test_st: mut ClockTestState) {
fresh(base_st, clock_st, clock_test_st)
expect_eq(clock_day(clock_st), 1)
expect(clock_hours(clock_st) == 8.0)
expect(clock_moon(clock_st) >= 0.2 and clock_moon(clock_st) < 0.8)
expect(clock_hhmm(clock_st) == "08:00")
}
test "the same seed gives the same moon" {
fresh()
let a = clock_moon()
clock_reset()
expect(clock_moon() == a)
test "the same seed gives the same moon" (base_st: mut BaseState, clock_st: mut ClockState, clock_test_st: mut ClockTestState) {
fresh(base_st, clock_st, clock_test_st)
let a = clock_moon(clock_st)
clock_reset(base_st, clock_st)
expect(clock_moon(clock_st) == a)
}
test "a real minute is a game hour at scale 60, and resting speeds it" {
fresh()
expect(clock_hours_in(60.0) == 1.0)
rest = 4.0
expect(clock_rate() == 240.0)
test "a real minute is a game hour at scale 60, and resting speeds it" (base_st: mut BaseState, clock_st: mut ClockState, clock_test_st: mut ClockTestState) {
fresh(base_st, clock_st, clock_test_st)
expect(clock_hours_in(clock_st, 60.0) == 1.0)
clock_test_st.rest = 4.0
expect(clock_rate(clock_st) == 240.0)
}
test "past midnight the day turns, once, as a fact" {
fresh()
test "past midnight the day turns, once, as a fact" (base_st: mut BaseState, clock_st: mut ClockState, clock_test_st: mut ClockTestState) {
fresh(base_st, clock_st, clock_test_st)
run_hours(15.0)
expect_eq(waiting(), 0)
expect_eq(waiting(base_st, clock_st), 0)
run_hours(2.5)
expect_eq(clock_day(), 2)
expect(clock_hours() == 1.5)
let t = turned()
expect_eq(clock_day(clock_st), 2)
expect(clock_hours(clock_st) == 1.5)
let t = turned(base_st, clock_st)
expect_eq(len(t), 1)
expect_eq(t[0].day, 2)
expect_eq(t[0].how, DAY_STAYED_UP)
}
test "a machine that does not own the world does not move it" {
fresh()
owns = false
test "a machine that does not own the world does not move it" (base_st: mut BaseState, clock_st: mut ClockState, clock_test_st: mut ClockTestState) {
fresh(base_st, clock_st, clock_test_st)
clock_test_st.owns = false
run_hours(20.0)
expect(clock_hours() == 8.0)
expect_eq(clock_day(), 1)
expect(clock_hours(clock_st) == 8.0)
expect_eq(clock_day(clock_st), 1)
}
test "a night slept turns the day and moves the moon a month's share" {
fresh()
let m0 = clock_moon()
clock_set_hours(6.5)
clock_new_day()
expect_eq(clock_day(), 2)
expect(clock_moon() > m0)
expect_eq(turned()[0].how, DAY_SLEPT)
test "a night slept turns the day and moves the moon a month's share" (base_st: mut BaseState, clock_st: mut ClockState, clock_test_st: mut ClockTestState) {
fresh(base_st, clock_st, clock_test_st)
let m0 = clock_moon(clock_st)
clock_set_hours(clock_st, 6.5)
clock_new_day(base_st, clock_st)
expect_eq(clock_day(clock_st), 2)
expect(clock_moon(clock_st) > m0)
expect_eq(turned(base_st, clock_st)[0].how, DAY_SLEPT)
}
test "night is outside the day's hours, and the hour wraps" {
fresh()
clock_set_hours(21.0)
expect(clock_is_night())
clock_set_hours(12.0)
expect(not clock_is_night())
clock_set_hours(25.0)
expect(clock_hours() == 1.0)
test "night is outside the day's hours, and the hour wraps" (base_st: mut BaseState, clock_st: mut ClockState, clock_test_st: mut ClockTestState) {
fresh(base_st, clock_st, clock_test_st)
clock_set_hours(clock_st, 21.0)
expect(clock_is_night(clock_st))
clock_set_hours(clock_st, 12.0)
expect(not clock_is_night(clock_st))
clock_set_hours(clock_st, 25.0)
expect(clock_hours(clock_st) == 1.0)
}
test "the calendar is a function of the day" {
fresh()
expect_eq(clock_season_of(1), 0)
expect_eq(clock_month_of(31), 3)
expect_eq(clock_season_of(31), 1)
expect_eq(clock_day_of_month_of(35), 5)
expect_eq(clock_year_of(121), 2)
expect_eq(clock_first_day_of(2), 61)
clock_set_day(28)
expect_eq(clock_days_to_change(), 3)
expect_eq(clock_season(), 0)
test "the calendar is a function of the day" (base_st: mut BaseState, clock_st: mut ClockState, clock_test_st: mut ClockTestState) {
fresh(base_st, clock_st, clock_test_st)
expect_eq(clock_season_of(clock_st, 1), 0)
expect_eq(clock_month_of(clock_st, 31), 3)
expect_eq(clock_season_of(clock_st, 31), 1)
expect_eq(clock_day_of_month_of(clock_st, 35), 5)
expect_eq(clock_year_of(clock_st, 121), 2)
expect_eq(clock_first_day_of(clock_st, 2), 61)
clock_set_day(clock_st, 28)
expect_eq(clock_days_to_change(clock_st), 3)
expect_eq(clock_season(clock_st), 0)
}
test "a save section reads back the same clock" {
fresh()
clock_set_day(17)
clock_set_hours(13.25)
clock_set_moon(0.375)
test "a save section reads back the same clock" (base_st: mut BaseState, clock_st: mut ClockState, clock_test_st: mut ClockTestState) {
fresh(base_st, clock_st, clock_test_st)
clock_set_day(clock_st, 17)
clock_set_hours(clock_st, 13.25)
clock_set_moon(clock_st, 0.375)
let root = save_tree()
save_section(root, "clock", 1, clock_save())
save_section(root, "clock", 1, clock_save(clock_st))
let text = save_encode(root)
clock_reset()
clock_reset(base_st, clock_st)
let n = load_section(save_decode(text), "clock")
clock_load(n.data, n.version)
expect_eq(clock_day(), 17)
expect(clock_hours() == 13.25)
expect(clock_moon() == 0.375)
clock_load(base_st, clock_st, n.data, n.version)
expect_eq(clock_day(clock_st), 17)
expect(clock_hours(clock_st) == 13.25)
expect(clock_moon(clock_st) == 0.375)
}
}

View file

@ -1,43 +1,43 @@
# verbs.ludic - the only way the clock changes
export function clock_set_scale(s: float) -> void { ck_scale = s }
export function clock_set_day(d: int) -> void { ck_day = d }
export function clock_set_moon(m: float) -> void { ck_moon = m }
export function clock_set_scale(clock_st: mut ClockState, s: float) -> void { clock_st.ck_scale = s }
export function clock_set_day(clock_st: mut ClockState, d: int) -> void { clock_st.ck_day = d }
export function clock_set_moon(clock_st: mut ClockState, m: float) -> void { clock_st.ck_moon = m }
# the hour, wrapped into [0, 24); setting it never turns the day - that is clock_new_day's
export function clock_set_hours(h: float) -> void {
export function clock_set_hours(clock_st: mut ClockState, h: float) -> void {
var x = h % 24.0
if x < 0.0 { x = x + 24.0 }
ck_hours = x
clock_st.ck_hours = x
}
function ck_turn(how: int) -> void {
ck_day += 1
ck_moon = (ck_moon + 1.0 / ck_moon_days) % 1.0
function ck_turn(base_st: mut BaseState, clock_st: mut ClockState, how: int) -> void {
clock_st.ck_day += 1
clock_st.ck_moon = (clock_st.ck_moon + 1.0 / clock_st.ck_moon_days) % 1.0
let d = new DayTurned
d.day = ck_day
d.day = clock_st.ck_day
d.how = how
q_push(clock_days(), d)
q_push(base_st, clock_days(base_st, clock_st), d)
}
# a new day however it came (a night slept, a collapse); the caller sets the hour first
export function clock_new_day() -> void { ck_turn(DAY_SLEPT) }
export function clock_new_day(base_st: mut BaseState, clock_st: mut ClockState) -> void { ck_turn(base_st, clock_st, DAY_SLEPT) }
# run the hours on by `gh` game hours; past midnight the day turns. Only the machine that owns
# the world moves it - another machine is told the time.
export function clock_advance(gh: float) -> void {
export function clock_advance(base_st: mut BaseState, clock_st: mut ClockState, gh: float) -> void {
if not ck_owns() { return }
ck_hours = ck_hours + gh
while not (ck_hours < 24.0) {
ck_hours = ck_hours - 24.0
ck_turn(DAY_STAYED_UP)
clock_st.ck_hours = clock_st.ck_hours + gh
while not (clock_st.ck_hours < 24.0) {
clock_st.ck_hours = clock_st.ck_hours - 24.0
ck_turn(base_st, clock_st, DAY_STAYED_UP)
}
}
# a new trip: day one at the start hour, the moon somewhere in its month
export function clock_reset() -> void {
ck_dice = rng_new(ClockWorld.seed())
ck_day = 1
ck_hours = ck_start_hours
ck_moon = rng_span(ck_dice, ck_moon_lo, ck_moon_hi) % 1.0
q_clear(clock_days())
export function clock_reset(base_st: mut BaseState, clock_st: mut ClockState) -> void {
clock_st.ck_dice = rng_new(ClockWorld.seed())
clock_st.ck_day = 1
clock_st.ck_hours = clock_st.ck_start_hours
clock_st.ck_moon = rng_span(clock_st.ck_dice, clock_st.ck_moon_lo, clock_st.ck_moon_hi) % 1.0
q_clear(base_st, clock_days(base_st, clock_st))
}