code wiki / _hdl_build / nx_activities.nx
nx_activities.nx source
↩ module page · 171 lines · 9606 B
1// nx_activities.nx -- LIB: the REAL VALUE of popular homestead activities (operator: "gamification for LOTS of
2// these popular activities but not dumb rewards but real rewards and real positives and real capabilities"). For
3// each activity a person does, this computes the REAL, MEASURED positive -- money kept or value created -- from
4// REFERENCE PRICES (grounded, each with a source), NEVER an invented number. The output feeds nx_rewards as a
5// real VALUE reward. Activities: compost (fertilizer not bought), cook-from-pantry (takeout not bought),
6// seed-saving (seed packets not bought), preserve/can (out-of-season value), rainwater (water not bought).
7// Sovereign seg-store (knowledge/store/act-*, NO TSV), integer cents. license_tier: ORIGINAL
8import "nx_food_science.nx"
9import "nx_seg_store.nx"
10import "nx_syscalls.nx"
11
12func ac_put(prefix: *u8, key: *u8, val: *u8) -> i64 {
13 let vl: i64 = as_len(val)
14 if fd_streq_store(prefix, key, val, vl) == 1 { return 0 }
15 let w: *i64 = ss_begin()
16 ss_add(w, 1, key, val, vl)
17 let seg: i64 = fd_seg_next(prefix)
18 ss_commit(prefix, w, seg)
19 return 1
20}
21func ac_money(dst: *u8, off: i64, cents: i64) -> i64 {
22 var o: i64 = off
23 dst[o] = 36 as u8; o = o + 1
24 o = fd_apnum(dst, o, cents / 100)
25 dst[o] = 46 as u8; o = o + 1
26 let r: i64 = cents % 100
27 dst[o] = (48 + (r / 10)) as u8; o = o + 1
28 dst[o] = (48 + (r % 10)) as u8; o = o + 1
29 return o
30}
31
32// reference price (grounded): act:ref:<item> -> price_cents <t> unit <t> source
33func ac_set_ref(prefix: *u8, item: *u8, price_cents: i64, unit: *u8, source: *u8) -> i64 {
34 let key: *u8 = sys_mmap(96); var o: i64 = 0; o = as_append(key, o, "act:ref:" as *u8); o = as_append(key, o, item); key[o] = 0 as u8
35 let val: *u8 = sys_mmap(160); var v: i64 = 0
36 v = fd_apnum(val, v, price_cents); val[v] = 9 as u8; v = v + 1
37 v = as_append(val, v, unit); val[v] = 9 as u8; v = v + 1
38 v = as_append(val, v, source); val[v] = 0 as u8
39 return ac_put(prefix, key, val)
40}
41// reference price in cents, or -1 if not set (un-grounded -> value calc returns 0, never invents).
42func ac_ref(prefix: *u8, item: *u8) -> i64 {
43 let key: *u8 = sys_mmap(96); var o: i64 = 0; o = as_append(key, o, "act:ref:" as *u8); o = as_append(key, o, item); key[o] = 0 as u8
44 let pq: *i64 = sys_mmap(16) as *i64
45 let lq: *i64 = sys_mmap(16) as *i64
46 if ss_get(prefix, key, pq, lq) != 1 { return 0 - 1 }
47 let fb: *u8 = sys_mmap(24)
48 let fl: i64 = fd_field(pq[0] as *u8, lq[0], 0, fb)
49 return fd_atoi(fb, fl)
50}
51
52// the REAL value (cents) of doing `activity` at `quantity`, computed from reference prices. Unknown activity or
53// a missing reference -> 0 (honest: no grounding, no value; never a fabricated number).
54func ac_value_of(prefix: *u8, activity: *u8, quantity: i64) -> i64 {
55 if quantity <= 0 { return 0 }
56 if fd_streq(activity, "compost" as *u8) == 1 { // cubic feet of finished compost not bought
57 let p: i64 = ac_ref(prefix, "compost_cuft" as *u8)
58 if p < 0 { return 0 }
59 return quantity * p
60 }
61 if fd_streq(activity, "seedsave" as *u8) == 1 { // seed packets not bought next season
62 let p: i64 = ac_ref(prefix, "seed_packet" as *u8)
63 if p < 0 { return 0 }
64 return quantity * p
65 }
66 if fd_streq(activity, "cookpantry" as *u8) == 1 { // meals: takeout avoided minus home ingredient cost
67 let t: i64 = ac_ref(prefix, "takeout_meal" as *u8)
68 let h: i64 = ac_ref(prefix, "home_meal" as *u8)
69 if t < 0 { return 0 }
70 if h < 0 { return 0 }
71 let net: i64 = t - h
72 if net <= 0 { return 0 }
73 return quantity * net
74 }
75 if fd_streq(activity, "preserve" as *u8) == 1 { // jars of preserved/canned produce value
76 let p: i64 = ac_ref(prefix, "preserve_jar" as *u8)
77 if p < 0 { return 0 }
78 return quantity * p
79 }
80 if fd_streq(activity, "rainwater" as *u8) == 1 { // 100-gallon units of water not bought
81 let p: i64 = ac_ref(prefix, "water_100gal" as *u8)
82 if p < 0 { return 0 }
83 return quantity * p
84 }
85 return 0
86}
87
88// additive activity log: act:log:<uid>:<seq> -> activity <t> quantity <t> day <t> note ; act:logn:<uid> count
89func ac_logn_key(uid: *u8, out: *u8) -> i64 { var o: i64 = 0; o = as_append(out, o, "act:logn:" as *u8); o = as_append(out, o, uid); out[o] = 0 as u8; return o }
90func ac_log_key(uid: *u8, seq: i64, out: *u8) -> i64 { var o: i64 = 0; o = as_append(out, o, "act:log:" as *u8); o = as_append(out, o, uid); out[o] = 58 as u8; o = o + 1; o = fd_apnum(out, o, seq); out[o] = 0 as u8; return o }
91func ac_logn(prefix: *u8, uid: *u8) -> i64 {
92 let key: *u8 = sys_mmap(96); ac_logn_key(uid, key)
93 let pq: *i64 = sys_mmap(16) as *i64
94 let lq: *i64 = sys_mmap(16) as *i64
95 if ss_get(prefix, key, pq, lq) != 1 { return 0 }
96 return fd_atoi(pq[0] as *u8, lq[0])
97}
98func ac_log(prefix: *u8, uid: *u8, activity: *u8, quantity: i64, day: i64, note: *u8) -> i64 {
99 let seq: i64 = ac_logn(prefix, uid)
100 let key: *u8 = sys_mmap(96); ac_log_key(uid, seq, key)
101 let val: *u8 = sys_mmap(256); var v: i64 = 0
102 v = as_append(val, v, activity); val[v] = 9 as u8; v = v + 1
103 v = fd_apnum(val, v, quantity); val[v] = 9 as u8; v = v + 1
104 v = fd_apnum(val, v, day); val[v] = 9 as u8; v = v + 1
105 v = as_append(val, v, note); val[v] = 0 as u8
106 ac_put(prefix, key, val)
107 let nk: *u8 = sys_mmap(96); ac_logn_key(uid, nk)
108 let nv: *u8 = sys_mmap(16); var no: i64 = fd_apnum(nv, 0, seq + 1); nv[no] = 0 as u8
109 ac_put(prefix, nk, nv)
110 return seq
111}
112func ac_log_str(prefix: *u8, uid: *u8, seq: i64, f: i64, out: *u8) -> i64 {
113 let key: *u8 = sys_mmap(96); ac_log_key(uid, seq, key)
114 let pq: *i64 = sys_mmap(16) as *i64
115 let lq: *i64 = sys_mmap(16) as *i64
116 if ss_get(prefix, key, pq, lq) != 1 { out[0] = 0 as u8; return 0 }
117 return fd_field(pq[0] as *u8, lq[0], f, out)
118}
119func ac_log_int(prefix: *u8, uid: *u8, seq: i64, f: i64) -> i64 {
120 let fb: *u8 = sys_mmap(24)
121 let fl: i64 = ac_log_str(prefix, uid, seq, f, fb)
122 if fl == 0 { return 0 }
123 return fd_atoi(fb, fl)
124}
125
126// total REAL value across everything the user has logged (the real positive of their habits).
127func ac_user_value(prefix: *u8, uid: *u8) -> i64 {
128 let n: i64 = ac_logn(prefix, uid)
129 var s: i64 = 0
130 var i: i64 = 0
131 while i < n {
132 let act: *u8 = sys_mmap(48); ac_log_str(prefix, uid, i, 0, act)
133 let q: i64 = ac_log_int(prefix, uid, i, 1)
134 s = s + ac_value_of(prefix, act, q)
135 i = i + 1
136 }
137 return s
138}
139
140func ac_activity_label(activity: *u8) -> *u8 {
141 if fd_streq(activity, "compost" as *u8) == 1 { return "Composting" as *u8 }
142 if fd_streq(activity, "seedsave" as *u8) == 1 { return "Seed saving" as *u8 }
143 if fd_streq(activity, "cookpantry" as *u8) == 1 { return "Cooking from the pantry" as *u8 }
144 if fd_streq(activity, "preserve" as *u8) == 1 { return "Preserving & canning" as *u8 }
145 if fd_streq(activity, "rainwater" as *u8) == 1 { return "Rainwater harvesting" as *u8 }
146 return "Activity" as *u8
147}
148
149// render the user's REAL positives (each activity + measured value + total). Sovereign, honest grounding note.
150func ac_render(prefix: *u8, uid: *u8, out: *u8) -> i64 {
151 var o: i64 = 0
152 o = as_append(out, o, "<!doctype html><html lang='en'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>Real positives</title><style>body{margin:0;font-family:system-ui,sans-serif;color:#1a2616;background:#eef6ea;line-height:1.5}header{background:#3a6b2f;color:#fff;padding:22px}header h1{margin:0;font-size:1.4rem}header p{margin:4px 0 0;color:#d7efce}main{max-width:680px;margin:0 auto;padding:16px}section{background:#fff;border-radius:14px;padding:16px 18px;margin-top:16px;box-shadow:0 1px 0 #dcebd3}h2{font-size:1.1rem;margin:0 0 8px;color:#3a6b2f}.tot{font-size:1.7rem;font-weight:800;color:#2f7a1f}table{border-collapse:collapse;width:100%}td,th{padding:8px 10px;text-align:left;border-top:1px solid #eef3e2}th{background:#e6efe1;color:#33503f}td.n{text-align:right;font-variant-numeric:tabular-nums;font-weight:700;color:#2f7a1f}.muted{color:#5b6a52;font-size:.88rem}</style></head><body><header><h1>Your real positives</h1><p>The measured value of the good things you actually did.</p></header><main>" as *u8)
153 o = as_append(out, o, "<section><h2>Value created this season</h2><p class='tot'>" as *u8)
154 o = ac_money(out, o, ac_user_value(prefix, uid))
155 o = as_append(out, o, "</p></section><section><h2>How you earned it</h2><table><tr><th>Activity</th><th>Amount</th><th>Real value</th></tr>" as *u8)
156 let n: i64 = ac_logn(prefix, uid)
157 var i: i64 = 0
158 while i < n {
159 let act: *u8 = sys_mmap(48); ac_log_str(prefix, uid, i, 0, act)
160 let q: i64 = ac_log_int(prefix, uid, i, 1)
161 o = as_append(out, o, "<tr><td>" as *u8)
162 o = as_append(out, o, ac_activity_label(act))
163 o = as_append(out, o, "</td><td>" as *u8); o = fd_apnum(out, o, q)
164 o = as_append(out, o, "</td><td class='n'>" as *u8); o = ac_money(out, o, ac_value_of(prefix, act, q))
165 o = as_append(out, o, "</td></tr>" as *u8)
166 i = i + 1
167 }
168 o = as_append(out, o, "</table></section><p class='muted'>Each value is measured from reference prices (what you'd have paid), each with a source — not points, not invented. Real positives, real money kept.</p></main></body></html>" as *u8)
169 out[o] = 0 as u8
170 return o
171}