codec.py
python · 108 lines · Sanitized derivative
Sanitized derivative: private paths or personal test identities use explicit placeholders. Original line count is preserved.
Version & provenance · state-v2-cm7
Recorded SHA-256 1ba2dc4ab0f0028b1726c8adb15e650e6ea1ef87c4ece40d59de7ba81b91e856Rendered SHA-256 e830e250ce661b6e4eec96046d2bfd420fbe824ff7d51e2361fc256fa3b2d7fc
Apache-2.0 original project code; dependencies retain their own licenses. License notes. Line links are stable within this snapshot. CM-7 completed implementation source; original and public rendered hashes recorded. Host-specific paths use /work placeholders; inspect reproduction instructions before running. Separate Rust helper retains its GPL license.
1"""Versioned standard-chess state prompt; shared by preparation and inference."""
2import hashlib,importlib.util,sys
3from pathlib import Path
4if importlib.util.find_spec('chess') is None:
5 p=Path('/work/.cache/pypoetry/virtualenvs/rulebound-LLUAbKSL-py3.11/lib/python3.11/site-packages/chess')
6 s=importlib.util.spec_from_file_location('chess',p/'__init__.py',submodule_search_locations=[str(p)])
7 m=importlib.util.module_from_spec(s);sys.modules['chess']=m;s.loader.exec_module(m)
8import chess
9
10VERSION='chess-state-history16-v2'
11BOS,EOS,PAD=69,70,71 # Legacy meanings/IDs retained; EOS is never emitted here.
12PIECE_BASE=128 # empty, white P/N/B/R/Q/K, black P/N/B/R/Q/K
13SIDE_BASE=141;CASTLE_BASE=143;EP_NONE=159;EP_BASE=160
14HALF_BASE=224;HALF_GE150=374;HIST_NONE=375;HIST_PARTIAL=376;STATE=377;NEXT=378
15VOCAB=512;HISTORY=16;PROMPT=120;INPUT=122;TARGET_POSITIONS=(119,120,121)
16PROMOTION={None:64,chess.KNIGHT:65,chess.BISHOP:66,chess.ROOK:67,chess.QUEEN:68}
17REVERSE={v:k for k,v in PROMOTION.items()}
18CONTRACT={'version':VERSION,'vocab':VOCAB,'prompt_positions':PROMPT,'model_positions':INPUT,
19 'serialized_positions':123,'target_positions':TARGET_POSITIONS,'history_plies':HISTORY,
20 'board_order':'a1..h8','ep':'raw FEN target, including non-capturable target',
21 'halfmove':'exact0..149; GE150 terminal range','fullmove':'metadata only',
22 'history':'genuine suffix of authoritative move stack; left PAD keys masked; fixed position IDs',
23 'legacy_reserved':'72..127 remain reserved','new_used':'128..378','remaining_reserved':'379..511',
24 'loss':'three move targets only; no EOS or prefix reconstruction'}
25
26def check_board(board):
27 if type(board) is not chess.Board or board.chess960 or not board.is_valid():raise ValueError('valid standard chess.Board required')
28 if type(board.halfmove_clock) is not int or board.halfmove_clock<0 or type(board.fullmove_number) is not int or board.fullmove_number<1:raise ValueError('invalid clock metadata')
29
30def triple(move):
31 if not move or move.from_square == move.to_square or move.drop or move.promotion not in PROMOTION:raise ValueError('null/drop/unsupported move')
32 return [move.from_square,move.to_square,PROMOTION[move.promotion]]
33
34def decode(values):
35 if len(values)!=3 or any(type(x) is not int for x in values) or not all(0<=x<64 for x in values[:2]) or values[2] not in REVERSE:raise ValueError('invalid move triple')
36 move=chess.Move(values[0],values[1],promotion=REVERSE[values[2]])
37 if not move or move.from_square == move.to_square:raise ValueError('null/equal-square move')
38 return move
39
40def castle(board):
41 return sum(bit for bit,ok in ((1,board.has_kingside_castling_rights(chess.WHITE)),(2,board.has_queenside_castling_rights(chess.WHITE)),(4,board.has_kingside_castling_rights(chess.BLACK)),(8,board.has_queenside_castling_rights(chess.BLACK))) if ok)
42
43def signature(board):return board.fen(en_passant='fen')
44
45def position_key(board):
46 """Conservative transposition key: ignore clocks/history; legal EP semantics.
47
48 Raw unreachable EP targets collapse with no-EP positions. Distinct castling
49 rights and side-to-move remain distinct. SHA256 collisions cannot admit a leak.
50 """
51 check_board(board)
52 fields=board.fen(en_passant='legal').split()[:4]
53 return hashlib.sha256(' '.join(fields).encode('ascii')).digest()
54
55def genuine_history(board,n=HISTORY):
56 if type(n) is not int or not 0<=n<=HISTORY:raise ValueError('history bound')
57 n=min(n,len(board.move_stack));prior=board.copy(stack=True);moves=[]
58 for _ in range(n):moves.append(prior.pop())
59 moves.reverse()
60 for move in moves:
61 if move not in prior.legal_moves:raise ValueError('invalid history stack')
62 prior.push(move)
63 if signature(prior)!=signature(board):raise ValueError('history does not reach supplied board')
64 return moves
65
66def prompt(board,history_plies=HISTORY):
67 check_board(board);moves=genuine_history(board,history_plies)
68 missing=3*(HISTORY-len(moves))
69 ids=[BOS,HIST_PARTIAL if moves else HIST_NONE]+[PAD]*missing
70 for move in moves:ids.extend(triple(move))
71 ids.append(STATE)
72 for square in chess.SQUARES:
73 piece=board.piece_at(square)
74 ids.append(PIECE_BASE+(0 if piece is None else piece.piece_type+(0 if piece.color else 6)))
75 ids.extend([SIDE_BASE+(0 if board.turn else 1),CASTLE_BASE+castle(board),EP_NONE if board.ep_square is None else EP_BASE+board.ep_square,
76 HALF_BASE+board.halfmove_clock if board.halfmove_clock<150 else HALF_GE150,NEXT])
77 mask=[1,1]+[0]*missing+[1]*(PROMPT-2-missing)
78 assert len(ids)==len(mask)==PROMPT
79 return {'input_ids':ids,'attention_mask':mask,'position_ids':list(range(PROMPT)),
80 'metadata':{'fullmove_number':board.fullmove_number,'history_plies':len(moves),'halfmove_clock':board.halfmove_clock}}
81
82def from_history(start_fen,uci_moves):
83 board=chess.Board(start_fen);check_board(board)
84 if len(uci_moves)>HISTORY:raise ValueError('history exceeds16 plies')
85 for uci in uci_moves:
86 move=chess.Move.from_uci(uci)
87 if not move or move not in board.legal_moves:raise ValueError('illegal supplied history')
88 board.push(move)
89 return board
90
91def example(board,move,history_plies=HISTORY):
92 check_board(board)
93 if board.is_game_over(claim_draw=False):raise ValueError('automatic terminal position has no training decision')
94 if move not in board.legal_moves:raise ValueError('illegal target')
95 p=prompt(board,history_plies);target=triple(move)
96 return {'input_ids':p['input_ids']+target[:2],'attention_mask':p['attention_mask']+[1,1],
97 'position_ids':list(range(INPUT)),'labels':target,'loss_mask':[int(i in TARGET_POSITIONS) for i in range(INPUT)],
98 'metadata':p['metadata'],'position_key':position_key(board)}
99
100def masks(board,prefix=(),legal=False):
101 """Separate optional output constraints. Raw512 logits are never renormalized here."""
102 check_board(board)
103 if len(prefix)>2 or any(type(x) is not int or not 0<=x<64 for x in prefix):raise ValueError('incorrect move phase')
104 allowed=set(range(64) if len(prefix)<2 else range(64,69))
105 if legal:
106 allowed={triple(m)[len(prefix)] for m in board.legal_moves if triple(m)[:len(prefix)]==list(prefix)}
107 return [i in allowed for i in range(VOCAB)]
108