code wiki / _hdl_build / nx_pantry_meal_gate.nx
nx_pantry_meal_gate.nx source
↩ module page · 125 lines · 7615 B
1// nx_pantry_meal_gate.nx -- GATE: the pantry -> food-engine integration (the operator's chain: pantry ->
2// what's expiring -> what can I make -> meal planning). Proves: T1 "what can I make" builds a complete
3// stir-fry from ONLY in-stock ingredients, T2 "cook what's expiring first" forces an expiring protein
4// (Chicken/Tofu) over a fresh one (Beef), T3 a sovereign no-JS "Your Kitchen" page renders from the pantry,
5// T4 a 2-meal plan CONSUMES inventory (stock drops by exactly 2 meals x 5 ingredients). license_tier: ORIGINAL
6import "nx_pantry.nx"
7import "nx_food_site.nx"
8import "nx_inventory.nx"
9import "nx_syscalls.nx"
10
11const PM_FOOD: *u8 = "knowledge/store/food-"
12const PM_INV: *u8 = "knowledge/store/inv-"
13const PM_DOM: *u8 = "kitchen"
14const PM_CAT: *u8 = "knowledge/registry/nishi_builder.tsv"
15
16func g_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
17func g_i(v: i64) -> i64 {
18 let bb: *u8 = sys_mmap(28); var m: i64 = v
19 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
20 let t: *u8 = sys_mmap(28); var k: i64 = 0
21 if m == 0 { t[0] = 48 as u8; k = 1 }
22 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
23 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, bb, k); return 0
24}
25func g_show(world: *i64, build: *i64, nb: i64) -> i64 {
26 let names: *i64 = world[4] as *i64
27 var i: i64 = 0
28 while i < nb { if i > 0 { g_p(" | " as *u8) } g_p(names[build[i]] as *u8); i = i + 1 }
29 g_p("\n" as *u8); return 0
30}
31
32func main() -> i64 {
33 g_p("=== nx_pantry_meal_gate (pantry -> what's expiring -> what can I make -> meal plan) ===\n" as *u8)
34 fd_seed(PM_FOOD)
35 fs_teach(PM_CAT)
36
37 // stock the kitchen (today = day 0; chicken/tofu expiring, beef fresh)
38 iv_add(PM_INV, PM_DOM, "beef" as *u8, "Beef" as *u8, "protein" as *u8, 1, "lb" as *u8, "fridge" as *u8, 0, 30, "" as *u8)
39 iv_add(PM_INV, PM_DOM, "chicken" as *u8, "Chicken" as *u8, "protein" as *u8, 2, "lb" as *u8, "fridge" as *u8, 0, 3, "" as *u8)
40 iv_add(PM_INV, PM_DOM, "tofu" as *u8, "Tofu" as *u8, "protein" as *u8, 1, "block" as *u8, "fridge" as *u8, 0, 2, "" as *u8)
41 iv_add(PM_INV, PM_DOM, "broccoli" as *u8, "Broccoli" as *u8, "veg" as *u8, 2, "head" as *u8, "fridge" as *u8, 0, 5, "" as *u8)
42 iv_add(PM_INV, PM_DOM, "onion" as *u8, "Onion" as *u8, "veg" as *u8, 3, "ea" as *u8, "pantry" as *u8, 0, 20, "" as *u8)
43 iv_add(PM_INV, PM_DOM, "snowpea" as *u8, "Snow Peas" as *u8, "veg" as *u8, 2, "bag" as *u8, "fridge" as *u8, 0, 6, "" as *u8)
44 iv_add(PM_INV, PM_DOM, "garlic" as *u8, "Garlic" as *u8, "aromatic" as *u8, 2, "bulb" as *u8, "pantry" as *u8, 0, 60, "" as *u8)
45 iv_add(PM_INV, PM_DOM, "ginger" as *u8, "Ginger" as *u8, "aromatic" as *u8, 2, "knob" as *u8, "fridge" as *u8, 0, 14, "" as *u8)
46 iv_add(PM_INV, PM_DOM, "soy" as *u8, "Soy Sauce" as *u8, "sauce" as *u8, 2, "bottle" as *u8, "pantry" as *u8, 0, 365, "" as *u8)
47 iv_add(PM_INV, PM_DOM, "oyster" as *u8, "Oyster Sauce" as *u8, "sauce" as *u8, 1, "bottle" as *u8, "pantry" as *u8, 0, 200, "" as *u8)
48 iv_add(PM_INV, PM_DOM, "rice" as *u8, "Rice" as *u8, "starch" as *u8, 2, "bag" as *u8, "pantry" as *u8, 0, 0, "" as *u8)
49
50 let world: *i64 = fd_world_open(PM_FOOD)
51 let n: i64 = world[0]
52 let ids: *i64 = world[1] as *i64
53 let names: *i64 = world[4] as *i64
54
55 var pass: i64 = 0
56 var tot: i64 = 0
57
58 // T1 "what can I make" from in-stock ingredients only
59 let avail: *i64 = sys_mmap(8 * 64) as *i64
60 let nav: i64 = fp_pantry_avail(world, PM_INV, PM_DOM, avail)
61 let b1: *i64 = sys_mmap(8 * 16) as *i64; let r1: *i64 = sys_mmap(8 * 16) as *i64
62 let nb1: i64 = fp_choose(PM_FOOD, world, avail, b1, r1)
63 g_p("in-stock ingredients=" as *u8); g_i(nav); g_p(" -> tonight: " as *u8); g_show(world, b1, nb1)
64 tot = tot + 1
65 var ok1: i64 = 1
66 if nb1 != 5 { ok1 = 0 }
67 var t1i: i64 = 0
68 while t1i < nb1 { if iv_qty(PM_INV, PM_DOM, ids[b1[t1i]] as *u8) <= 0 { ok1 = 0 } t1i = t1i + 1 }
69 if ok1 == 1 { pass = pass + 1; g_p("PASS T1 what-can-I-make: a complete stir-fry from only what's in stock\n" as *u8) } else { g_p("FAIL T1\n" as *u8) }
70
71 // T2 cook-what's-expiring-first: forces an expiring protein over fresh Beef
72 let avexp: *i64 = sys_mmap(8 * 64) as *i64
73 fp_expiring_first(world, PM_INV, PM_DOM, PM_FOOD, 0, 3, avail, avexp)
74 let be: *i64 = sys_mmap(8 * 16) as *i64; let re: *i64 = sys_mmap(8 * 16) as *i64
75 let nbe: i64 = fp_choose(PM_FOOD, world, avexp, be, re)
76 g_p("normal protein=" as *u8); g_p(names[b1[0]] as *u8); g_p(" expiring-first protein=" as *u8); g_p(names[be[0]] as *u8); g_p("\n" as *u8)
77 tot = tot + 1
78 var ok2: i64 = 1
79 if nbe != 5 { ok2 = 0 }
80 if fp_is_expiring(PM_INV, PM_DOM, ids[be[0]] as *u8, 0, 3) != 1 { ok2 = 0 }
81 if ok2 == 1 { pass = pass + 1; g_p("PASS T2 expiring-first: the meal uses a soon-to-expire protein (cut waste)\n" as *u8) } else { g_p("FAIL T2\n" as *u8) }
82
83 // T3 sovereign "Your Kitchen" page from the pantry
84 let avoid: *i64 = sys_mmap(8 * 64) as *i64
85 let prefw: *i64 = sys_mmap(8 * 8) as *i64
86 fd_set_all(avoid, n, 0)
87 var z: i64 = 0; while z < FOOD_NAX { prefw[z] = 0; z = z + 1 }
88 let page: *u8 = sys_mmap(65536)
89 let np: i64 = fs_render_avail(PM_FOOD, PM_CAT, "Your Kitchen" as *u8, avail, avoid, prefw, page)
90 tot = tot + 1
91 var ok3: i64 = 1
92 if as_has_thirdparty_js(page, np) != 0 { ok3 = 0 }
93 if as_contains(page, np, names[b1[0]] as *u8) != 1 { ok3 = 0 }
94 if ok3 == 1 { pass = pass + 1; g_p("PASS T3 sovereign 'Your Kitchen' page rendered from the pantry (" as *u8); g_i(np); g_p(" bytes, 0 JS)\n" as *u8) } else { g_p("FAIL T3\n" as *u8) }
95
96 // T4 meal plan: 2 meals, consuming inventory
97 let q0: i64 = fp_total_qty(PM_INV, PM_DOM)
98 // meal 1
99 let m1: *i64 = sys_mmap(8 * 64) as *i64; fp_pantry_avail(world, PM_INV, PM_DOM, m1)
100 let m1e: *i64 = sys_mmap(8 * 64) as *i64; fp_expiring_first(world, PM_INV, PM_DOM, PM_FOOD, 0, 3, m1, m1e)
101 let mb1: *i64 = sys_mmap(8 * 16) as *i64; let mr1: *i64 = sys_mmap(8 * 16) as *i64
102 let nm1: i64 = fp_choose(PM_FOOD, world, m1e, mb1, mr1)
103 g_p(" meal 1: " as *u8); g_show(world, mb1, nm1)
104 fp_consume_build(PM_INV, PM_DOM, world, mb1, nm1)
105 // meal 2 (pantry now depleted)
106 let m2: *i64 = sys_mmap(8 * 64) as *i64; fp_pantry_avail(world, PM_INV, PM_DOM, m2)
107 let m2e: *i64 = sys_mmap(8 * 64) as *i64; fp_expiring_first(world, PM_INV, PM_DOM, PM_FOOD, 0, 3, m2, m2e)
108 let mb2: *i64 = sys_mmap(8 * 16) as *i64; let mr2: *i64 = sys_mmap(8 * 16) as *i64
109 let nm2: i64 = fp_choose(PM_FOOD, world, m2e, mb2, mr2)
110 g_p(" meal 2: " as *u8); g_show(world, mb2, nm2)
111 fp_consume_build(PM_INV, PM_DOM, world, mb2, nm2)
112 let q2: i64 = fp_total_qty(PM_INV, PM_DOM)
113 g_p(" pantry stock: " as *u8); g_i(q0); g_p(" -> " as *u8); g_i(q2); g_p(" units after 2 meals\n" as *u8)
114 tot = tot + 1
115 var ok4: i64 = 1
116 if nm1 != 5 { ok4 = 0 }
117 if nm2 != 5 { ok4 = 0 }
118 if q0 - q2 != 10 { ok4 = 0 }
119 if ok4 == 1 { pass = pass + 1; g_p("PASS T4 meal plan: 2 meals cooked, inventory consumed (10 units depleted)\n" as *u8) } else { g_p("FAIL T4 (q0=" as *u8); g_i(q0); g_p(" q2=" as *u8); g_i(q2); g_p(" nm1=" as *u8); g_i(nm1); g_p(" nm2=" as *u8); g_i(nm2); g_p(")\n" as *u8) }
120
121 g_p("nx_pantry_meal_gate pass=" as *u8); g_i(pass); g_p("/" as *u8); g_i(tot)
122 if pass == tot { g_p(" verdict=GREEN (pantry -> expiry -> what can I make -> meal plan, inventory consumed)\n" as *u8); return 0 }
123 g_p(" verdict=RED\n" as *u8)
124 return 1
125}