code wiki / _hdl_build / nx_game_genetics_gate.nx
nx_game_genetics_gate.nx source
↩ module page · 338 lines · 17387 B
1// nx_game_genetics_gate.nx -- proves the genetics core teaches REAL science by MEASURING the textbook
2// ratios out of the running simulation. Nothing here is asserted: every tooth crosses thousands of
3// virtual creatures and checks the emergent numbers against what Mendel/Morgan/waddington predict.
4// If a tooth is green, a student could reproduce that number with a pencil and a Punnett square.
5// MUTATION TARGET (documented): break segregation in gx_gamete (always pass allele 0) => T1 monohybrid
6// ratio collapses to 4:0 => RED, while the independent-assortment and epigenetic teeth are unaffected.
7// license_tier: ORIGINAL
8import "nx_syscalls.nx"
9import "nx_game_genetics.nx"
10
11// evidence-line builders (local, so the gate stays self-contained)
12func gg_cat(b: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var i: i64 = 0; while s[i] != (0 as u8) { b[o] = s[i]; o = o + 1; i = i + 1 } return o }
13func gg_catn(b: *u8, off: i64, v: i64) -> i64 {
14 var m: i64 = v
15 if m < 0 { m = 0 }
16 let t: *u8 = sys_mmap(28)
17 var k: i64 = 0
18 if m == 0 { t[0] = 48 as u8; k = 1 }
19 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
20 var o: i64 = off
21 var i: i64 = 0
22 while i < k { b[o] = t[k - 1 - i]; o = o + 1; i = i + 1 }
23 return o
24}
25
26func p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
27func pn(v: i64) -> i64 {
28 let t: *u8 = sys_mmap(32) as *u8
29 var m: i64 = v
30 var w: i64 = 0
31 if m < 0 { t[w] = 45 as u8; w = w + 1; m = 0 - m }
32 if m == 0 { t[w] = 48 as u8; sys_write(1, t, w + 1); return 0 }
33 let d: *u8 = sys_mmap(32) as *u8
34 var k: i64 = 0
35 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
36 var j: i64 = 0
37 while j < k { t[w] = d[k - 1 - j]; w = w + 1; j = j + 1 }
38 sys_write(1, t, w)
39 return 0
40}
41func nl() -> i64 { p("\n" as *u8); return 0 }
42
43const N: i64 = 8000 // sample size: big enough that a 3:1 lands inside +/-40 permil
44const TOL: i64 = 45 // permil tolerance on every predicted ratio
45
46func near(got: i64, want: i64) -> i64 {
47 var d: i64 = got - want
48 if d < 0 { d = 0 - d }
49 if d <= TOL { return 1 }
50 return 0
51}
52
53func main() -> i64 {
54 p("=== nx_game_genetics_gate (real Mendelian + modern genetics, MEASURED) ===\n" as *u8)
55 var pass: i64 = 0
56 let checks: i64 = 9
57 let s: *i64 = sys_mmap(16) as *i64
58 s[0] = 20260727
59
60 // ---------- T1 MONOHYBRID CROSS Hh x Hh -> genotypes 1:2:1, phenotypes 3:1 (Mendel's 1st law) ----------
61 let het: i64 = gx_set(0, GX_HORN, 0, 1)
62 var homD: i64 = 0
63 var hetC: i64 = 0
64 var homR: i64 = 0
65 var domPh: i64 = 0
66 var i: i64 = 0
67 while i < N {
68 let c: i64 = gx_cross(het, het, s)
69 let a: i64 = gx_a0(c, GX_HORN)
70 let b: i64 = gx_a1(c, GX_HORN)
71 if a == 1 { if b == 1 { homD = homD + 1 } }
72 if a != b { hetC = hetC + 1 }
73 if a == 0 { if b == 0 { homR = homR + 1 } }
74 if gx_phenotype(c, GX_HORN) == 1 { domPh = domPh + 1 }
75 i = i + 1
76 }
77 let g_homD: i64 = homD * 1000 / N
78 let g_het: i64 = hetC * 1000 / N
79 let g_homR: i64 = homR * 1000 / N
80 let ph_dom: i64 = domPh * 1000 / N
81 var t1: i64 = 0
82 if near(g_homD, 250) { if near(g_het, 500) { if near(g_homR, 250) { if near(ph_dom, 750) { t1 = 1 } } } }
83 if t1 == 1 { pass = pass + 1; p("T1 GREEN monohybrid Hh x Hh: genotypes " as *u8); pn(g_homD); p(":" as *u8); pn(g_het); p(":" as *u8); pn(g_homR); p(" permil (textbook 250:500:250), phenotype dominant " as *u8); pn(ph_dom); p(" (textbook 750 = the 3:1)\n" as *u8) }
84 if t1 == 0 { p("T1 RED monohybrid " as *u8); pn(g_homD); p(":" as *u8); pn(g_het); p(":" as *u8); pn(g_homR); p(" ph=" as *u8); pn(ph_dom); nl() }
85
86 // ---------- T2 DIHYBRID 9:3:3:1 (Mendel's 2nd law -- independent assortment) ----------
87 // use two UNLINKED traits: HORN is linked to TAIL, so cross HORN x WING instead.
88 var dihyb: i64 = gx_set(0, GX_HORN, 0, 1)
89 dihyb = gx_set(dihyb, GX_WING, 0, 1)
90 var c99: i64 = 0
91 var c93: i64 = 0
92 var c39: i64 = 0
93 var c11: i64 = 0
94 var j: i64 = 0
95 while j < N {
96 let c: i64 = gx_cross(dihyb, dihyb, s)
97 let ph1: i64 = gx_phenotype(c, GX_HORN)
98 let ph2: i64 = gx_phenotype(c, GX_WING)
99 if ph1 == 1 { if ph2 == 1 { c99 = c99 + 1 } }
100 if ph1 == 1 { if ph2 == 0 { c93 = c93 + 1 } }
101 if ph1 == 0 { if ph2 == 1 { c39 = c39 + 1 } }
102 if ph1 == 0 { if ph2 == 0 { c11 = c11 + 1 } }
103 j = j + 1
104 }
105 let r99: i64 = c99 * 1000 / N
106 let r93: i64 = c93 * 1000 / N
107 let r39: i64 = c39 * 1000 / N
108 let r11: i64 = c11 * 1000 / N
109 var t2: i64 = 0
110 if near(r99, 562) { if near(r93, 187) { if near(r39, 187) { if near(r11, 62) { t2 = 1 } } } }
111 if t2 == 1 { pass = pass + 1; p("T2 GREEN dihybrid independent assortment: " as *u8); pn(r99); p(":" as *u8); pn(r93); p(":" as *u8); pn(r39); p(":" as *u8); pn(r11); p(" permil = the 9:3:3:1 (562:187:187:62)\n" as *u8) }
112 if t2 == 0 { p("T2 RED dihybrid " as *u8); pn(r99); p(":" as *u8); pn(r93); p(":" as *u8); pn(r39); p(":" as *u8); pn(r11); nl() }
113
114 // ---------- T3 INCOMPLETE DOMINANCE: F1 all pink, F2 phenotypes 1:2:1 (NOT 3:1) ----------
115 let red: i64 = gx_set(0, GX_COAT, 1, 1)
116 let white: i64 = gx_set(0, GX_COAT, 0, 0)
117 var f1_all_rose: i64 = 1
118 var k3: i64 = 0
119 while k3 < 200 {
120 let f1: i64 = gx_cross(red, white, s)
121 if gx_phenotype(f1, GX_COAT) != 1 { f1_all_rose = 0 }
122 k3 = k3 + 1
123 }
124 let rose: i64 = gx_set(0, GX_COAT, 0, 1)
125 var pW: i64 = 0
126 var pR: i64 = 0
127 var pC: i64 = 0
128 var m3: i64 = 0
129 while m3 < N {
130 let c: i64 = gx_cross(rose, rose, s)
131 let ph: i64 = gx_phenotype(c, GX_COAT)
132 if ph == 0 { pW = pW + 1 }
133 if ph == 1 { pR = pR + 1 }
134 if ph == 2 { pC = pC + 1 }
135 m3 = m3 + 1
136 }
137 let iw: i64 = pW * 1000 / N
138 let ir: i64 = pR * 1000 / N
139 let ic: i64 = pC * 1000 / N
140 var t3: i64 = 0
141 if f1_all_rose == 1 { if near(iw, 250) { if near(ir, 500) { if near(ic, 250) { t3 = 1 } } } }
142 if t3 == 1 { pass = pass + 1; p("T3 GREEN incomplete dominance: crimson x white -> ALL rose (F1), F2 phenotypes " as *u8); pn(ic); p(":" as *u8); pn(ir); p(":" as *u8); pn(iw); p(" = 1:2:1, NOT 3:1 (that is how you tell it from simple dominance)\n" as *u8) }
143 if t3 == 0 { p("T3 RED incomplete f1=" as *u8); pn(f1_all_rose); p(" " as *u8); pn(ic); p(":" as *u8); pn(ir); p(":" as *u8); pn(iw); nl() }
144
145 // ---------- T4 CODOMINANCE / ABO: A0 x B0 -> 1:1:1:1 of AB, A, B, O ----------
146 let pa: i64 = gx_set(0, GX_ELEM, 1, 0) // A O
147 let pb: i64 = gx_set(0, GX_ELEM, 2, 0) // B O
148 var nAB: i64 = 0
149 var nA: i64 = 0
150 var nB: i64 = 0
151 var nO: i64 = 0
152 var m4: i64 = 0
153 while m4 < N {
154 let c: i64 = gx_cross(pa, pb, s)
155 let ph: i64 = gx_phenotype(c, GX_ELEM)
156 if ph == 3 { nAB = nAB + 1 }
157 if ph == 1 { nA = nA + 1 }
158 if ph == 2 { nB = nB + 1 }
159 if ph == 0 { nO = nO + 1 }
160 m4 = m4 + 1
161 }
162 let qAB: i64 = nAB * 1000 / N
163 let qA: i64 = nA * 1000 / N
164 let qB: i64 = nB * 1000 / N
165 let qO: i64 = nO * 1000 / N
166 var t4: i64 = 0
167 if near(qAB, 250) { if near(qA, 250) { if near(qB, 250) { if near(qO, 250) { t4 = 1 } } } }
168 if t4 == 1 { pass = pass + 1; p("T4 GREEN codominance (ABO): AO x BO -> AB " as *u8); pn(qAB); p(" / A " as *u8); pn(qA); p(" / B " as *u8); pn(qB); p(" / O " as *u8); pn(qO); p(" = the real 1:1:1:1, and AB expresses BOTH\n" as *u8) }
169 if t4 == 0 { p("T4 RED ABO " as *u8); pn(qAB); p(":" as *u8); pn(qA); p(":" as *u8); pn(qB); p(":" as *u8); pn(qO); nl() }
170
171 // ---------- T5 TEST CROSS 1:1 + the PUNNETT widget agrees with the simulation ----------
172 var nDom: i64 = 0
173 var m5: i64 = 0
174 while m5 < N {
175 let c: i64 = gx_cross(het, gx_set(0, GX_HORN, 0, 0), s)
176 if gx_phenotype(c, GX_HORN) == 1 { nDom = nDom + 1 }
177 m5 = m5 + 1
178 }
179 let tc: i64 = nDom * 1000 / N
180 let sq: *i64 = sys_mmap(16 * 8) as *i64
181 let distinct: i64 = gx_punnett(het, het, GX_HORN, sq)
182 let odds_dom: i64 = gx_odds_permil(het, het, GX_HORN, 1)
183 let odds_tc: i64 = gx_odds_permil(het, gx_set(0, GX_HORN, 0, 0), GX_HORN, 1)
184 var t5: i64 = 0
185 if near(tc, 500) { if odds_dom == 750 { if odds_tc == 500 { if distinct == 2 { t5 = 1 } } } }
186 if t5 == 1 { pass = pass + 1; p("T5 GREEN test cross Hh x hh measured " as *u8); pn(tc); p(" permil dominant = 1:1, and the PUNNETT widget independently predicts 750 (Hh x Hh) / 500 (test cross) -- the tool agrees with the world\n" as *u8) }
187 if t5 == 0 { p("T5 RED testcross=" as *u8); pn(tc); p(" odds=" as *u8); pn(odds_dom); p("/" as *u8); pn(odds_tc); nl() }
188
189 // ---------- T6 SEX-LINKAGE (ZW): mother determines sex ~1:1, and hemizygous daughters ----------
190 // father ZZ carrier (Z1 Z0), mother ZW with Z1. Sons get a Z from each parent; daughters get
191 // their ONLY Z from the father -> a carrier father produces luminous daughters, never luminous sons here.
192 let father: i64 = gx_sexgene(GX_SEX_M, 1, 0)
193 let mother: i64 = gx_sexgene(GX_SEX_F, 1, 0)
194 var sons: i64 = 0
195 var lum_daughters: i64 = 0
196 var lum_sons: i64 = 0
197 var daughters: i64 = 0
198 var m6: i64 = 0
199 while m6 < N {
200 let c: i64 = gx_cross_sex(mother, father, s)
201 if gx_sex(c) == GX_SEX_M {
202 sons = sons + 1
203 if gx_z_phenotype(c) == 0 { lum_sons = lum_sons + 1 }
204 }
205 if gx_sex(c) == GX_SEX_F {
206 daughters = daughters + 1
207 if gx_z_phenotype(c) == 0 { lum_daughters = lum_daughters + 1 }
208 }
209 m6 = m6 + 1
210 }
211 let sexratio: i64 = sons * 1000 / N
212 var lumd: i64 = 0
213 if daughters > 0 { lumd = lum_daughters * 1000 / daughters }
214 var lums: i64 = 0
215 if sons > 0 { lums = lum_sons * 1000 / sons }
216 var t6: i64 = 0
217 if near(sexratio, 500) { if near(lumd, 500) { if lums == 0 { t6 = 1 } } }
218 if t6 == 1 { pass = pass + 1; p("T6 GREEN sex-linkage (ZW): sex ratio " as *u8); pn(sexratio); p(" permil sons (mother decides), " as *u8); pn(lumd); p(" permil of DAUGHTERS luminous (hemizygous -- one Z, nothing to mask it) vs " as *u8); pn(lums); p(" of sons\n" as *u8) }
219 if t6 == 0 { p("T6 RED sexlink ratio=" as *u8); pn(sexratio); p(" lumd=" as *u8); pn(lumd); p(" lums=" as *u8); pn(lums); nl() }
220
221 // ---------- T7 LINKAGE + RECOMBINATION: linked genes co-inherit ~88%, unlinked ~50% ----------
222 // parent is double-heterozygous in COUPLING: chromosome1 = (H,T), chromosome2 = (h,t)
223 var coup: i64 = gx_set(0, GX_LINK_A, 1, 0)
224 coup = gx_set(coup, GX_LINK_B, 1, 0)
225 let info: *i64 = sys_mmap(8 * 8) as *i64
226 var parental: i64 = 0
227 var recomb_seen: i64 = 0
228 var m7: i64 = 0
229 while m7 < N {
230 let ga: *i64 = sys_mmap(8 * 8) as *i64
231 let r: i64 = gx_gamete_linked(coup, s, ga)
232 recomb_seen = recomb_seen + r
233 // parental gametes are (1,1) or (0,0); recombinant are (1,0) or (0,1)
234 if ga[0] == ga[1] { parental = parental + 1 }
235 m7 = m7 + 1
236 }
237 let par_permil: i64 = parental * 1000 / N
238 let rec_permil: i64 = recomb_seen * 1000 / N
239 // control: two UNLINKED traits must co-inherit at chance (500)
240 var unl: i64 = gx_set(0, GX_HORN, 1, 0)
241 unl = gx_set(unl, GX_WING, 1, 0)
242 var same_unlinked: i64 = 0
243 var m7b: i64 = 0
244 while m7b < N {
245 let g1: i64 = gx_gamete(unl, GX_HORN, s)
246 let g2: i64 = gx_gamete(unl, GX_WING, s)
247 if g1 == g2 { same_unlinked = same_unlinked + 1 }
248 m7b = m7b + 1
249 }
250 let unlinked_permil: i64 = same_unlinked * 1000 / N
251 var t7: i64 = 0
252 if near(par_permil, 880) { if near(rec_permil, 120) { if near(unlinked_permil, 500) { t7 = 1 } } }
253 if t7 == 1 { pass = pass + 1; p("T7 GREEN linkage: linked loci co-inherit " as *u8); pn(par_permil); p(" permil (map distance 12 cM -> " as *u8); pn(rec_permil); p(" recombinant), while UNLINKED loci sit at " as *u8); pn(unlinked_permil); p(" = chance. That contrast IS the discovery of gene mapping\n" as *u8) }
254 if t7 == 0 { p("T7 RED linkage par=" as *u8); pn(par_permil); p(" rec=" as *u8); pn(rec_permil); p(" unlinked=" as *u8); pn(unlinked_permil); nl() }
255
256 // ---------- T8 POLYGENIC: bell curve, mean at the middle, extremes RARE ----------
257 // both parents mid-dose heterozygous at all 4 loci -> children spread 0..8 around 4
258 var pg: i64 = 0
259 var li: i64 = 0
260 while li < GX_POLY_N { pg = pg | (1 << (li*2)); li = li + 1 } // allele0=1, allele1=0 at each locus
261 let hist: *i64 = sys_mmap(16 * 8) as *i64
262 var hz: i64 = 0
263 while hz < 12 { hist[hz] = 0; hz = hz + 1 }
264 var m8: i64 = 0
265 var total_dose: i64 = 0
266 while m8 < N {
267 let c: i64 = gx_poly_cross(pg, pg, s)
268 let d: i64 = gx_poly_dose(c)
269 hist[d] = hist[d] + 1
270 total_dose = total_dose + d
271 m8 = m8 + 1
272 }
273 let mean10: i64 = total_dose * 10 / N
274 let mid: i64 = hist[4] * 1000 / N
275 let extreme: i64 = (hist[0] + hist[8]) * 1000 / N
276 var t8: i64 = 0
277 if mean10 >= 38 { if mean10 <= 42 { if mid > extreme * 3 { if extreme < 40 { t8 = 1 } } } }
278 if t8 == 1 { pass = pass + 1; p("T8 GREEN polygenic size: mean dose " as *u8); pn(mean10); p("/10 (predicted 40), middle " as *u8); pn(mid); p(" permil vs both extremes together " as *u8); pn(extreme); p(" = a real bell curve. Selective breeding shifts a MEAN, it does not flip a switch\n" as *u8) }
279 if t8 == 0 { p("T8 RED polygenic mean=" as *u8); pn(mean10); p(" mid=" as *u8); pn(mid); p(" ext=" as *u8); pn(extreme); nl() }
280
281 // ---------- T9 EPIGENETICS: silencing changes EXPRESSION not GENOTYPE, is inherited, and FADES ----------
282 // A homozygous-dominant horned creature, methylated -> LOOKS hornless. Its genotype is untouched,
283 // so it still passes H to every child, and grandchildren (mark faded) look horned again.
284 let HH: i64 = gx_set(0, GX_HORN, 1, 1)
285 let eg0: i64 = gx_epi_imprint(0, GX_HORN, 3)
286 let looks: i64 = gx_expressed(HH, eg0, GX_HORN)
287 let geno_intact: i64 = gx_phenotype(HH, GX_HORN)
288 // pass it on: child inherits mark at strength 2 (faded by one), grandchild at 1, great-grand 0
289 let eg1: i64 = gx_epi_inherit(eg0, 0)
290 let eg2: i64 = gx_epi_inherit(eg1, 0)
291 let eg3: i64 = gx_epi_inherit(eg2, 0)
292 // and the ALLELE is provably still segregating: cross the silenced parent with a recessive
293 var passedH: i64 = 0
294 var m9: i64 = 0
295 while m9 < N {
296 let c: i64 = gx_cross(HH, gx_set(0, GX_HORN, 0, 0), s)
297 if gx_a0(c, GX_HORN) == 1 { passedH = passedH + 1 }
298 if gx_a1(c, GX_HORN) == 1 { passedH = passedH + 1 }
299 m9 = m9 + 1
300 }
301 let inherit_rate: i64 = passedH * 1000 / N // every child gets exactly one H => 1000
302 var t9: i64 = 0
303 if looks == 0 { if geno_intact == 1 {
304 if gx_epi_strength(eg1, GX_HORN) == 2 { if gx_epi_strength(eg2, GX_HORN) == 1 {
305 if gx_epi_marked(eg3, GX_HORN) == 0 {
306 if inherit_rate == 1000 { t9 = 1 }
307 } } }
308 } }
309 if t9 == 1 { pass = pass + 1; p("T9 GREEN epigenetics: a methylated HH LOOKS hornless (expressed " as *u8); pn(looks); p(") while its genotype stays dominant (" as *u8); pn(geno_intact); p("); the mark is inherited but FADES 3->2->1->gone; and the H allele still passes to " as *u8); pn(inherit_rate); p("/1000 children. Expression changed, DNA did not\n" as *u8) }
310 if t9 == 0 { p("T9 RED epi looks=" as *u8); pn(looks); p(" geno=" as *u8); pn(geno_intact); p(" fade=" as *u8); pn(gx_epi_strength(eg1, GX_HORN)); p("/" as *u8); pn(gx_epi_strength(eg2, GX_HORN)); p("/" as *u8); pn(gx_epi_marked(eg3, GX_HORN)); p(" inh=" as *u8); pn(inherit_rate); nl() }
311
312 p("nx_game_genetics_gate: " as *u8); pn(pass); p("/" as *u8); pn(checks); nl()
313
314 // EVIDENCE (2026-07-30): the genetics/bio lane has EIGHT gate organs (genome, game_genetics,
315 // game_breed, breeder_arena, genetic_algorithm, wasm_breeders, biotwin_board, biotwin_morphometrics)
316 // and NOT ONE of them wrote to knowledge/status -- so nx_gatereg_derive could not see the lane and
317 // the maturity rollup could not grade it. Fourth confirmation of the same defect after lab-science
318 // (43 gates), the browser renderer (24) and search (36): these lanes were never UNMEASURED, they
319 // were UNREADABLE. This gate is the lane's strongest witness -- Mendelian ratios MEASURED from the
320 // simulation rather than asserted -- so it carries the anchor.
321 // Plain verdict=GREEN|RED: gv_is_pass accepts GREEN|PASS|VALID only. Do not invent a fifth word.
322 let gfd: i64 = sys_openat_append("knowledge/status/genetics_gate.log\x00" as *u8, 420)
323 if gfd >= 0 {
324 let gb: *u8 = sys_mmap(256)
325 var go: i64 = 0
326 go = gg_cat(gb, go, "GENETICS-GATE rows=" as *u8)
327 go = gg_catn(gb, go, checks)
328 go = gg_cat(gb, go, " passed=" as *u8)
329 go = gg_catn(gb, go, pass)
330 if pass == checks { go = gg_cat(gb, go, " verdict=GREEN\n" as *u8) } else { go = gg_cat(gb, go, " verdict=RED\n" as *u8) }
331 sys_write(gfd, gb, go)
332 sys_close(gfd)
333 }
334
335 if pass == checks { p("VERDICT GREEN -- every ratio above was MEASURED from the simulation, not asserted\n" as *u8); return 0 }
336 p("VERDICT RED\n" as *u8)
337 return 1
338}