code wiki / _hdl_build / nx_pantry.nx
nx_pantry.nx source
↩ module page · 105 lines · 4714 B
1// nx_pantry.nx -- LIB: bridges the universal INVENTORY (a person's pantry stock) to the FOOD-SCIENCE engine.
2// "What can I make" = run the chooser over ONLY the ingredients you actually have (qty>0); "cook what's
3// expiring first" = bias the build toward soon-to-expire items to cut waste; "meal planning" = choose a meal
4// then CONSUME its ingredients from inventory so the next meal sees the depleted pantry. One engine, two
5// stores: the food store (knowledge/store/food-) holds the science; the inventory store holds the stock.
6// license_tier: ORIGINAL
7import "nx_inventory.nx"
8import "nx_food_science.nx"
9import "nx_syscalls.nx"
10
11// 1 if a pantry item is expiring within `within` days of `as_of` (0 expiry = non-perishable -> 0)
12func fp_is_expiring(inv_prefix: *u8, domain: *u8, id: *u8, as_of: i64, within: i64) -> i64 {
13 let e: i64 = iv_expiry(inv_prefix, domain, id)
14 if e > 0 { if e <= as_of + within { return 1 } }
15 return 0
16}
17
18// availability over the food world from the pantry: avail[i]=1 iff that ingredient is in stock (qty>0).
19// Returns the number of in-stock ingredients.
20func fp_pantry_avail(food_world: *i64, inv_prefix: *u8, domain: *u8, avail: *i64) -> i64 {
21 let n: i64 = food_world[0]
22 let ids: *i64 = food_world[1] as *i64
23 var c: i64 = 0
24 var i: i64 = 0
25 while i < n {
26 if iv_qty(inv_prefix, domain, ids[i] as *u8) > 0 { avail[i] = 1; c = c + 1 } else { avail[i] = 0 }
27 i = i + 1
28 }
29 return c
30}
31
32func fp_quota(frame: *i64, nframe: i64, rc: i64) -> i64 {
33 var c: i64 = 0
34 var i: i64 = 0
35 while i < nframe { if frame[i] == rc { c = c + 1 } i = i + 1 }
36 return c
37}
38
39// "cook what's expiring first": for each role with at least `quota` in-stock EXPIRING members, restrict that
40// role to its expiring members (so the build uses them up); other roles unchanged. Never makes a role
41// unfillable (only restricts when enough expiring members exist to meet the quota). Writes into avail_out.
42func fp_expiring_first(food_world: *i64, inv_prefix: *u8, domain: *u8, food_prefix: *u8, as_of: i64, within: i64, avail_in: *i64, avail_out: *i64) -> i64 {
43 let n: i64 = food_world[0]
44 let ids: *i64 = food_world[1] as *i64
45 let role: *i64 = food_world[2] as *i64
46 let frame: *i64 = sys_mmap(8 * 16) as *i64
47 let nframe: i64 = fd_load_frame(food_prefix, frame)
48 var i: i64 = 0
49 while i < n { avail_out[i] = avail_in[i]; i = i + 1 }
50 var rc: i64 = 1
51 while rc <= 4 {
52 let quota: i64 = fp_quota(frame, nframe, rc)
53 if quota > 0 {
54 var expcount: i64 = 0
55 i = 0
56 while i < n {
57 if role[i] == rc { if avail_in[i] == 1 { if fp_is_expiring(inv_prefix, domain, ids[i] as *u8, as_of, within) == 1 { expcount = expcount + 1 } } }
58 i = i + 1
59 }
60 if expcount >= quota {
61 i = 0
62 while i < n {
63 if role[i] == rc { if avail_in[i] == 1 {
64 if fp_is_expiring(inv_prefix, domain, ids[i] as *u8, as_of, within) == 1 { avail_out[i] = 1 } else { avail_out[i] = 0 }
65 } }
66 i = i + 1
67 }
68 }
69 }
70 rc = rc + 1
71 }
72 return 0
73}
74
75// consume one unit of every ingredient in a finished build from the pantry (meal cooked)
76func fp_consume_build(inv_prefix: *u8, domain: *u8, food_world: *i64, build: *i64, nb: i64) -> i64 {
77 let ids: *i64 = food_world[1] as *i64
78 var i: i64 = 0
79 while i < nb { iv_consume(inv_prefix, domain, ids[build[i]] as *u8, 1); i = i + 1 }
80 return 0
81}
82
83// total units of stock across the pantry domain (to show depletion across a meal plan)
84func fp_total_qty(inv_prefix: *u8, domain: *u8) -> i64 {
85 let items: *i64 = sys_mmap(8 * 256) as *i64
86 let n: i64 = iv_list(inv_prefix, domain, items)
87 var t: i64 = 0
88 var i: i64 = 0
89 while i < n { let q: i64 = iv_qty(inv_prefix, domain, items[i] as *u8); if q > 0 { t = t + q } i = i + 1 }
90 return t
91}
92
93// choose a meal over an availability mask (neutral preference); fills build/roles, returns slots filled
94func fp_choose(food_prefix: *u8, food_world: *i64, avail: *i64, build: *i64, roles: *i64) -> i64 {
95 let n: i64 = food_world[0]
96 let avoid: *i64 = sys_mmap(8 * 64) as *i64
97 let prefw: *i64 = sys_mmap(8 * 8) as *i64
98 fd_set_all(avoid, n, 0)
99 var z: i64 = 0; while z < FOOD_NAX { prefw[z] = 0; z = z + 1 }
100 let frame: *i64 = sys_mmap(8 * 16) as *i64
101 let nframe: i64 = fd_load_frame(food_prefix, frame)
102 let wts: *i64 = sys_mmap(8 * 8) as *i64
103 fd_load_weights(food_prefix, wts)
104 return fd_choose(food_world, avail, avoid, prefw, frame, nframe, wts, build, roles)
105}