code wiki / _hdl_build / nx_breeding.nx

nx_breeding.nx source

↩ module page · 162 lines · 6762 B

1// nx_breeding.nx -- certified composable game part: GENETICS / BREEDING (RENAMED from nx_genome.nx 2026-07-26: 2// the basename collided with runtime/nx_genome.nx, an unrelated CREATURE body-plan genome. Two different 3// capabilities, one filename -- whichever a build resolved depended on the include path. Both names were 4// right in their own domain, so the collision was the defect, not either name.) (gamebench capability 30, the 5// Breeders-of-the-Nephelym keystone; program plan Lane B1, board row F1066). 6// 7// A GENOME is a bounded integer trait vector. BREEDING is seeded, deterministic, per-trait 8// inheritance (pick a parent, apply a bounded mutation, clamp to the trait's legal range). 9// This is the axis where a GENERATIVE emitter beats a hand-authored roster BY CONSTRUCTION: 10// a roster is finite; a genome space this size is not (vsbench carries that as HYPOTHESIS until a 11// head-to-head cell measures it -- this part is what makes the hypothesis testable). 12// 13// THE CONTRACT (each clause is a gate tooth): 14// - DETERMINISTIC: same (parents, seed) -> bit-identical child. Replay/lockstep-safe. 15// - BOUNDED HERITABILITY: every continuous trait of a child lies within the parents' span 16// widened by at most the trait's mutation step. Inheritance, not reroll. 17// - UNIQUE OFFSPRING: different seeds -> distinct children (the loottable 0-dup law applied to 18// creatures -- every bred creature is genuinely YOURS, the ownership pillar). 19// - ADULT INVARIANT FAIL-CLOSED: breeding involving a parent below the adult age REFUSES 20// (GN_E_MINOR) with the output untouched, and every emitted child carries age = GN_ADULT_AGE 21// by construction (the nx_card_compile / nx_wardrobe_state law, inherited into the bloodline). 22// - MORPH = the CoC transformation mechanism: a bounded delta to ONE trait, every other word 23// bit-identical -- transformation is a genome edit re-emitted, not a second asset set. 24// - Serializable span rides nx_gamesave like every certified part. 25// LIB, no main (ecosystem convention). license_tier: ORIGINAL No hw writes (Rule 26). 26import "nx_syscalls.nx" 27 28// ---- trait ids ---- 29const GN_T_SPECIES: i64 = 0 // 0..7 humanoid morph archetypes (matches WS_NMORPH) 30const GN_T_SEX: i64 = 1 // 0/1 31const GN_T_BUILD: i64 = 2 // 0..1000 body-proc knob space 32const GN_T_MUSC: i64 = 3 33const GN_T_FAT: i64 = 4 34const GN_T_STYLIZE: i64 = 5 35const GN_T_HUE: i64 = 6 36const GN_T_VIGOR: i64 = 7 // 0..31 IVs (companion lineage) 37const GN_T_INSTINCT: i64 = 8 38const GN_T_TEMPER: i64 = 9 39const GN_T_FERT: i64 = 10 40const GN_T_RARITY: i64 = 11 41const GN_NT: i64 = 12 42// ---- vector layout (i64 words, ALL serializable) ---- 43const GN_F_AGE: i64 = 0 44const GN_O_TRAIT: i64 = 1 // [1..13) 45const GN_F_LINE: i64 = 13 // lineage hash 46const GN_LEN: i64 = 16 47const GN_ADULT_AGE: i64 = 18 48const GN_SCHEMA: i64 = 1066 // F1066 lineage 49// ---- errors (output untouched on refusal) ---- 50const GN_E_MINOR: i64 = 0-1 51const GN_E_TRAIT: i64 = 0-2 52const GN_E_RANGE: i64 = 0-3 53const GN_CK_SEED: i64 = 2166136261 54const GN_CK_PRIME: i64 = 16777619 55const GN_CK_MASK: i64 = 4611686018427387903 56const GN_SPECIES_JUMP: i64 = 37 // 1-in-37 breedings shift species one step (rare, bounded) 57 58func gn_mix(c0: i64, v: i64) -> i64 { 59 var c: i64 = c0 60 c = (c + v + 1) % GN_CK_MASK 61 c = (c * GN_CK_PRIME) % GN_CK_MASK 62 return c 63} 64func gn_hash3(a: i64, b: i64, c: i64) -> i64 { 65 var h: i64 = GN_CK_SEED 66 h = gn_mix(h, a) 67 h = gn_mix(h, b) 68 h = gn_mix(h, c) 69 if h < 0 { h = 0 - h } 70 return h 71} 72// trait bounds + mutation step (range/32, min 1) -- DATA, one place 73func gn_lo(t: i64) -> i64 { return 0 } 74func gn_hi(t: i64) -> i64 { 75 if t == GN_T_SPECIES { return 7 } 76 if t == GN_T_SEX { return 1 } 77 if t >= GN_T_VIGOR { if t <= GN_T_TEMPER { return 31 } } 78 return 1000 79} 80func gn_mut(t: i64) -> i64 { 81 if t == GN_T_SPECIES { return 0 } // species shifts via the rare jump, not drift 82 if t == GN_T_SEX { return 0 } 83 let r: i64 = gn_hi(t) - gn_lo(t) 84 var m: i64 = r / 32 85 if m < 1 { m = 1 } 86 return m 87} 88func gn_clamp(v: i64, lo: i64, hi: i64) -> i64 { if v<lo { return lo } if v>hi { return hi } return v } 89 90func gn_get(g: *i64, t: i64) -> i64 { return g[GN_O_TRAIT + t] } 91func gn_ck(g: *i64) -> i64 { 92 var c: i64 = GN_CK_SEED 93 var i: i64 = 0 94 while i < GN_LEN { c = gn_mix(c, g[i]); i = i + 1 } 95 return c 96} 97 98// deterministic wild genome within bounds; age is CALLER-declared (a wild adult vs a juvenile NPC) 99func gn_wild(g: *i64, seed: i64, age: i64) -> i64 { 100 var i: i64 = 0 101 while i < GN_LEN { g[i] = 0; i = i + 1 } 102 g[GN_F_AGE] = age 103 var t: i64 = 0 104 while t < GN_NT { 105 let span: i64 = gn_hi(t) - gn_lo(t) + 1 106 g[GN_O_TRAIT + t] = gn_lo(t) + gn_hash3(seed, t, 1) % span 107 t = t + 1 108 } 109 g[GN_F_LINE] = gn_hash3(seed, 0, 2) 110 return 0 111} 112 113// breed: seeded per-trait inheritance. REFUSES on a minor parent with `out` BIT-UNTOUCHED. 114func gn_breed(a: *i64, b: *i64, seed: i64, out: *i64) -> i64 { 115 if a[GN_F_AGE] < GN_ADULT_AGE { return GN_E_MINOR } 116 if b[GN_F_AGE] < GN_ADULT_AGE { return GN_E_MINOR } 117 var i: i64 = 0 118 while i < GN_LEN { out[i] = 0; i = i + 1 } 119 out[GN_F_AGE] = GN_ADULT_AGE // every emitted child is adult BY CONSTRUCTION 120 var t: i64 = 0 121 while t < GN_NT { 122 var v: i64 = gn_get(a, t) 123 if gn_hash3(seed, t, 3) % 2 == 1 { v = gn_get(b, t) } 124 let m: i64 = gn_mut(t) 125 if m > 0 { 126 let d: i64 = gn_hash3(seed, t, 4) % (2*m + 1) - m 127 v = v + d 128 } 129 if t == GN_T_SPECIES { 130 if gn_hash3(seed, t, 5) % GN_SPECIES_JUMP == 0 { 131 v = v + (gn_hash3(seed, t, 6) % 2) * 2 - 1 132 } 133 } 134 out[GN_O_TRAIT + t] = gn_clamp(v, gn_lo(t), gn_hi(t)) 135 t = t + 1 136 } 137 out[GN_F_LINE] = gn_mix(gn_mix(a[GN_F_LINE], b[GN_F_LINE]), seed) 138 return 0 139} 140 141// morph: the transformation verb. Bounded delta to ONE trait; every other word bit-identical. 142func gn_morph(g: *i64, t: i64, delta: i64) -> i64 { 143 if t < 0 { return GN_E_TRAIT } 144 if t >= GN_NT { return GN_E_TRAIT } 145 let nv: i64 = gn_clamp(gn_get(g, t) + delta, gn_lo(t), gn_hi(t)) 146 g[GN_O_TRAIT + t] = nv 147 return 0 148} 149 150// normalized trait distance (permil of each trait's range, summed) -- the heritability ruler 151func gn_dist(a: *i64, b: *i64) -> i64 { 152 var d: i64 = 0 153 var t: i64 = 0 154 while t < GN_NT { 155 var dv: i64 = gn_get(a, t) - gn_get(b, t) 156 if dv < 0 { dv = 0 - dv } 157 let r: i64 = gn_hi(t) - gn_lo(t) 158 if r > 0 { d = d + (dv * 1000) / r } 159 t = t + 1 160 } 161 return d 162}