Spaces:
Sleeping
Sleeping
File size: 5,234 Bytes
3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 decd848 dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 355b1fc dc1c3d2 3ffe4ed 355b1fc 3ffe4ed dc1c3d2 3ffe4ed 355b1fc 3ffe4ed 355b1fc 3ffe4ed dc1c3d2 355b1fc dc1c3d2 3ffe4ed 355b1fc dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 3ffe4ed dc1c3d2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | #!/usr/bin/env python3
import sys
import torch
import chess
from transformers import AutoTokenizer, AutoModelForCausalLM
MODEL_ID = "zhoudoe23/ChessQween3-base-puzzled"
print(f"[Engine] 正在加载模型: {MODEL_ID} ...", file=sys.stderr)
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
model = AutoModelForCausalLM.from_pretrained(MODEL_ID, torch_dtype=torch.float32)
model.eval()
print("[Engine] 模型加载成功,准备下棋!", file=sys.stderr)
def format_fen_for_model(fen_str: str) -> str:
"""将标准 FEN 转化为模型训练时的格式"""
parts = fen_str.split(" ")
# 1. 棋盘字符间加空格
ranks = parts[0].split("/")
formatted_ranks = [" ".join(list(rank)) for rank in ranks]
formatted_board = " / ".join(formatted_ranks)
# 2. 颜色转换
color = "<|WHITE|>" if parts[1] == "w" else "<|BLACK|>"
# 3. 组合其他字段
castling = parts[2]
ep = parts[3]
halfmove = parts[4]
fullmove = parts[5]
return f"{formatted_board} {color} {castling} {ep} 0 1 >"
def is_suicide_move(board: chess.Board, move: chess.Move) -> bool:
"""精准判断:这一步是不是把重子(车/后)送给对方白吃(Hanging Piece)"""
moving_piece = board.piece_at(move.from_square)
if not moving_piece:
return False
# 只针对车 (Rook) 和 后 (Queen) 这种大子做防御(送兵/送马有时是战术弃子,但送车后绝对崩盘)
if moving_piece.piece_type not in [chess.ROOK, chess.QUEEN]:
return False
my_color = board.turn
dest_square = move.to_square
# 模拟走这步棋
board.push(move)
# 1. 如果走完这步直接【绝杀(Checkmate)】,那送子也无所谓,这是好棋!
if board.is_checkmate():
board.pop()
return False
opponent_color = board.turn # 走完后轮到对方
# 2. 检查落子点:落子后,这个格子是否在对方的攻击火力下?
is_under_attack = board.is_attacked_by(opponent_color, dest_square)
# 3. 检查落子点:落子后,这个格子是否有我方其他棋子在保护?
is_defended = board.is_attacked_by(my_color, dest_square)
board.pop()
# 【核心逻辑】:如果落子点【暴露在对方火力下】且【我方没有任何棋子守护】,这就是纯送死!
if is_under_attack and not is_defended:
return True # 判定为纯送死(自杀)
return False
def get_best_move(board: chess.Board) -> chess.Move:
raw_fen = board.fen()
prompt = format_fen_for_model(raw_fen)
inputs = tokenizer(prompt, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
logits = outputs.logits[0, -1, :]
# 将所有 Token 按模型预测的概率从高到低排序
sorted_indices = torch.argsort(logits, descending=True)
candidate_moves = []
for token_id in sorted_indices:
move_str = tokenizer.decode(token_id.item()).strip()
try:
move = chess.Move.from_uci(move_str)
if move in board.legal_moves:
candidate_moves.append(move)
except ValueError:
continue
# 🌟 第一优先级:找【概率高】且【不是自杀送车送后】的走法
for move in candidate_moves:
if not is_suicide_move(board, move):
return move # 找到了兼具战术直觉与安全的完美走法!
# 🌟 保底:如果模型脑子抽风,认为所有走法都是自杀,则被迫返回概率最高的合法走法
return candidate_moves[0]
def main():
board = chess.Board()
while True:
line = sys.stdin.readline()
if not line:
break
line = line.strip()
if not line:
continue
if line == "uci":
print("id name ChessQween3-base")
print("id author zhoudoe23")
print("uciok")
sys.stdout.flush()
elif line == "isready":
print("readyok")
sys.stdout.flush()
elif line == "ucinewgame":
board = chess.Board()
elif line.startswith("position"):
tokens = line.split()
if "startpos" in tokens:
board = chess.Board()
if "moves" in tokens:
move_idx = tokens.index("moves") + 1
for m in tokens[move_idx:]:
board.push_uci(m)
elif "fen" in tokens:
fen_idx = tokens.index("fen") + 1
if "moves" in tokens:
moves_idx = tokens.index("moves")
fen_str = " ".join(tokens[fen_idx:moves_idx])
board = chess.Board(fen_str)
for m in tokens[moves_idx + 1:]:
board.push_uci(m)
else:
fen_str = " ".join(tokens[fen_idx:])
board = chess.Board(fen_str)
elif line.startswith("go"):
best_move = get_best_move(board)
print(f"bestmove {best_move.uci()}")
sys.stdout.flush()
elif line == "quit":
break
if __name__ == "__main__":
main() |