Merge branch 'lang/play-leaks' into lang/leaks2
This commit is contained in:
commit
67474a5cfe
15 changed files with 153 additions and 11 deletions
19
packages/ludic.fishing/facts.ludic
Normal file
19
packages/ludic.fishing/facts.ludic
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# facts.ludic - a fishing fact's record: one no drain holds any more, made fresh (and kept) only when
|
||||
# every one is held. A cast, a bite, every crossing and run of a fight is a fact, and a record a fact
|
||||
# is never given back (the ludic.wildlife idiom, facts.ludic there)
|
||||
function fishing_fact_record(fishing_st: mut FishingState) -> FishingFact {
|
||||
if fishing_st.fishing_fnext[0] >= len(fishing_st.fishing_ffree) {
|
||||
q_unheld(fishing_st.fishing_fact_q, fishing_st.fishing_fpool, fishing_st.fishing_ffree)
|
||||
fishing_st.fishing_fnext[0] = 0
|
||||
}
|
||||
if fishing_st.fishing_fnext[0] < len(fishing_st.fishing_ffree) {
|
||||
let f = fishing_st.fishing_ffree[fishing_st.fishing_fnext[0]]
|
||||
fishing_st.fishing_fnext[0] += 1
|
||||
return f
|
||||
}
|
||||
let f = new FishingFact
|
||||
push(fishing_st.fishing_fpool, f)
|
||||
return f
|
||||
}
|
||||
# how many fact records have ever been made: the peak held at once, not the facts said
|
||||
export function fishing_fact_records(fishing_st: FishingState) -> int { return len(fishing_st.fishing_fpool) }
|
||||
|
|
@ -6,6 +6,7 @@ import "ludic.base"
|
|||
import "kinds.ludic"
|
||||
import "ports.ludic"
|
||||
import "state.ludic"
|
||||
import "facts.ludic"
|
||||
import "fight.ludic"
|
||||
import "verbs.ludic"
|
||||
import "run.ludic"
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ export state FishingState {
|
|||
fishing_run_next: float = 0.0
|
||||
fishing_dice: Rng = null
|
||||
fishing_fact_q: Queue<FishingFact> = fishing_fact_q__new()
|
||||
fishing_fpool: []FishingFact = new []FishingFact # every fact record made, reused once no drain holds it (facts.ludic)
|
||||
fishing_ffree: []FishingFact = new []FishingFact
|
||||
fishing_fnext: []int = words(1)
|
||||
fishing_n: int = 0 # the record: caught, the biggest (cm), a legend landed
|
||||
fishing_big: int = 0
|
||||
fishing_leg: bool = false
|
||||
|
|
@ -51,8 +54,8 @@ function fishing_rand(fishing_st: mut FishingState) -> float {
|
|||
return rng_float(fishing_st.fishing_dice)
|
||||
}
|
||||
|
||||
function fishing_say(fishing_st: FishingState, what: int) -> void {
|
||||
let f = new FishingFact
|
||||
function fishing_say(fishing_st: mut FishingState, what: int) -> void {
|
||||
let f = fishing_fact_record(fishing_st)
|
||||
f.what = what
|
||||
f.species = fishing_st.fishing_sp
|
||||
f.cm = fishing_st.fishing_len
|
||||
|
|
|
|||
|
|
@ -254,4 +254,20 @@ program FishingTest {
|
|||
expect(fishing_legend_caught(fishing_st))
|
||||
expect(not fishing_active(fishing_st))
|
||||
}
|
||||
|
||||
test "fifty fish, their facts drained each time, reuse a handful of records" (fishing_st: mut FishingState, fishing_test_st: mut FishingTestState) {
|
||||
fresh(fishing_st, fishing_test_st)
|
||||
for k in 0 .. 50 {
|
||||
fishing_cast(fishing_st, 20.0, 0.0)
|
||||
facts(fishing_st)
|
||||
hook(fishing_st)
|
||||
facts(fishing_st)
|
||||
play(fishing_st, 12)
|
||||
facts(fishing_st)
|
||||
fishing_stop(fishing_st)
|
||||
facts(fishing_st)
|
||||
}
|
||||
print(`fishing: 50 fish, {fishing_fact_records(fishing_st)} fact records made`)
|
||||
expect(fishing_fact_records(fishing_st) < 30)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
19
packages/ludic.jobs/facts.ludic
Normal file
19
packages/ludic.jobs/facts.ludic
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# facts.ludic - a jobs fact's record: one no drain holds any more, made fresh (and kept) only when
|
||||
# every one is held. A deed that moves a job is a fact, and a record a fact is never given back
|
||||
# (the ludic.wildlife idiom)
|
||||
function jobs__fact_record(jobs_st: mut JobsState) -> JobsFact {
|
||||
if jobs_st.jobs__fnext[0] >= len(jobs_st.jobs__ffree) {
|
||||
q_unheld(jobs_st.jobs__q, jobs_st.jobs__fpool, jobs_st.jobs__ffree)
|
||||
jobs_st.jobs__fnext[0] = 0
|
||||
}
|
||||
if jobs_st.jobs__fnext[0] < len(jobs_st.jobs__ffree) {
|
||||
let f = jobs_st.jobs__ffree[jobs_st.jobs__fnext[0]]
|
||||
jobs_st.jobs__fnext[0] += 1
|
||||
return f
|
||||
}
|
||||
let f = new JobsFact
|
||||
push(jobs_st.jobs__fpool, f)
|
||||
return f
|
||||
}
|
||||
# how many fact records have ever been made: the peak held at once, not the facts said
|
||||
export function jobs_fact_records(jobs_st: JobsState) -> int { return len(jobs_st.jobs__fpool) }
|
||||
|
|
@ -6,6 +6,7 @@ import "ludic.base"
|
|||
import "defs.ludic"
|
||||
import "ports.ludic"
|
||||
import "state.ludic"
|
||||
import "facts.ludic"
|
||||
import "jobs.ludic"
|
||||
import "giveup.ludic"
|
||||
import "count.ludic"
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ export state JobsState {
|
|||
jobs__seed: int = 1000
|
||||
jobs__dice: Rng = rng_new(1000)
|
||||
jobs__q: Queue<JobsFact> = jobs__q__new()
|
||||
jobs__fpool: []JobsFact = new []JobsFact # every fact record made, reused once no drain holds it (facts.ludic)
|
||||
jobs__ffree: []JobsFact = new []JobsFact
|
||||
jobs__fnext: []int = words(1)
|
||||
}
|
||||
|
||||
# the posts, every board's slots end to end from jobs__off[b]
|
||||
|
|
@ -58,8 +61,8 @@ export function jobs_facts(jobs_st: JobsState) -> Queue<JobsFact> {
|
|||
return jobs_st.jobs__q
|
||||
}
|
||||
|
||||
function jobs__fact(jobs_st: JobsState, what: int, job: int, b: int, s: int, have: int, need: int) -> void {
|
||||
let f = new JobsFact
|
||||
function jobs__fact(jobs_st: mut JobsState, what: int, job: int, b: int, s: int, have: int, need: int) -> void {
|
||||
let f = jobs__fact_record(jobs_st)
|
||||
f.what = what
|
||||
f.job = job
|
||||
f.board = b
|
||||
|
|
|
|||
|
|
@ -129,4 +129,17 @@ program JobsGiveUpTest {
|
|||
jobs_test_st.day = 2
|
||||
expect(jobs_offered(jobs_st, JOB_CATCH))
|
||||
}
|
||||
|
||||
test "two hundred jobs taken and given up, their facts drained each time, reuse a handful of records" (jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
|
||||
fresh(jobs_st, jobs_test_st)
|
||||
for k in 0 .. 200 {
|
||||
jobs_take(jobs_st, JOB_CATCH)
|
||||
count_of(jobs_st, 0)
|
||||
jobs_give_up(jobs_st, JOB_CATCH)
|
||||
count_of(jobs_st, 0)
|
||||
jobs_st.jobs__back[JOB_CATCH] = -1
|
||||
}
|
||||
print(`jobs: 200 taken and given up, {jobs_fact_records(jobs_st)} fact records made`)
|
||||
expect(jobs_fact_records(jobs_st) < 10)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ export port MinimapWorld { # every member has a default
|
|||
| `minimap_pin_count()`, `minimap_pin_max()`, `minimap_pin_full()`, `minimap_pin(i) -> MinimapPin` | the marks |
|
||||
| `minimap_pin_set_label/icon/colour(i, v)`, `minimap_pin_last_icon()` | editing one |
|
||||
| `minimap_pin_open()`, `minimap_pin_select(i)`, `minimap_pin_followed()`, `minimap_pin_follow(i)`, `minimap_pin_follow_toggle()` | the open one and the followed one |
|
||||
| `minimap_pins_near(x, z, n, within) -> []int` | the nearest marks, not the followed one (for a compass) |
|
||||
| `minimap_pins_near(x, z, n, within) -> []int` | the nearest marks, not the followed one (for a compass), in a list the state keeps and refills: read it, do not keep it |
|
||||
| `minimap_config_view(span, zoom_min, zoom_max, focus)`, `minimap_window(x0, y0, size)` | the view's range, and where the window is this frame |
|
||||
| `minimap_px(x)`, `minimap_py(z)`, `minimap_wx(rx)`, `minimap_wz(ry)`, `minimap_span()`, `minimap_scale()`, `minimap_scale_metres()` | projection, and a scale bar's round distance |
|
||||
| `minimap_zoom()`, `minimap_zoom_set(z)`, `minimap_zoom_step(dir)`, `minimap_zoom_about(rx, ry, factor)` | zoom |
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# grid.ludic - the explored grid: square cells round the origin, and the part of it "explored" is
|
||||
# measured over (a core, so a bigger grid does not change what a share of it means)
|
||||
export state MinimapState {
|
||||
mm_near: []int = new []int # minimap_pins_near's answer, cleared and refilled: a compass asks every frame
|
||||
mm_land_n: int = 0 # land cells in the core, counted once per origin
|
||||
mm_land_ox: float = 0.0
|
||||
mm_land_oz: float = 0.0
|
||||
|
|
|
|||
|
|
@ -71,8 +71,9 @@ export function minimap_pin(minimap_st: MinimapState, i: int) -> MinimapPin {
|
|||
}
|
||||
|
||||
# the nearest n marks within `within` of (x, z), nearest first, leaving out the followed one
|
||||
export function minimap_pins_near(minimap_st: MinimapState, x: float, z: float, n: int, within: float) -> []int {
|
||||
let out = new []int
|
||||
export function minimap_pins_near(minimap_st: mut MinimapState, x: float, z: float, n: int, within: float) -> []int {
|
||||
let out = minimap_st.mm_near
|
||||
List.clear(out)
|
||||
for k in 0 .. n {
|
||||
var best = -1
|
||||
var bd = within * within
|
||||
|
|
|
|||
|
|
@ -111,6 +111,20 @@ program MinimapTest {
|
|||
expect_eq(near[1], 1)
|
||||
}
|
||||
|
||||
test "asking for the nearest marks every frame allocates nothing" (minimap_st: mut MinimapState, minimap_test_st: mut MinimapTestState) {
|
||||
fresh(minimap_st, minimap_test_st)
|
||||
minimap_config_pins(minimap_st, 8, 8, 5)
|
||||
minimap_pin_add(minimap_st, 110.0, 100.0, 0, "near")
|
||||
minimap_pin_add(minimap_st, 130.0, 100.0, 0, "next")
|
||||
minimap_pins_near(minimap_st, 100.0, 100.0, 2, 400.0)
|
||||
let before = Os.heap_bytes()
|
||||
for k in 0 .. 1000 { minimap_pins_near(minimap_st, 100.0 + float(k % 7), 100.0, 2, 400.0) }
|
||||
let grew = Os.heap_bytes() - before
|
||||
print(`minimap: 1000 asks, heap {grew} bytes`)
|
||||
expect(grew == long(0))
|
||||
expect_eq(len(minimap_pins_near(minimap_st, 100.0, 100.0, 2, 400.0)), 2)
|
||||
}
|
||||
|
||||
test "the view: the world on the window and back, zoom about a point, a pan, focus and the clamp" (minimap_st: mut MinimapState, minimap_test_st: mut MinimapTestState) {
|
||||
fresh(minimap_st, minimap_test_st)
|
||||
minimap_centre(minimap_st, 100.0, 100.0)
|
||||
|
|
|
|||
|
|
@ -16,14 +16,15 @@ export function phys_is_open(physics_st: PhysicsState) -> bool { return physics_
|
|||
# which world this is: a body, shape or walker id kept from an older one means nothing now
|
||||
export function phys_generation(physics_st: PhysicsState) -> int { return physics_st.ph_gen }
|
||||
|
||||
# everything let go: the world, every body in it and every shape (a world swap, a quit)
|
||||
# everything let go: the world, every body in it and every shape (a world swap, a quit); the lists
|
||||
# that held them are emptied and kept, since nothing is given back
|
||||
export function phys_close(physics_st: mut PhysicsState) -> void {
|
||||
if physics_st.ph_walkers != null {
|
||||
for i in 0 .. len(physics_st.ph_walkers) {
|
||||
if physics_st.ph_walkers[i] != null { jph_char_free(physics_st.ph_walkers[i]) }
|
||||
}
|
||||
}
|
||||
physics_st.ph_walkers = new []pointer
|
||||
if physics_st.ph_walkers != null { List.clear(physics_st.ph_walkers) }
|
||||
if physics_st.ph_world != null { jph_world_free(physics_st.ph_world) }
|
||||
physics_st.ph_world = null
|
||||
if physics_st.ph_shapes != null {
|
||||
|
|
@ -31,7 +32,7 @@ export function phys_close(physics_st: mut PhysicsState) -> void {
|
|||
if physics_st.ph_shapes[i] != null { jph_shape_free(physics_st.ph_shapes[i]) }
|
||||
}
|
||||
}
|
||||
physics_st.ph_shapes = new []pointer
|
||||
if physics_st.ph_shapes != null { List.clear(physics_st.ph_shapes) }
|
||||
List.clear(physics_st.ph_spare)
|
||||
List.clear(physics_st.ph_floats)
|
||||
List.clear(physics_st.ph_float_k)
|
||||
|
|
|
|||
42
packages/ludic.physics/tests/reuse_test.ludic
Normal file
42
packages/ludic.physics/tests/reuse_test.ludic
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# reuse_test.ludic - what is taken away is given back: a walker made and removed two hundred times
|
||||
# holds one place in the list and no more heap, and a world closed and opened again keeps its lists
|
||||
import "ludic.physics"
|
||||
import "ludic.base"
|
||||
program ReuseTest {
|
||||
numbers float
|
||||
|
||||
test "a walker made and removed takes the same place and grows nothing" (physics_st: mut PhysicsState) {
|
||||
expect(phys_open(physics_st, 64, 1))
|
||||
let w = phys_walker_add(physics_st, 0.4, 1.8, 0.0, 0.0, 0.0, 50.0, 80.0)
|
||||
phys_walker_remove(physics_st, w)
|
||||
let before = Os.heap_bytes()
|
||||
for k in 0 .. 200 {
|
||||
let id = phys_walker_add(physics_st, 0.4, 1.8, float(k), 0.0, 0.0, 50.0, 80.0)
|
||||
expect_eq(id, w)
|
||||
phys_walker_remove(physics_st, id)
|
||||
}
|
||||
let grew = Os.heap_bytes() - before
|
||||
print(`reuse: 200 walkers made and removed, {len(physics_st.ph_walkers)} place, heap {grew} bytes`)
|
||||
expect_eq(len(physics_st.ph_walkers), 1)
|
||||
expect(grew < long(1024))
|
||||
phys_close(physics_st)
|
||||
}
|
||||
|
||||
test "a world closed and opened again keeps the lists it held" (physics_st: mut PhysicsState) {
|
||||
expect(phys_open(physics_st, 64, 1))
|
||||
phys_box(physics_st, 1.0, 1.0, 1.0)
|
||||
phys_walker_add(physics_st, 0.4, 1.8, 0.0, 0.0, 0.0, 50.0, 80.0)
|
||||
let shapes = physics_st.ph_shapes
|
||||
let walkers = physics_st.ph_walkers
|
||||
for k in 0 .. 20 {
|
||||
phys_close(physics_st)
|
||||
expect(phys_open(physics_st, 64, 1))
|
||||
phys_box(physics_st, 1.0, 1.0, 1.0)
|
||||
phys_walker_add(physics_st, 0.4, 1.8, 0.0, 0.0, 0.0, 50.0, 80.0)
|
||||
}
|
||||
expect(physics_st.ph_shapes == shapes)
|
||||
expect(physics_st.ph_walkers == walkers)
|
||||
expect_eq(phys_shapes(physics_st), 1)
|
||||
phys_close(physics_st)
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,15 @@ function ph_walker(physics_st: PhysicsState, id: int) -> pointer {
|
|||
export function phys_walker_add(physics_st: mut PhysicsState, r: float, h: float, x: float, y: float, z: float, max_slope: float, mass: float) -> int {
|
||||
if physics_st.ph_world == null { return -1 }
|
||||
ph_buffers()
|
||||
push(physics_st.ph_walkers, jph_char_new(physics_st.ph_world, r, h, x, y, z, max_slope, mass))
|
||||
let k = jph_char_new(physics_st.ph_world, r, h, x, y, z, max_slope, mass)
|
||||
# a removed walker's place is taken again, so a horse called and sent away grows nothing
|
||||
for i in 0 .. len(physics_st.ph_walkers) {
|
||||
if physics_st.ph_walkers[i] == null {
|
||||
physics_st.ph_walkers[i] = k
|
||||
return i
|
||||
}
|
||||
}
|
||||
push(physics_st.ph_walkers, k)
|
||||
return len(physics_st.ph_walkers) - 1
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue