code wiki / _hdl_build / nx_char_ai_gate.nx
nx_char_ai_gate.nx source
↩ module page · 65 lines · 3651 B
1// nx_char_ai_gate.nx -- proves G-R2 char-AI (behavior tree + FSM). NPC BT (priority selector):
2// SEL[ SEQ[COND health_low, ACT flee], SEQ[COND enemy_visible, ACT attack], ACT patrol ]
3// blackboard bits: 0=health_low, 1=enemy_visible. actions: flee=1, attack=2, patrol=3.
4// FSM: IDLE--see-->ATTACK--health_low-->FLEE--healed-->IDLE (no other transitions). GREEN only if every
5// decision + transition is correct, incl. priority and neg-controls. license_tier: ORIGINAL expect_exit: 0
6import "nx_syscalls.nx"
7import "nx_char_ai.nx"
8
9func cw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
10func cn(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1} sys_write(1,bb,k); return 0 }
11
12func bt_action(ty: *i64, a0: *i64, nk: *i64, kids: *i64, bb: i64) -> i64 {
13 let ao: *i64 = sys_mmap(8) as *i64
14 ao[0] = -1
15 bt_tick(ty, a0, nk, kids, 0, bb, ao)
16 return ao[0]
17}
18
19func main() -> i64 {
20 // ---- behavior tree (8 nodes) ----
21 let ty: *i64 = sys_mmap(8 * 8) as *i64
22 let a0: *i64 = sys_mmap(8 * 8) as *i64
23 let nk: *i64 = sys_mmap(8 * 8) as *i64
24 let kids: *i64 = sys_mmap(8 * 32) as *i64
25 var i: i64 = 0
26 while i < 32 { kids[i] = -1; i = i + 1 }
27 // node 0 SEL(flee-seq, attack-seq, patrol); 1 SEQ(cond hp, act flee); 2 COND hp; 3 ACT flee;
28 // 4 SEQ(cond vis, act atk); 5 COND vis; 6 ACT atk; 7 ACT patrol
29 ty[0]=NT_SEL; nk[0]=3; kids[0]=1; kids[1]=4; kids[2]=7
30 ty[1]=NT_SEQ; nk[1]=2; kids[4]=2; kids[5]=3
31 ty[2]=NT_COND; a0[2]=0
32 ty[3]=NT_ACT; a0[3]=1
33 ty[4]=NT_SEQ; nk[4]=2; kids[16]=5; kids[17]=6
34 ty[5]=NT_COND; a0[5]=1
35 ty[6]=NT_ACT; a0[6]=2
36 ty[7]=NT_ACT; a0[7]=3
37
38 var pass: i64 = 0
39 var total: i64 = 0
40
41 total=total+1; if bt_action(ty,a0,nk,kids, 1)==1 { pass=pass+1 } else { cw("BT1 FAIL health_low!=flee got "); cn(bt_action(ty,a0,nk,kids,1)); cw("\n") } // health_low -> flee
42 total=total+1; if bt_action(ty,a0,nk,kids, 2)==2 { pass=pass+1 } else { cw("BT2 FAIL enemy!=attack\n") } // enemy_visible -> attack
43 total=total+1; if bt_action(ty,a0,nk,kids, 3)==1 { pass=pass+1 } else { cw("BT3 FAIL priority (both)!=flee\n") } // both -> flee (priority)
44 total=total+1; if bt_action(ty,a0,nk,kids, 0)==3 { pass=pass+1 } else { cw("BT4 FAIL none!=patrol\n") } // nothing -> patrol
45
46 // ---- FSM (3 states x 4 events) ----
47 // states IDLE=0 ATTACK=1 FLEE=2 ; events SEE=0 LOSE=1 HPLOW=2 HEALED=3
48 let trans: *i64 = sys_mmap(8 * 12) as *i64
49 var j: i64 = 0
50 while j < 12 { trans[j] = -1; j = j + 1 }
51 trans[0*4 + 0] = 1 // IDLE + SEE -> ATTACK
52 trans[1*4 + 1] = 0 // ATTACK + LOSE -> IDLE
53 trans[1*4 + 2] = 2 // ATTACK + HPLOW -> FLEE
54 trans[2*4 + 3] = 0 // FLEE + HEALED -> IDLE
55
56 total=total+1; if fsm_step(trans,4, 0,0)==1 { pass=pass+1 } else { cw("FSM1 FAIL idle+see!=attack\n") }
57 total=total+1; if fsm_step(trans,4, 1,2)==2 { pass=pass+1 } else { cw("FSM2 FAIL attack+hplow!=flee\n") }
58 total=total+1; if fsm_step(trans,4, 2,3)==0 { pass=pass+1 } else { cw("FSM3 FAIL flee+healed!=idle\n") }
59 total=total+1; if fsm_step(trans,4, 0,1)==0 { pass=pass+1 } else { cw("FSM4 FAIL idle+lose should STAY idle\n") } // NEG-CONTROL: no transition
60
61 cw("CHAR-AI "); cn(pass); cw("/"); cn(total); cw("\n")
62 if pass == total { cw("CHAR-AI ALL-PASS (BT priority decisions + FSM transitions + neg-control)\n"); sys_exit(0) }
63 sys_exit(1)
64 return 1
65}