nx_beach_pose_pair_gate_t123.nx source
↩ module page · 145 lines · 8453 B
1// Private qualification of the existing native facing owner.
2import "_hdl_build/nx_wasm_craft_residency_t44.nx"
3import "nx_gate_verdict.nx"
4import "nx_game_page_artifact_lib.nx"
5import "nx_game_pair_layout_lib.nx"
6import "nx_wasm_layout_read_lib.nx"
7func facing_legacy_step(hdg: i64, dx: i64, dz: i64) -> i64 {
8 var ax: i64 = dx
9 if ax < 0 { ax = 0 - ax }
10 var az: i64 = dz
11 if az < 0 { az = 0 - az }
12 if ax + az == 0 { return hdg } // no intent, no turn: she is standing
13 let mag: i64 = sd_isqrt(dx*dx + dz*dz)
14 if mag <= 0 { return hdg }
15 let fx: i64 = it_sin4096(hdg % (2*IT_PI))
16 let fz: i64 = it_cos4096(hdg % (2*IT_PI))
17 // cross and dot of forward (fx4096, unit) with the desired step (q8, magnitude mag)
18 // ⚠NOT PRE-DIVIDED BY 4096. Dividing here first would floor cr to single digits at a mob's
19 // 4-7 q8 step and quantise the whole controller into a handful of levels -- which is the
20 // stutter this function exists to remove, reintroduced inside the fix. Both products stay in
21 // 4096*q8 units and the one division happens at the end, against mag*4096.
22 let cr: i64 = fx*dz - fz*dx // 4096 * mag * sin(error)
23 let dt: i64 = fx*dx + fz*dz // 4096 * mag * cos(error)
24 // quarter turn per stride, pro-rated by the ground this tick actually covers
25 let mx: i64 = mag*WC_TURN_PER_STRIDE/WC_STRIDE_Q8
26 // SIGN, AND IT WAS WRONG FIRST TIME. The (x,z) cross product fx*dz - fz*dx measures rotation
27 // from +x toward +z, and this engine yaw runs the OTHER way round: forward is (sin yaw,
28 // cos yaw), so increasing yaw turns from +z toward +x. The cross therefore carries
29 // -sin(error), not +sin(error), and the correction is its NEGATION.
30 // Settled against a case with an unambiguous answer rather than by staring at it: facing +z
31 // (yaw 0) with the target at +x plainly needs yaw to INCREASE, and there the cross comes out
32 // NEGATIVE -- so the turn is -cr.
33 // WHAT THE WRONG SIGN DID, because it is not the failure anyone would predict: it does not
34 // wobble or overshoot, it makes facing-directly-AWAY-from-the-target a stable point, so she
35 // walks backwards away from where she is going and looks perfectly calm doing it. Gate tooth
36 // T82 caught it as a 2-cycle that never converged out of a half-turn reversal.
37 var st: i64 = 0 - mx*cr/(mag*WATER_MAGIC_4096) // = mx*sin(error): proportional, saturating
38 if dt < 0 { // behind her: no proportional term is valid
39 st = mx
40 if cr > 0 { st = 0 - mx }
41 }
42 // THE INTEGER TAIL, and it is the FLOPPY failure mode arriving through rounding rather than
43 // through a bad gain. The proportional term is mx*sin(error), so once sin(error) falls below
44 // 1/mx it truncates to ZERO and she stops turning while still misaligned -- at the derived
45 // allowance that floor sits near 0.84 degrees, so she would sit permanently just off her own
46 // direction of travel and never arrive. Taking ONE UNIT instead is the smallest turn this
47 // representation can express, so it is the smallest possible repair and needs no constant of
48 // its own. Both guards require a nonzero cross product, so a girl who IS aligned still turns
49 // by nothing at all.
50 // ⚠STATED IMPRECISION: this leaves a one-unit limit cycle about the exact heading, which is
51 // 0.014 degrees and bounded. It is preferred to the alternative, which is a permanent and
52 // UNBOUNDED offset -- a bounded jitter below the angular resolution of the rig beats a
53 // static error you can see.
54 if st == 0 { if cr > 0 { st = 0 - 1 } }
55 if st == 0 { if cr < 0 { st = 1 } }
56 if st > mx { st = mx }
57 if st < 0 - mx { st = 0 - mx }
58 var nh: i64 = hdg + st
59 if nh < 0 { nh = nh + 2*IT_PI }
60 if nh >= 2*IT_PI { nh = nh - 2*IT_PI }
61 return nh
62}
63
64func main() -> i64 {
65 let c: *i64=gv_ctr()
66 gv_head("BEACH-POSE-PAIR-T123" as *u8)
67 var equivalent: i64=1
68 var samples: i64=0
69 var angle: i64=0
70 while angle<2*IT_PI {
71 var dx: i64=0-6
72 while dx<=6 {
73 var dz: i64=0-6
74 while dz<=6 {
75 if wc_hdg_step(angle,dx,dz)!=facing_legacy_step(angle,dx,dz) { equivalent=0 }
76 samples=samples+1;dz=dz+1
77 }
78 dx=dx+1
79 }
80 angle=angle+127
81 }
82 gv_check("movement controller preserves old compiled arithmetic across heading/intention matrix" as *u8,equivalent==1&&samples>0,c)
83 gv_check("positive X intent rotates positive from forward" as *u8,wc_hdg_step(0,4,0)>0,c)
84 gv_check("zero intent preserves heading" as *u8,wc_hdg_step(700,0,0)==700,c)
85 gv_check("stationary social target turns toward player" as *u8,wc_facing_step(0,0,0,400,0,819,205)>0,c)
86 gv_check("stationary outside social radius holds heading" as *u8,wc_facing_step(700,0,0,900,0,819,205)==700,c)
87 gv_check("coincident social position preserves heading" as *u8,wc_facing_step(700,0,0,0,0,819,205)==700,c)
88 gv_check("locomotion wins over conflicting social target" as *u8,wc_facing_step(700,4,0,0-400,0,819,205)==wc_hdg_step(700,4,0),c)
89 gv_check("behind target remains bounded" as *u8,wc_facing_step(0,0,0,0,0-400,819,205)==205,c)
90 let arena: i64=sys_mmap(CRAFT_EXT_TOTAL) as i64
91 let state: *i64=wst(arena)
92 gv_check("explicit facing policy admitted" as *u8,wc_set_facing_policy(arena,819,205)==0&&state[S_FACE_RADIUS]==819&&state[S_FACE_GAIN]==205,c)
93 gv_check("invalid policy leaves admitted state unchanged" as *u8,wc_set_facing_policy(arena,0,205)==0-1&&state[S_FACE_RADIUS]==819&&state[S_FACE_GAIN]==205,c)
94 let hp: *i64=(arena+O_MOBHDG) as *i64
95 hp[0]=700
96 var reads: i64=0
97 var stable: i64=1
98 while reads<144 {
99 if wc_hdg_of(arena,0)!=700 {stable=0}
100 reads=reads+1
101 }
102 gv_check("render heading reads cannot advance native state" as *u8,stable==1&&hp[0]==700,c)
103 sys_munmap(arena as *u8,CRAFT_EXT_TOTAL)
104 let length: *i64=sys_mmap(16) as *i64
105 let plain: *u8=sys_read_file("/tmp/beach-pose-t123.wasm" as *u8,length)
106 let pn: i64=length[0]
107 let twin: *u8=sys_read_file("/tmp/beach-pose-shared-t123.wasm" as *u8,length)
108 let tn: i64=length[0]
109 let plain_wat:*u8=sys_read_file("/tmp/beach-pose-t123.wat" as *u8,length)
110 let pwn:i64=length[0]
111 let shared_wat:*u8=sys_read_file("/tmp/beach-pose-shared-t123.wat" as *u8,length)
112 let swn:i64=length[0]
113 gv_check("actual compiler WAT artifacts read" as *u8,pwn>0&&swn>0,c)
114 if pwn<=0||swn<=0 {return 3}
115 let pr:*u8=sys_mmap(pwn)
116 let sr:*u8=sys_mmap(swn)
117 let rn:i64=wlv_wat(plain_wat,pwn,pr,pwn,0)
118 let sn:i64=wlv_wat(shared_wat,swn,sr,swn,1)
119 gv_check("compiler attached plain and shared layout records decode" as *u8,rn>0&&sn>0,c)
120 gv_check("unterminated WAT evidence refused" as *u8,wlv_wat(plain_wat,pwn-1,pr,pwn,0)==0,c)
121 gv_check("short record destination refused" as *u8,wlv_wat(plain_wat,pwn,pr,WLV_HEADER-1,0)==0,c)
122 gv_check("compiled pair matches existing layout-aware compiler-extension owner" as *u8,pn>0&&tn>0&&rn>0&&sn>0&&gpl_pair(plain,pn,twin,tn,pr,rn,sr,sn)==1,c)
123 if rn>0&&sn>0 {
124 gv_check("truncated layout record refused" as *u8,gpl_pair(plain,pn,twin,tn,pr,rn-1,sr,sn)==0,c)
125 gv_check("plain record cannot stand in for shared reservation" as *u8,gpl_pair(plain,pn,twin,tn,pr,rn,pr,rn)==0,c)
126 let before:u8=sr[40]
127 sr[40]=((before as i64)^1) as u8
128 gv_check("altered shared initializer reservation refused" as *u8,gpl_pair(plain,pn,twin,tn,pr,rn,sr,sn)==0,c)
129 sr[40]=before
130 gv_check("restored original records requalify exact pair" as *u8,gpl_pair(plain,pn,twin,tn,pr,rn,sr,sn)==1,c)
131 let wh:*u8=sys_mmap(65)
132 gpa_sha(plain_wat,pwn,wh);fsx_puts("plain_wat_sha256=");fsx_puts(wh);fsx_puts(" bytes=");fsx_putn(pwn);fsx_puts("\n")
133 gpa_sha(shared_wat,swn,wh);fsx_puts("shared_wat_sha256=");fsx_puts(wh);fsx_puts(" bytes=");fsx_putn(swn);fsx_puts("\n")
134 gpa_sha(pr,rn,wh);fsx_puts("plain_layout_sha256=");fsx_puts(wh);fsx_puts(" bytes=");fsx_putn(rn);fsx_puts("\n")
135 gpa_sha(sr,sn,wh);fsx_puts("shared_layout_sha256=");fsx_puts(wh);fsx_puts(" bytes=");fsx_putn(sn);fsx_puts("\n")
136 }
137 if pn>0&&tn>0 {
138 let ph: *u8=sys_mmap(65)
139 let th: *u8=sys_mmap(65)
140 gpa_sha(plain,pn,ph);gpa_sha(twin,tn,th)
141 fsx_puts("plain_sha256=");fsx_puts(ph);fsx_puts(" bytes=");fsx_putn(pn);fsx_puts("\n")
142 fsx_puts("shared_sha256=");fsx_puts(th);fsx_puts(" bytes=");fsx_putn(tn);fsx_puts("\n")
143 }
144 return gv_verdict("BEACH-POSE-PAIR-T123" as *u8,c,"Native control qualification; served motion acceptance pending" as *u8)
145}