code wiki / _hdl_build / nx_game_genetics.nx
nx_game_genetics.nx
buildroot/runtime/_hdl_build/nx_game_genetics.nx
about
nx_game_genetics.nx -- REAL MENDELIAN GENETICS as the breeding core (ws=game-interact rung 3b;
operator: "use Mendelian genetics so we can really reuse systems, fun not overwhelming... educational
while entertaining, teach real world science").
THE SCIENCE (this is textbook genetics, implemented honestly -- not a "genetics-flavoured" rng):
* DIPLOID genome: every trait carries TWO alleles, one from each parent.
* MENDEL'S 1st LAW (SEGREGATION): a parent passes ONE randomly-chosen allele of its pair (a gamete).
* MENDEL'S 2nd LAW (INDEPENDENT ASSORTMENT): each trait segregates independently of the others.
* The famous emergent ratios are therefore NOT hardcoded -- they FALL OUT: monohybrid Aa x Aa gives
genotypes 1:2:1 and phenotypes 3:1; a dihybrid cross gives 9:3:3:1; a test cross gives 1:1.
The gate MEASURES them. That is the difference between teaching science and cosplaying it.
* Three real inheritance MODES, each the textbook exemplar:
SIMPLE dominant/recessive (pea plants; horned/hornless here)
INCOMPLETE blending heterozygote (snapdragon flower colour: red x white -> PINK, and F2 is
1:2:1 PHENOTYPES -- the fact that distinguishes it from simple dominance)
CODOM multiple alleles + codominance (human ABO blood groups: A and B both expressed -> AB)
* CARRIERS are real and visible-to-the-game: a heterozygote showing the dominant phenotype still
carries the recessive allele -- the whole reason selective breeding is interesting.
FUN, NOT OVERWHELMING (the design constraint): FIVE visible traits, each with an obvious readable
phenotype. The player never sees a genotype string unless they ask; the Punnett square (gx_punnett)
is the ONE teaching widget -- 4 cells, the real thing, computed not illustrated.
Genome packs into ONE i64: trait t occupies 4 bits (two 2-bit alleles) => 5 traits = 20 bits, and it
rides the existing companion component word, so nothing else in the parts library changes shape.
All integer, deterministic. LIB, no main. license_tier: ORIGINAL
dependencies 1 imports · 4 importers
imports: nx_syscalls.nx
imported by: nx_char_identity.nxnx_game_breed.nxnx_game_genetics_gate.nxnx_game_taming.nx
structs
| none |
consts
| 30 | const GX_NTRAIT: i64 = 5 |
| 31 | const GX_HORN: i64 = 0 // SIMPLE H dominant (horned) / h recessive (hornless) |
| 32 | const GX_WING: i64 = 1 // SIMPLE W dominant (wingless) / w recessive (winged -- rare, prized) |
| 33 | const GX_COAT: i64 = 2 // INCOMPLETE crimson / rose (blend) / white |
| 34 | const GX_ELEM: i64 = 3 // CODOM ABO-style: A, B codominant, O recessive |
| 35 | const GX_TAIL: i64 = 4 // SIMPLE T dominant (long) / t recessive (short) |
| 37 | const GX_SIMPLE: i64 = 0 |
| 38 | const GX_INCOMPLETE: i64 = 1 |
| 39 | const GX_CODOM: i64 = 2 |
| 259 | const GX_SEX_F: i64 = 0 |
| 260 | const GX_SEX_M: i64 = 1 |
| 302 | const GX_LINK_A: i64 = 0 // = GX_HORN |
| 303 | const GX_LINK_B: i64 = 4 // = GX_TAIL |
| 304 | const GX_LINK_CM: i64 = 120 // recombination frequency in per-mille (120 = 12 cM) |
| 348 | const GX_POLY_N: i64 = 4 |
| 396 | const GX_EPI_FADE: i64 = 1 |
| 445 | const GX_MUT_PERMIL: i64 = 8 |
| 462 | const GX_REC: i64 = 4 |
functions
| 41 | func gx_mode(t: i64) -> i64 |
| 48 | func gx_a0(g: i64, t: i64) -> i64 { return (g >> (t*4)) & 3 } |
| 49 | func gx_a1(g: i64, t: i64) -> i64 { return (g >> (t*4 + 2)) & 3 } |
| 50 | func gx_set(g: i64, t: i64, a: i64, b: i64) -> i64 |
| 58 | func gx_homozygous(g: i64, t: i64) -> i64 { if gx_a0(g, t) == gx_a1(g, t) { return 1 } return 0 } |
| 59 | func gx_heterozygous(g: i64, t: i64) -> i64 { if gx_a0(g, t) != gx_a1(g, t) { return 1 } return 0 } |
| 65 | func gx_phenotype(g: i64, t: i64) -> i64 |
| 91 | func gx_carrier(g: i64, t: i64) -> i64 |
| 98 | func gx_trait_name(t: i64) -> *u8 |
| 105 | func gx_mode_name(t: i64) -> *u8 calls 1: gx_mode |
| 111 | func gx_pheno_name(t: i64, ph: i64) -> *u8 |
| 129 | func gx_allele_char(t: i64, a: i64) -> *u8 |
| 146 | func gx_rng(s: *i64) -> i64 |
| 155 | func gx_gamete(g: i64, t: i64, s: *i64) -> i64 |
| 161 | func gx_cross(gA: i64, gB: i64, s: *i64) -> i64 |
| 177 | func gx_punnett(gA: i64, gB: i64, t: i64, out: *i64) -> i64 |
| 206 | func gx_odds_permil(gA: i64, gB: i64, t: i64, ph: i64) -> i64 |
| 217 | func gx_founder(seed: i64) -> i64 |
| 236 | func gx_rarity_permil(g: i64) -> i64 calls 1: gx_phenotype |
| 263 | func gx_sex(sg: i64) -> i64 { return sg & 1 } |
| 264 | func gx_z0(sg: i64) -> i64 { return (sg >> 1) & 3 } |
| 265 | func gx_z1(sg: i64) -> i64 { return (sg >> 3) & 3 } |
| 266 | func gx_sexgene(sex: i64, z0: i64, z1: i64) -> i64 { return (sex & 1) | ((z0 & 3) << 1) | ((z1 & 3) << 3) } |
| 268 | func gx_z_phenotype(sg: i64) -> i64 |
| 279 | func gx_z_carrier(sg: i64) -> i64 |
| 285 | func gx_cross_sex(sgMother: i64, sgFather: i64, s: *i64) -> i64 |
| 306 | func gx_gamete_linked(g: i64, s: *i64, out: *i64) -> i64 |
| 324 | func gx_cross_linked(gA: i64, gB: i64, s: *i64, info: *i64) -> i64 |
| 349 | func gx_poly_dose(pg: i64) -> i64 |
| 355 | func gx_poly_gamete(pg: i64, s: *i64) -> i64 |
| 366 | func gx_poly_cross(pgA: i64, pgB: i64, s: *i64) -> i64 |
| 378 | func gx_size_name(dose: i64) -> *u8 |
| 397 | func gx_epi_marked(eg: i64, t: i64) -> i64 { return (eg >> t) & 1 } |
| 398 | func gx_epi_strength(eg: i64, t: i64) -> i64 { return (eg >> (8 + t*3)) & 7 } |
| 399 | func gx_epi_set(eg: i64, t: i64, strength: i64) -> i64 |
| 412 | func gx_epi_imprint(eg: i64, t: i64, env_intensity: i64) -> i64 |
| 416 | func gx_expressed(g: i64, eg: i64, t: i64) -> i64 |
| 427 | func gx_epi_inherit(egA: i64, egB: i64) -> i64 |
| 446 | func gx_mutate(g: i64, s: *i64, out: *i64) -> i64 |
| 463 | func gx_breed_modern(pA: *i64, pB: *i64, s: *i64, child: *i64, info: *i64) -> i64 called by 1: brd_breed_info calls 7: gx_sexsys_mmapgx_cross_linkedgx_mutategx_cross_sexgx_poly_cross+1 |