nx_caplab_sim_test.nx source
↩ module page · 100 lines · 4380 B
1// nx_caplab_sim_test.nx -- gate for Capitalism Lab R3 (the tick-loop engine).
2//
3// Proves: (1) one tick banks the right profit per firm, (2) cash accumulates
4// across many ticks, (3) production CAPACITY caps sales, (4) the sim is
5// DETERMINISTIC (same inputs -> byte-identical cash, replay-safe), (5) the AI
6// competitor undercuts but never prices below cost, (6) NEG-CONTROL: a firm
7// priced out of the market earns nothing, (7) the CAPITALISM_LAB game config.
8
9import "nx_syscalls.nx"
10import "nx_runtime.nx"
11import "nx_tier.nx"
12import "nx_caplab_sim.nx"
13
14func nx_assert_eq(label: *u8, got: nx_int, want: nx_int, pass_n: *nx_int, fail_n: *nx_int) {
15 print(label); print(": got=" as *u8); print_i64(got); print(" want=" as *u8); print_i64(want)
16 if got == want {
17 println(" PASS" as *u8)
18 pass_n[0] = pass_n[0] + 1
19 return
20 }
21 println(" FAIL" as *u8)
22 fail_n[0] = fail_n[0] + 1
23}
24
25// helper: alloc + fill a 2-firm i64 array
26func mk2(a: nx_int, b: nx_int) -> *i64 {
27 let p: *i64 = (sys_mmap(16)) as *i64
28 p[0] = a
29 p[1] = b
30 return p
31}
32
33func main() -> nx_exit {
34 let pass_n: *nx_int = (sys_mmap(8)) as *nx_int
35 let fail_n: *nx_int = (sys_mmap(8)) as *nx_int
36 pass_n[0] = 0
37 fail_n[0] = 0
38
39 let choke: nx_int = 100
40 let M: nx_int = 120
41
42 println("=== CAPLAB R3: simulation tick loop ===" as *u8)
43
44 // --- T1: one tick. firms @[40,60], cost 20, cap 100. demand=[72,48] ---
45 let pr: *i64 = mk2(40, 60)
46 let uc: *i64 = mk2(20, 20)
47 let cap: *i64 = mk2(100, 100)
48 let cashA: *i64 = mk2(0, 0)
49 let sold: *i64 = mk2(0, 0)
50 nx_clab_sim_tick(2, pr, uc, cap, choke, M, cashA, sold)
51 nx_assert_eq("tick1 firm0 cash " as *u8, cashA[0], 1440, pass_n, fail_n)
52 nx_assert_eq("tick1 firm1 cash " as *u8, cashA[1], 1920, pass_n, fail_n)
53 nx_assert_eq("tick1 firm0 sold " as *u8, sold[0], 72, pass_n, fail_n)
54
55 // --- T2: 3 ticks accumulate (linear at fixed prices) ---
56 let cash3: *i64 = mk2(0, 0)
57 nx_clab_sim_run(2, pr, uc, cap, choke, M, cash3, 3)
58 nx_assert_eq("3-tick firm0 cash " as *u8, cash3[0], 4320, pass_n, fail_n)
59 nx_assert_eq("3-tick firm1 cash " as *u8, cash3[1], 5760, pass_n, fail_n)
60
61 // --- T3: capacity caps sales. firm0 cap 50 < demand 72 -> sells 50 ---
62 let capC: *i64 = mk2(50, 100)
63 let cashC: *i64 = mk2(0, 0)
64 let soldC: *i64 = mk2(0, 0)
65 nx_clab_sim_tick(2, pr, uc, capC, choke, M, cashC, soldC)
66 nx_assert_eq("capacity-capped sold " as *u8, soldC[0], 50, pass_n, fail_n)
67 nx_assert_eq("capacity-capped cash " as *u8, cashC[0], 1000, pass_n, fail_n)
68
69 // --- T4: DETERMINISM. same scenario twice -> identical cash ---
70 let cashB: *i64 = mk2(0, 0)
71 nx_clab_sim_run(2, pr, uc, cap, choke, M, cashB, 3)
72 nx_assert_eq("determinism firm0 " as *u8, cashB[0], cash3[0], pass_n, fail_n)
73 nx_assert_eq("determinism firm1 " as *u8, cashB[1], cash3[1], pass_n, fail_n)
74
75 // --- T5: AI competitor undercuts, but never below cost ---
76 nx_assert_eq("ai undercuts rival " as *u8, nx_clab_ai_price(60, 20, 5), 55, pass_n, fail_n)
77 nx_assert_eq("ai floors at cost+1 " as *u8, nx_clab_ai_price(22, 20, 5), 21, pass_n, fail_n)
78
79 // --- T6: NEG-CONTROL. firm priced at choke earns nothing; rival capped ---
80 let prX: *i64 = mk2(40, 100)
81 let cashX: *i64 = mk2(0, 0)
82 let soldX: *i64 = mk2(0, 0)
83 nx_clab_sim_tick(2, prX, uc, cap, choke, M, cashX, soldX)
84 nx_assert_eq("priced-out earns 0 " as *u8, cashX[1], 0, pass_n, fail_n)
85 nx_assert_eq("rival capped at 100 " as *u8, soldX[0], 100, pass_n, fail_n)
86
87 // --- T7: CAPITALISM_LAB game config ---
88 let cfg: *i64 = (sys_mmap(NX_CLAB_CFG_STRIDE * NX_SIZEOF_NX_INT)) as *i64
89 nx_clab_mode_init(cfg)
90 nx_assert_eq("mode id " as *u8, cfg[NX_CLAB_CFG_MODE], NX_CLAB_MODE_ID, pass_n, fail_n)
91 nx_assert_eq("mode start cash " as *u8, cfg[NX_CLAB_CFG_START_CASH], 1000, pass_n, fail_n)
92 nx_assert_eq("mode ticks/year " as *u8, cfg[NX_CLAB_CFG_TICKS], 12, pass_n, fail_n)
93 nx_assert_eq("mode firms " as *u8, cfg[NX_CLAB_CFG_N_FIRMS], 4, pass_n, fail_n)
94
95 println("" as *u8)
96 print("PASS=" as *u8); print_i64(pass_n[0])
97 print(" FAIL=" as *u8); print_i64(fail_n[0]); println("" as *u8)
98 if fail_n[0] > 0 { return 1 }
99 return 0
100}