nx_erotica_craft_lib.nx source
↩ module page · 150 lines · 7796 B
1// nx_erotica_craft_lib.nx -- the erotica craft SCORER as a shared lib (no main; Rule 15) so BOTH the gate
2// (nx_erotica_craft) and the autonomous loop (nx_erotica_loop) score off ONE impl. Reads the rubric + lexicons
3// from the sovereign seg_store via ss_open/ss_hget (idiomatic). ec_eval fills the per-axis scores into out[0..7]
4// and returns the weighted composite permil; callers decide KEEP/REVISE + build directives. NO 3rd-party.
5// out layout: [0]=emotion_ratio [1]=sensory [2]=displacement [3]=tension [4]=pacing [5]=afterglow [6]=consent [7]=slop_penalty
6// license_tier: ORIGINAL module: nishi-core.erotica.craft_lib
7import "nx_syscalls.nx"
8import "nx_seg_store.nx"
9const K_MAGIC_1000000: i64 = 1000000
10
11func ec_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
12func ec_lc(c: i64) -> i64 { if c>=65 { if c<=90 { return c+32 } } return c }
13func ec_count_term(text: *u8, tlen: i64, term: *u8, termlen: i64) -> i64 {
14 if termlen<=0 { return 0 }
15 var cnt: i64=0; var i: i64=0
16 while i+termlen<=tlen {
17 var j: i64=0; var hit: i64=1
18 while j<termlen { if ec_lc(text[i+j] as i64) != ec_lc(term[j] as i64) { hit=0; j=termlen } else { j=j+1 } }
19 if hit==1 { cnt=cnt+1; i=i+termlen } else { i=i+1 }
20 }
21 return cnt
22}
23func ec_list_hits(text: *u8, tlen: i64, buf: *u8, n: i64) -> i64 {
24 if (buf as i64)==0 { return 0 }
25 var total: i64=0; var i: i64=0
26 while i<n {
27 let ls: i64=i
28 var e: i64=ls; var go: i64=1
29 while go==1 { if e>=n { go=0 } else { if buf[e]==(10 as u8) { go=0 } else { e=e+1 } } }
30 if e>ls { if buf[ls]!=(35 as u8) {
31 var ts: i64=ls; var k: i64=ls
32 while k<e { if buf[k]==(58 as u8) { ts=k+1 } k=k+1 }
33 var termlen: i64=e-ts
34 if termlen>0 { if buf[ts+termlen-1]==(13 as u8) { termlen=termlen-1 } }
35 if termlen>0 { total = total + ec_count_term(text, tlen, ((buf as i64)+ts) as *u8, termlen) }
36 } }
37 i=e+1
38 }
39 return total
40}
41func ec_store_hits(text: *u8, tlen: i64, h: *i64, key: *u8) -> i64 {
42 let pq: *i64 = sys_mmap(16) as *i64
43 let lq: *i64 = sys_mmap(16) as *i64
44 if ss_hget(h, key, pq, lq) != 1 { return 0 }
45 return ec_list_hits(text, tlen, pq[0] as *u8, lq[0])
46}
47func ec_words(text: *u8, tlen: i64) -> i64 {
48 var w: i64=0; var inw: i64=0; var i: i64=0
49 while i<tlen { let c: i64=text[i] as i64
50 if c==32 { inw=0 } else { if c==10 { inw=0 } else { if c==9 { inw=0 } else { if inw==0 { w=w+1; inw=1 } } } }
51 i=i+1 }
52 return w
53}
54func ec_sent_spread(text: *u8, tlen: i64) -> i64 {
55 var maxw: i64=0; var minw: i64=K_MAGIC_1000000; var cur: i64=0; var inw: i64=0; var sents: i64=0; var i: i64=0
56 while i<tlen {
57 let c: i64=text[i] as i64
58 var term: i64=0
59 if c==46 { term=1 } else { if c==33 { term=1 } else { if c==63 { term=1 } } }
60 if term==1 { if cur>0 { if cur>maxw { maxw=cur } if cur<minw { minw=cur } sents=sents+1; cur=0 } inw=0 }
61 else { if c==32 { inw=0 } else { if c==10 { inw=0 } else { if c==9 { inw=0 } else { if inw==0 { cur=cur+1; inw=1 } } } } }
62 i=i+1
63 }
64 if cur>0 { if cur>maxw { maxw=cur } if cur<minw { minw=cur } sents=sents+1 }
65 if sents<2 { return 0 }
66 var sc: i64=(maxw-minw)*70; if sc>1000 { sc=1000 }
67 return sc
68}
69func ec_weight(buf: *u8, n: i64, axis: *u8, axislen: i64) -> i64 {
70 var i: i64=0
71 while i<n {
72 let ls: i64=i
73 var mt: i64=1; var j: i64=0
74 while j<axislen { if (ls+j)>=n { mt=0; j=axislen } else { if buf[ls+j]!=axis[j] { mt=0; j=axislen } else { j=j+1 } } }
75 if mt==1 { if (ls+axislen)<n { if buf[ls+axislen]==(9 as u8) {
76 var k: i64=ls+axislen+1; var v: i64=0; var go: i64=1
77 while go==1 { if k>=n { go=0 } else { let c: i64=buf[k] as i64; if c>=48 { if c<=57 { v=v*10+(c-48); k=k+1 } else { go=0 } } else { go=0 } } }
78 return v
79 } } }
80 var e: i64=ls; var g2: i64=1
81 while g2==1 { if e>=n { g2=0 } else { if buf[e]==(10 as u8) { g2=0 } else { e=e+1 } } }
82 i=e+1
83 }
84 return 0
85}
86
87// escalation-arc (R3): does the scene BUILD -- anticipation (early third) -> action (middle) -> afterglow (late)?
88func ec_arc(text: *u8, h: *i64) -> i64 {
89 let tlen: i64 = ec_slen(text)
90 let t1: i64 = tlen/3; let t2: i64 = (tlen*2)/3
91 let ant_early: i64 = ec_store_hits(text, t1, h, "lex:anticipation" as *u8)
92 let act_mid: i64 = ec_store_hits(((text as i64)+t1) as *u8, t2-t1, h, "lex:physical" as *u8)
93 let aft_late: i64 = ec_store_hits(((text as i64)+t2) as *u8, tlen-t2, h, "lex:afterglow" as *u8)
94 var arc: i64 = 0
95 if ant_early>0 { arc = arc + 350 }
96 if act_mid>0 { arc = arc + 300 }
97 if aft_late>0 { arc = arc + 350 }
98 return arc
99}
100// score `text` against the store `h`; fill out[0..8] axis scores; return the weighted composite permil
101func ec_eval(text: *u8, h: *i64, out: *i64) -> i64 {
102 let tlen: i64 = ec_slen(text)
103 var words: i64 = ec_words(text, tlen); if words<1 { words=1 }
104 let emo: i64 = ec_store_hits(text, tlen, h, "lex:emotion" as *u8)
105 let phys: i64 = ec_store_hits(text, tlen, h, "lex:physical" as *u8)
106 let sens: i64 = ec_store_hits(text, tlen, h, "lex:sensory" as *u8)
107 let slop: i64 = ec_store_hits(text, tlen, h, "lex:slop" as *u8)
108 let cons: i64 = ec_store_hits(text, tlen, h, "lex:consent" as *u8)
109 let third: i64 = (tlen*2)/3
110 let after: i64 = ec_store_hits(((text as i64)+third) as *u8, tlen-third, h, "lex:afterglow" as *u8)
111 let disp: i64 = ec_store_hits(text, tlen, h, "lex:displacement" as *u8)
112 let antic: i64 = ec_store_hits(text, tlen, h, "lex:anticipation" as *u8)
113
114 let emotion_ratio: i64 = (emo*1000)/(emo+phys+1)
115 let sdens: i64 = (sens*1000)/words
116 var sens_score: i64 = 1000
117 if sdens<20 { sens_score = sdens*50 }
118 if sdens>160 { sens_score = 1000-((sdens-160)*4); if sens_score<0 { sens_score=0 } }
119 let slop_dens: i64 = (slop*1000)/words
120 var slop_pen: i64 = slop_dens*4; if slop_pen>1000 { slop_pen=1000 }
121 var afterglow: i64 = 0; if after>0 { afterglow=1000 }
122 var consent: i64 = 0; if cons>0 { consent=1000 }
123 let pacing: i64 = ec_sent_spread(text, tlen)
124 var disp_score: i64 = disp*500; if disp_score>1000 { disp_score=1000 }
125 var tension: i64 = antic*250; if tension>1000 { tension=1000 }
126 let arc: i64 = ec_arc(text, h)
127
128 out[0]=emotion_ratio; out[1]=sens_score; out[2]=disp_score; out[3]=tension
129 out[4]=pacing; out[5]=afterglow; out[6]=consent; out[7]=slop_pen; out[8]=arc
130
131 let rpq: *i64 = sys_mmap(16) as *i64
132 let rlq: *i64 = sys_mmap(16) as *i64
133 ss_hget(h, "rubric" as *u8, rpq, rlq)
134 let rub: *u8 = rpq[0] as *u8
135 let rn: i64 = rlq[0]
136 let w_emo: i64 = ec_weight(rub, rn, "emotion_ratio" as *u8, 13)
137 let w_sens: i64 = ec_weight(rub, rn, "sensory_density" as *u8, 15)
138 let w_pace: i64 = ec_weight(rub, rn, "pacing_sentence_var" as *u8, 19)
139 let w_after: i64 = ec_weight(rub, rn, "afterglow_presence" as *u8, 18)
140 let w_consent: i64 = ec_weight(rub, rn, "consent_presence" as *u8, 16)
141 let w_slop: i64 = ec_weight(rub, rn, "slop_density" as *u8, 12)
142 let w_disp: i64 = ec_weight(rub, rn, "sensory_displacement" as *u8, 19)
143 let w_tension: i64 = ec_weight(rub, rn, "tension_curve" as *u8, 13)
144 let w_arc: i64 = ec_weight(rub, rn, "escalation_arc" as *u8, 14)
145 var wsum: i64 = w_emo+w_sens+w_pace+w_after+w_consent+w_disp+w_tension+w_arc; if wsum<1 { wsum=1 }
146 var composite: i64 = (emotion_ratio*w_emo + sens_score*w_sens + pacing*w_pace + afterglow*w_after + consent*w_consent + disp_score*w_disp + tension*w_tension + arc*w_arc)/wsum
147 composite = composite - (slop_pen*w_slop)/wsum
148 if composite<0 { composite=0 }
149 return composite
150}