codec.mjs
javascript · 22 lines · Exact bytes
Version & provenance · browser-local-cm7-v1
Recorded SHA-256 29544abff84c306d0c34535fedb1c3ec387f39a53d97a52b412ad7d6da60fe3bRendered SHA-256 29544abff84c306d0c34535fedb1c3ec387f39a53d97a52b412ad7d6da60fe3b
Apache-2.0 License notes. Line links are stable within this snapshot. CM-7 schema-2 state-input browser integration; FP32 selected update2232 checkpoint 29e68a8e85336cbb1f56efdad36bd76217728b6a376d1e5f74e89887d21383da. ONNX Runtime Web 1.24.3, chess.js 1.4.0. Exact integrated source; standard-game UI, fixed masked120-slot prompt,512 raw output classes. Three-ply browser helper is separate from live seven-ply search. Original UI and terminal PGN export preserved; prototype scorer/codec/worker/runner unchanged except adding PGN export utility.
1// CM-6/CM-7 state-v2: fixed slots, genuine recent moves, raw FEN EP target.
2export const square=s=>s.charCodeAt(0)-97+8*(Number(s[1])-1);
3export const triple=m=>[square(m.from),square(m.to),({n:65,b:66,r:67,q:68})[m.promotion]??64];
4export function prompt(board,historyPlies=16){
5 if(!Number.isInteger(historyPlies)||historyPlies<0||historyPlies>16)throw Error('History must be 0 to 16 plies');
6 const all=board.history({verbose:true}),moves=historyPlies?all.slice(-historyPlies):[];
7 const fen=board.fen({forceEnpassantSquare:true}).split(' ');
8 // chess.js discards non-capturable EP targets after double pushes. Recover the
9 // raw target from the actual last move, independent of optional model history.
10 const last=all.at(-1);let ep=fen[3];
11 if(last)ep=last.piece==='p'&&Math.abs(Number(last.from[1])-Number(last.to[1]))===2?last.from[0]+((Number(last.from[1])+Number(last.to[1]))/2):'-';
12 const missing=3*(16-moves.length),ids=[69,moves.length?376:375,...Array(missing).fill(71),...moves.flatMap(triple),377];
13 for(let rank=1;rank<=8;rank++)for(const file of 'abcdefgh'){
14 const p=board.get(file+rank);ids.push(128+(p?('pnbrqk'.indexOf(p.type)+1)+(p.color==='b'?6:0):0));
15 }
16 const castle=[['K',1],['Q',2],['k',4],['q',8]].reduce((v,[c,bit])=>v+(fen[2].includes(c)?bit:0),0),half=Number(fen[4]);
17 ids.push(board.turn()==='w'?141:142,143+castle,ep==='-'?159:160+square(ep),half>=150?374:224+half,378);
18 const mask=[1,1,...Array(missing).fill(0),...Array(118-missing).fill(1)];
19 if(ids.length!==120||mask.length!==120)throw Error('Invalid state prompt');
20 return {input_ids:ids,attention_mask:mask,position_ids:Array.from({length:120},(_,i)=>i)};
21}
22