nx_econsim_page.nx source
↩ module page · 245 lines · 15361 B
1// nx_econsim_page.nx -- EMIT the live nishifamily.com/econsim page for the
2// Capitalism Lab (EconSim). Self-contained game-side emitter: it imports the
3// sovereign sim organs and renders their output COMPUTED AT RENDER TIME (no
4// hand-typed numbers), then writes web_assets/econsim.html. Publishing is the
5// separate sovereign step nx_aw_push (additive, vault-backed) -- the shared
6// loop every property reuses. No JS/HTML is hand-written; this organ authors
7// the page. license_tier: ORIGINAL
8//
9// genealogy_id: capitalism_lab_econsim_page
10// lineage_id: nx_econsim_page_v1
11
12import "nx_syscalls.nx"
13import "nx_caplab_market.nx"
14import "nx_caplab_compete.nx"
15import "nx_caplab_supply.nx"
16import "nx_caplab_sim.nx"
17import "nx_caplab_quality.nx"
18
19const EC_OUT: *u8 = "web_assets/econsim.html"
20const EC_CAP: i64 = 262144
21
22// append a NUL-terminated string into dst at off; returns new off.
23func ec_cat(dst: *u8, off: i64, s: *u8) -> i64 {
24 var o: i64 = off
25 var i: i64 = 0
26 while s[i] != 0 as u8 { dst[o] = s[i]; o = o + 1; i = i + 1 }
27 return o
28}
29
30// append a signed decimal into dst at off; returns new off (handles losses).
31func ec_catn(dst: *u8, off: i64, v: i64) -> i64 {
32 var o: i64 = off
33 var n: i64 = v
34 if n < 0 { dst[o] = 45 as u8; o = o + 1; n = 0 - n }
35 let tmp: *u8 = sys_mmap(32)
36 var k: i64 = 0
37 if n == 0 { tmp[0] = 48 as u8; k = 1 }
38 while n > 0 { tmp[k] = (48 + (n % 10)) as u8; n = n / 10; k = k + 1 }
39 var j: i64 = k - 1
40 while j >= 0 { dst[o] = tmp[j]; o = o + 1; j = j - 1 }
41 return o
42}
43
44func main() -> i64 {
45 let now: i64 = sys_now_realtime_sec()
46 let h: *u8 = sys_mmap(EC_CAP)
47 var w: i64 = 0
48
49 // market under view (same atom the R0 gate proves): a=100, b=2, cost=10
50 let mkt_a: i64 = 100
51 let mkt_b: i64 = 2
52 let mkt_c: i64 = 10
53
54 w = ec_cat(h, w, "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\">\n" as *u8)
55 w = ec_cat(h, w, "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n" as *u8)
56 w = ec_cat(h, w, "<title>EconSim — Nishi Capitalism Lab</title>\n" as *u8)
57 w = ec_cat(h, w, "<style>\n" as *u8)
58 w = ec_cat(h, w, ":root{--bg:#0b0f14;--panel:#131b24;--ink:#e6edf3;--mut:#8aa0b4;--acc:#4cc2ff;--good:#3fb950;--bad:#f85149;--line:#243140}\n" as *u8)
59 w = ec_cat(h, w, "*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.55 system-ui,Segoe UI,Roboto,sans-serif}\n" as *u8)
60 w = ec_cat(h, w, "header{padding:32px 20px 18px;max-width:920px;margin:0 auto}h1{margin:0;font-size:30px;letter-spacing:.3px}\n" as *u8)
61 w = ec_cat(h, w, ".sub{color:var(--mut);margin:.5em 0 0}.stamp{color:var(--mut);font-size:12.5px;margin:.4em 0 0}\n" as *u8)
62 w = ec_cat(h, w, "main{max-width:920px;margin:0 auto;padding:0 20px 60px}section{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:18px 20px;margin:18px 0}\n" as *u8)
63 w = ec_cat(h, w, "h2{margin:.1em 0 .3em;font-size:19px}code{color:var(--acc);font-size:.92em}\n" as *u8)
64 w = ec_cat(h, w, "table{border-collapse:collapse;width:100%;margin:.6em 0}th,td{padding:7px 10px;text-align:right;border-bottom:1px solid var(--line)}th:first-child,td:first-child{text-align:left}\n" as *u8)
65 w = ec_cat(h, w, "th{color:var(--mut);font-weight:600;font-size:12.5px;text-transform:uppercase;letter-spacing:.4px}\n" as *u8)
66 w = ec_cat(h, w, ".pos{color:var(--good)}.neg{color:var(--bad)}.peak{background:#10261a}\n" as *u8)
67 w = ec_cat(h, w, ".ladder{list-style:none;padding:0;margin:.4em 0}.ladder li{padding:4px 0;border-bottom:1px solid var(--line)}.done{color:var(--good)}.todo{color:var(--mut)}\n" as *u8)
68 w = ec_cat(h, w, "footer{max-width:920px;margin:0 auto;padding:8px 20px 40px;color:var(--mut);font-size:12.5px}\n" as *u8)
69 w = ec_cat(h, w, "</style></head><body>\n" as *u8)
70
71 w = ec_cat(h, w, "<header><h1>EconSim — Capitalism Lab</h1>\n" as *u8)
72 w = ec_cat(h, w, "<p class=\"sub\">An in-browser, multiplayer economic strategy game built 100% on the Nishi sovereign stack — no shell, no Python, no hand-written JS/HTML. This page was emitted by the organ <code>nx_econsim_page</code>.</p>\n" as *u8)
73 w = ec_cat(h, w, "<p class=\"stamp\">Generated LIVE at epoch " as *u8)
74 w = ec_catn(h, w, now)
75 w = ec_cat(h, w, " — every number below is COMPUTED by the sovereign sim (<code>nx_caplab_market</code> + <code>nx_caplab_compete</code>) at render time, not typed in.</p></header>\n" as *u8)
76
77 w = ec_cat(h, w, "<main>\n" as *u8)
78
79 // ===== R0: the market atom =====
80 w = ec_cat(h, w, "<section><h2>R0 — the market atom (one firm)</h2>\n" as *u8)
81 w = ec_cat(h, w, "<p>Linear demand: max demand <b>100</b>, slope <b>2</b>, unit cost <b>10</b>. Demand falls as price rises; profit = (price − cost) × units sold.</p>\n" as *u8)
82 w = ec_cat(h, w, "<table><tr><th>Price</th><th>Demand</th><th>Revenue</th><th>Profit</th></tr>\n" as *u8)
83 let opt: i64 = nx_clab_optimal_price(mkt_a, mkt_b, mkt_c)
84 var p: i64 = 0
85 while p <= 50 {
86 let pf: i64 = nx_clab_profit(mkt_a, mkt_b, p, mkt_c)
87 if p == opt { w = ec_cat(h, w, "<tr class=\"peak\">" as *u8) }
88 else { w = ec_cat(h, w, "<tr>" as *u8) }
89 w = ec_cat(h, w, "<td>" as *u8); w = ec_catn(h, w, p)
90 w = ec_cat(h, w, "</td><td>" as *u8); w = ec_catn(h, w, nx_clab_demand(mkt_a, mkt_b, p))
91 w = ec_cat(h, w, "</td><td>" as *u8); w = ec_catn(h, w, nx_clab_revenue(mkt_a, mkt_b, p))
92 if pf < 0 { w = ec_cat(h, w, "</td><td class=\"neg\">" as *u8) }
93 else { w = ec_cat(h, w, "</td><td class=\"pos\">" as *u8) }
94 w = ec_catn(h, w, pf)
95 w = ec_cat(h, w, "</td></tr>\n" as *u8)
96 p = p + 10
97 }
98 w = ec_cat(h, w, "</table>\n" as *u8)
99 w = ec_cat(h, w, "<p>The sim's optimiser scans every price and returns the profit-maximising one: <b>" as *u8)
100 w = ec_catn(h, w, opt)
101 w = ec_cat(h, w, "</b> (profit <b>" as *u8)
102 w = ec_catn(h, w, nx_clab_profit(mkt_a, mkt_b, opt, mkt_c))
103 w = ec_cat(h, w, "</b>) — which matches the closed-form monopoly price. The highlighted row is that peak.</p></section>\n" as *u8)
104
105 // ===== R1: competition =====
106 w = ec_cat(h, w, "<section><h2>R1 — competition (three firms, one market)</h2>\n" as *u8)
107 w = ec_cat(h, w, "<p>Max willingness-to-pay <b>100</b>, <b>100</b> customers. Customers split by how far each firm undercuts; the split is conserved (largest-remainder) so quantities always sum to the market. Each firm's unit cost is <b>20</b>.</p>\n" as *u8)
108 let prices: *i64 = sys_mmap(24) as *i64
109 prices[0] = 40
110 prices[1] = 50
111 prices[2] = 60
112 let q: *i64 = sys_mmap(24) as *i64
113 nx_clab_split(3, prices, 100, 100, q)
114 w = ec_cat(h, w, "<table><tr><th>Firm price</th><th>Customers</th><th>Profit</th></tr>\n" as *u8)
115 var f: i64 = 0
116 var qsum: i64 = 0
117 while f < 3 {
118 w = ec_cat(h, w, "<tr><td>" as *u8); w = ec_catn(h, w, prices[f])
119 w = ec_cat(h, w, "</td><td>" as *u8); w = ec_catn(h, w, q[f])
120 w = ec_cat(h, w, "</td><td class=\"pos\">" as *u8); w = ec_catn(h, w, nx_clab_firm_profit(prices[f], 20, q[f]))
121 w = ec_cat(h, w, "</td></tr>\n" as *u8)
122 qsum = qsum + q[f]
123 f = f + 1
124 }
125 w = ec_cat(h, w, "<tr><td><b>total</b></td><td><b>" as *u8); w = ec_catn(h, w, qsum)
126 w = ec_cat(h, w, "</b></td><td></td></tr>\n" as *u8)
127 w = ec_cat(h, w, "</table>\n" as *u8)
128 w = ec_cat(h, w, "<p>The cheapest firm wins the most <i>customers</i> — but margin × volume decides who actually earns the most. That tension is the whole game.</p></section>\n" as *u8)
129
130 // ===== R2: supply chain =====
131 w = ec_cat(h, w, "<section><h2>R2 — production & supply chains</h2>\n" as *u8)
132 w = ec_cat(h, w, "<p>No magic costs: a firm converts raw → factory → finished, and input costs roll UP into the unit cost it prices against. Output is capped by the scarcest input.</p>\n" as *u8)
133 let sqp: *i64 = (sys_mmap(8)) as *i64
134 sqp[0] = 2
135 let spr: *i64 = (sys_mmap(8)) as *i64
136 spr[0] = 5
137 let s_inter: i64 = nx_clab_unit_cost(1, sqp, spr, 3)
138 let fqp: *i64 = (sys_mmap(8)) as *i64
139 fqp[0] = 3
140 let fpr: *i64 = (sys_mmap(8)) as *i64
141 fpr[0] = s_inter
142 let s_fin: i64 = nx_clab_unit_cost(1, fqp, fpr, 4)
143 w = ec_cat(h, w, "<table><tr><th>Stage</th><th>Recipe</th><th>Unit cost</th></tr>\n" as *u8)
144 w = ec_cat(h, w, "<tr><td>raw material</td><td>market price</td><td>" as *u8); w = ec_catn(h, w, 5); w = ec_cat(h, w, "</td></tr>\n" as *u8)
145 w = ec_cat(h, w, "<tr><td>intermediate</td><td>2 raw + proc 3</td><td>" as *u8); w = ec_catn(h, w, s_inter); w = ec_cat(h, w, "</td></tr>\n" as *u8)
146 w = ec_cat(h, w, "<tr><td>finished</td><td>3 intermediate + proc 4</td><td>" as *u8); w = ec_catn(h, w, s_fin); w = ec_cat(h, w, "</td></tr>\n" as *u8)
147 w = ec_cat(h, w, "</table>\n" as *u8)
148 let tqp: *i64 = (sys_mmap(16)) as *i64
149 tqp[0] = 2
150 tqp[1] = 1
151 let tst: *i64 = (sys_mmap(16)) as *i64
152 tst[0] = 100
153 tst[1] = 30
154 w = ec_cat(h, w, "<p>With 100 raw (2/unit) and 30 labor (1/unit), throughput is <b>" as *u8)
155 w = ec_catn(h, w, nx_clab_throughput(2, tqp, tst))
156 w = ec_cat(h, w, "</b> units — labor is the bottleneck. Pricing the finished good (cost " as *u8)
157 w = ec_catn(h, w, s_fin)
158 w = ec_cat(h, w, ") the optimiser sets price <b>" as *u8)
159 w = ec_catn(h, w, nx_clab_optimal_price(100, 2, s_fin))
160 w = ec_cat(h, w, "</b> — thin margins, because the supply chain is expensive.</p></section>\n" as *u8)
161
162 // ===== R3: a 12-month game over time =====
163 w = ec_cat(h, w, "<section><h2>R3 — a 12-month game (firms compete over time)</h2>\n" as *u8)
164 w = ec_cat(h, w, "<p>Three firms run a 12-month year. Each month the market splits by price, firms sell up to capacity, cash banks. Same inputs → identical replay (deterministic).</p>\n" as *u8)
165 let gp: *i64 = (sys_mmap(24)) as *i64
166 gp[0] = 60
167 gp[1] = 45
168 gp[2] = 35
169 let guc: *i64 = (sys_mmap(24)) as *i64
170 guc[0] = 20
171 guc[1] = 20
172 guc[2] = 20
173 let gcap: *i64 = (sys_mmap(24)) as *i64
174 gcap[0] = 100
175 gcap[1] = 100
176 gcap[2] = 100
177 let gcash: *i64 = (sys_mmap(24)) as *i64
178 gcash[0] = 0
179 gcash[1] = 0
180 gcash[2] = 0
181 nx_clab_sim_run(3, gp, guc, gcap, 100, 120, gcash, 12)
182 w = ec_cat(h, w, "<table><tr><th>Strategy</th><th>Price</th><th>Cash after 12 months</th></tr>\n" as *u8)
183 w = ec_cat(h, w, "<tr><td>premium</td><td>60</td><td class=\"pos\">" as *u8); w = ec_catn(h, w, gcash[0]); w = ec_cat(h, w, "</td></tr>\n" as *u8)
184 w = ec_cat(h, w, "<tr><td>mid-market</td><td>45</td><td class=\"pos\">" as *u8); w = ec_catn(h, w, gcash[1]); w = ec_cat(h, w, "</td></tr>\n" as *u8)
185 w = ec_cat(h, w, "<tr><td>discount</td><td>35</td><td class=\"pos\">" as *u8); w = ec_catn(h, w, gcash[2]); w = ec_cat(h, w, "</td></tr>\n" as *u8)
186 w = ec_cat(h, w, "</table>\n" as *u8)
187 w = ec_cat(h, w, "<p>At these inputs the premium price wins the year on margin — change the numbers and the winner changes. That's the game.</p></section>\n" as *u8)
188
189 // ===== R4: quality + brand =====
190 w = ec_cat(h, w, "<section><h2>R4 — quality & brand (why premium wins)</h2>\n" as *u8)
191 w = ec_cat(h, w, "<p>Customers weigh price, quality AND brand. A pricier product with better quality and brand can take MORE of the market than a cheap commodity — the heart of Capitalism Lab.</p>\n" as *u8)
192 let qpr: *i64 = (sys_mmap(16)) as *i64
193 qpr[0] = 40
194 qpr[1] = 60
195 let qql: *i64 = (sys_mmap(16)) as *i64
196 qql[0] = 0
197 qql[1] = 30
198 let qbr: *i64 = (sys_mmap(16)) as *i64
199 qbr[0] = 0
200 qbr[1] = 20
201 let qout: *i64 = (sys_mmap(16)) as *i64
202 nx_clab_split_qb(2, qpr, qql, qbr, 100, 1, 2, 1, 120, qout)
203 w = ec_cat(h, w, "<table><tr><th>Product</th><th>Price</th><th>Quality</th><th>Brand</th><th>Customers</th></tr>\n" as *u8)
204 w = ec_cat(h, w, "<tr><td>cheap commodity</td><td>40</td><td>0</td><td>0</td><td>" as *u8); w = ec_catn(h, w, qout[0]); w = ec_cat(h, w, "</td></tr>\n" as *u8)
205 w = ec_cat(h, w, "<tr><td>premium brand</td><td>60</td><td>30</td><td>20</td><td class=\"pos\">" as *u8); w = ec_catn(h, w, qout[1]); w = ec_cat(h, w, "</td></tr>\n" as *u8)
206 w = ec_cat(h, w, "</table>\n" as *u8)
207 w = ec_cat(h, w, "<p>The premium product costs MORE yet wins more customers.</p></section>\n" as *u8)
208
209 // ===== build status =====
210 w = ec_cat(h, w, "<section><h2>Build status — from the hardware rung up</h2>\n" as *u8)
211 w = ec_cat(h, w, "<ul class=\"ladder\">\n" as *u8)
212 w = ec_cat(h, w, "<li class=\"done\">✓ R0 — economic atom: single-firm market (gate 15/15, sovereign)</li>\n" as *u8)
213 w = ec_cat(h, w, "<li class=\"done\">✓ R1 — multi-firm price competition (gate 20/20, sovereign)</li>\n" as *u8)
214 w = ec_cat(h, w, "<li class=\"done\">✓ P0 — this page is live: emit → push → verify loop</li>\n" as *u8)
215 w = ec_cat(h, w, "<li class=\"done\">✓ R2 — production / supply chains (gate 8/8)</li>\n" as *u8)
216 w = ec_cat(h, w, "<li class=\"done\">✓ R3 — tick loop + AI competitor + game config (gate 17/17)</li>\n" as *u8)
217 w = ec_cat(h, w, "<li class=\"done\">✓ R4 — quality + brand demand (gate 11/11)</li>\n" as *u8)
218 w = ec_cat(h, w, "<li class=\"todo\">□ R5 — multiple products + categories</li>\n" as *u8)
219 w = ec_cat(h, w, "<li class=\"todo\">□ R6 — cities + retail units + per-city demand (the map)</li>\n" as *u8)
220 w = ec_cat(h, w, "<li class=\"todo\">□ R7 — firm finances: loans, debt, bankruptcy</li>\n" as *u8)
221 w = ec_cat(h, w, "<li class=\"todo\">□ R8 — stock market + corporations + acquisitions</li>\n" as *u8)
222 w = ec_cat(h, w, "<li class=\"todo\">□ then — interactive in-browser client + multiplayer; measured S-class census vs Capitalism Lab</li>\n" as *u8)
223 w = ec_cat(h, w, "</ul>\n" as *u8)
224 w = ec_cat(h, w, "<p class=\"stamp\">Honest scope: this is a live read-out of the sim so far, not yet the interactive game (that arrives at R4/R5). Numbers are real, computed on render.</p></section>\n" as *u8)
225
226 w = ec_cat(h, w, "</main>\n" as *u8)
227 w = ec_cat(h, w, "<footer>Sovereign Nishi stack · sim: <code>nx_caplab_market</code> + <code>nx_caplab_compete</code> · published via <code>nx_aw_push</code> · nishifamily.com/econsim</footer>\n" as *u8)
228 w = ec_cat(h, w, "</body></html>\n" as *u8)
229
230 let fd: i64 = sys_openat_wr(EC_OUT, 0x1a4)
231 if fd < 0 { sys_write(2, "FATAL: cannot open web_assets/econsim.html\n" as *u8, 43); sys_exit(2); return 2 }
232 sys_write(fd, h, w)
233 sys_close(fd)
234 sys_write(1, "[nx_econsim_page] wrote econsim.html bytes=" as *u8, 43)
235 let nb: *u8 = sys_mmap(28)
236 var k2: i64 = 0
237 var m2: i64 = w
238 if m2 == 0 { nb[0] = 48 as u8; k2 = 1 }
239 while m2 > 0 { nb[k2] = (48 + (m2 % 10)) as u8; m2 = m2 / 10; k2 = k2 + 1 }
240 var qd: i64 = k2 - 1
241 while qd >= 0 { let o1: *u8 = sys_mmap(1); o1[0] = nb[qd]; sys_write(1, o1, 1); qd = qd - 1 }
242 sys_write(1, "\n" as *u8, 1)
243 sys_exit(0)
244 return 0
245}