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}