news 2026/6/30 4:53:49

core/game_node.py - 游戏树节点

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
core/game_node.py - 游戏树节点

文件大小: 18857 字节 (452 行)
功能: 棋谱树结构管理

3.9.1 GameNode类
class GameNode:
"""
游戏树节点
主要属性:
- parent: 父节点
- children: 子节点列表
- move: 本节点着法(Move对象)
- properties: SGF属性字典
- analysis: 分析结果(从KataGo获取)
"""
def __init__(self, parent=None, move=None):
self.parent = parent
self.children = []
self.move = move
self.properties = {}
self.analysis = None
self.move_number = 0
if parent:
self.move_number = parent.move_number + 1
3.9.2 核心方法
def play(self, move: Move) -> 'GameNode':
"""
执行着法
流程:
1. 查找是否已有该着法的子节点
2. 如果有,返回现有节点
3. 如果没有,创建新节点
返回:子节点
"""
# 查找现有子节点
for child in self.children:
if child.move and child.move.equals(move):
return child
# 创建新节点
new_node = GameNode(parent=self, move=move)
self.children.append(new_node)
return new_node
@property
def nodes_from_root(self) -> List['GameNode']:
"""
从根节点到本节点的路径
返回:节点列表
"""
nodes = []
current = self
while current:
nodes.insert(0, current)
current = current.parent
return nodes
@property
def nodes_in_tree(self) -> List['GameNode']:
"""
树中的所有节点
递归遍历所有子孙节点
返回:节点列表
"""
nodes = [self]
for child in self.children:
nodes.extend(child.nodes_in_tree)
return nodes
def analyze(self, engine: KataGoEngine, **kwargs):
"""
分析本节点
参数:
- engine: KataGo引擎
- kwargs: 分析参数
流程:
1. 调用KataGo引擎
2. 存储分析结果
"""
def callback(result):
self.analysis = result
engine.request_analysis(self, callback, **kwargs)
3.9.3 分析数据压缩
# 分析结果可能很大(数百KB)
# 使用压缩存储减少内存占用
import gzip
import pickle
def set_analysis(self, analysis: dict):
"""压缩存储分析结果"""
self._analysis_compressed = gzip.compress(
pickle.dumps(analysis)
)
def get_analysis(self) -> dict:
"""解压获取分析结果"""
if hasattr(self, '_analysis_compressed'):
return pickle.loads(
gzip.decompress(self._analysis_compressed)
)
return None

3.10 core/sgf_parser.py - SGF棋谱解析

文件位置:core/sgf_parser.py
文件大小: 26249 字节 (713 行)
功能: 解析和生成SGF格式棋谱

3.10.1 Move类 - 棋步
class Move:
"""
棋步类
坐标系统:
- GTP: A1-T19(列字母+行数字)
- SGF: aa-ss(双字母,左上角为aa)
- 内部: (x, y) 元组,x=列,y=行
"""
def __init__(self, coords: Optional[Tuple[int, int]], player: str):
"""
参数:
- coords: (x, y) 或 None(pass)
- player: 'B' 或 'W'
"""
self.coords = coords
self.player = player
def gtp(self) -> str:
"""转换为GTP坐标:如 "Q16" """
if not self.coords:
return "pass"
x, y = self.coords
col = chr(ord('A') + x)
row = 19 - y
return f"{col}{row}"
def sgf(self) -> str:
"""转换为SGF坐标:如 "pd" """
if not self.coords:
return ""
x, y = self.coords
col = chr(ord('a') + x)
row = chr(ord('a') + y)
return f"{col}{row}"
@staticmethod
def from_gtp(gtp: str, player: str) -> 'Move':
"""从GTP坐标创建"""
if gtp.lower() == 'pass':
return Move(None, player)
col = gtp[0].upper()
row = int(gtp[1:])
x = ord(col) - ord('A')
y = 19 - row
return Move((x, y), player)
@staticmethod
def from_sgf(sgf: str, player: str) -> 'Move':
"""从SGF坐标创建"""
if not sgf:
return Move(None, player)
x = ord(sgf[0]) - ord('a')
y = ord(sgf[1]) - ord('a')
return Move((x, y), player)
3.10.2 SGF类 - SGF文件解析
class SGF:
"""
SGF文件解析
SGF属性:
- GM: 游戏类型(1=围棋)
- FF: 文件格式(4)
- SZ: 棋盘大小(19)
- KM: 贴目(7.5)
- RU: 规则(chinese)
- PB/PW: 黑/白方姓名
- DT: 日期
- RE: 结果(如 "B+3.5")
"""
@staticmethod
def parse(sgf_content: str) -> GameNode:
"""
解析SGF文件
流程:
1. 解析SGF属性(如GM、FF、SZ、KM等)
2. 构建游戏树(支持分支)
3. 返回根节点(GameNode)
"""
# 解析属性
properties = SGF._parse_properties(sgf_content)
# 创建根节点
root = GameNode()
root.properties = properties
# 解析着法
current = root
SGF._parse_moves(sgf_content, current)
return root
@staticmethod
def generate(root: GameNode) -> str:
"""
生成SGF文件
返回:SGF格式字符串
"""
sgf = "(;"
# 添加属性
for key, value in root.properties.items():
sgf += f"{key}[{value}]"
# 添加着法
sgf += SGF._generate_moves(root)
sgf += ")"
return sgf

3.11 core/goai.py - AI封装接口

文件位置:core/goai.py
文件大小: 7230 字节 (173 行)
功能: 简化AI调用接口

3.11.1 GoAI类
class GoAI:
"""
围棋AI封装
主要方法:
- get_best_move(): 获取最佳着法
"""
def __init__(self, strategy: str = 'default'):
self.strategy = strategy
def get_best_move(self, game: Game, color: int) -> Optional[Move]:
"""
获取最佳着法
流程:
1. 优先提子逻辑
- 检查是否能提掉对方≥3子的棋块
- 如果能,直接提子(避免错失提子机会)
2. 调用KataGo分析
- 获取当前节点的分析结果
- 提取候选着法列表
3. 合法落子检查
- 过滤掉非法着法(如自杀、劫)
- 返回最佳合法着法
参数:
- game: 游戏对象
- color: 颜色(1=黑,2=白)
返回:Move对象,失败返回None
"""
# 提子优先
capture_move = self._check_capture_opportunity(game, color)
if capture_move:
return capture_move
# 调用策略
strategy_func = STRATEGIES[self.strategy]
return strategy_func(game)
def _check_capture_opportunity(
self,
game: Game,
color: int
) -> Optional[Move]:
"""
检查提子机会
如果能提掉对方≥3子的棋块,直接提子
"""
# ...(详细实现见源码)
pass

3.12 core/wechat_pay.py - 微信支付集成

文件位置:core/wechat_pay.py
文件大小: 8538 字节 (273 行)
功能: 微信支付V3 API封装

3.12.1 核心功能
class WeChatPay:
"""
微信支付V3
主要功能:
1. Native支付(扫码支付)
2. 订单管理
3. 支付回调
"""
def __init__(self, app_id, mch_id, api_key):
self.app_id = app_id
self.mch_id = mch_id
self.api_key = api_key
def create_order(
self,
out_trade_no: str,
total_amount: int,
description: str
) -> str:
"""
创建订单
参数:
- out_trade_no: 商户订单号
- total_amount: 金额(分)
- description: 商品描述
返回:支付二维码链接
"""
# 构建请求
# ...
# 返回code_url
return code_url
def query_order(self, out_trade_no: str) -> dict:
"""
查询订单状态
返回:
{
'trade_state': 'SUCCESS', # SUCCESS/NOTPAY/CLOSED
'transaction_id': '...',
...
}
"""
pass
def close_order(self, out_trade_no: str):
"""关闭订单"""
pass
def verify_callback(self, headers: dict, body: str) -> dict:
"""
验证支付回调
安全措施:
- 使用微信平台证书验证签名
- 敏感数据加密传输(AES-256-GCM)
- 订单幂等性处理
返回:解密后的回调数据
"""
# 验证签名
# ...
# 解密数据
# ...
return decrypted_data

3.13 其他核心模块

3.13.1 core/constants.py - 全局常量
# AI策略类型
AI_DEFAULT = 'default'
AI_RANK = 'rank'
AI_HUMAN = 'human'
AI_PRO = 'pro'
AI_WEIGHTED = 'weighted'
# ... 更多策略
# 输出级别
OUTPUT_RAW = 'raw'
OUTPUT_ANALYSIS = 'analysis'
OUTPUT_OWNERSHIP = 'ownership'
# 优先级
PRIORITY_HIGH = 10
PRIORITY_NORMAL = 5
PRIORITY_LOW = 1
# 游戏模式
MODE_PLAY = 'play'
MODE_ANALYZE = 'analyze'
MODE_SELFPLAY = 'selfplay'
3.13.2 core/utils.py - 工具函数
def coord_to_gtp(x: int, y: int) -> str:
"""坐标转GTP格式"""
col = chr(ord('A') + x)
row = 19 - y
return f"{col}{row}"
def weighted_choice(items: List, weights: List[float]) -> Any:
"""加权随机选择"""
total = sum(weights)
r = random.random() * total
cumsum = 0
for item, weight in zip(items, weights):
cumsum += weight
if r <= cumsum:
return item
return items[-1]
def truncate_json_array(data: dict, key: str, max_items: int):
"""截断JSON数组"""
if key in data and isinstance(data[key], list):
data[key] = data[key][:max_items]
3.13.3 core/email_config.py - 邮件服务
import smtplib
from email.mime.text import MIMEText
def send_email(to: str, subject: str, body: str):
"""
发送邮件
用于:
- 密码重置
- VIP到期提醒
"""
msg = MIMEText(body)
msg['Subject'] = subject
msg['From'] = SMTP_USER
msg['To'] = to
with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as server:
server.starttls()
server.login(SMTP_USER, SMTP_PASSWORD)
server.send_message(msg)
3.13.4 core/bj_time.py - 北京时间
from datetime import datetime, timezone, timedelta
def get_beijing_time() -> datetime:
"""获取当前北京时间"""
utc_now = datetime.utcnow()
beijing_tz = timezone(timedelta(hours=8))
return utc_now.replace(tzinfo=beijing_tz)
3.13.5 core/katabase.py - KataGo配置管理
class KatagoBase:
"""
KataGo基础配置
主要属性:
- size: 棋盘大小
- komi: 贴目
- rules: 规则集
- max_visits: 最大访问次数
"""
def __init__(self, config_path: str = "data/config.json"):
self.config = self._load_config(config_path)
self.size = self.config.get('size', 19)
self.komi = self.config.get('komi', 7.5)
self.rules = self.config.get('rules', 'chinese')
self.max_visits = self.config.get('max_visits', 1000)
class SimpleJsonStore:
"""轻量级JSON存储器"""
def __init__(self, filepath: str):
self.filepath = filepath
self.data = self._load()
def save(self):
"""保存到文件"""
with open(self.filepath, 'w') as f:
json.dump(self.data, f, indent=2)

四、路由模块详解

4.1 routers/ws.py - WebSocket路由 ⭐核心

文件位置:routers/ws.py
文件大小: 31361 字节 (755 行)
功能: WebSocket路由和实时对弈处理

4.1.1 端点定义
@router.get("/")
async def get_home():
"""主页路由"""
return FileResponse('static/index.html')
@router.websocket("/ws/{room_id}")
async def websocket_endpoint(
websocket: WebSocket,
room_id: str,
token: str = Query(...)
):
"""
WebSocket连接端点
参数:
- room_id: 房间ID
- token: JWT认证token
流程:
1. 验证token
2. 接受WebSocket连接
3. 加入房间
4. 循环处理消息
5. 处理断线
"""
# 验证token
username = decode_token(token)
if not username:
await websocket.close(code=4001)
return
# 接受连接
await websocket.accept()
# 加入房间
success, color, error = await manager.join_room(
room_id, websocket, username
)
if not success:
await websocket.send_json({'type': 'error', 'message': error})
await websocket.close()
return
try:
# 消息循环
while True:
data = await websocket.receive_json()
await handle_websocket_message(room_id, username, data, websocket)
except WebSocketDisconnect:
# 处理断线
await manager.handle_disconnect(room_id, color, username)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/30 4:50:07

Fillinger智能填充脚本:从设计困境到高效创作的突破之路

Fillinger智能填充脚本&#xff1a;从设计困境到高效创作的突破之路 【免费下载链接】illustrator-scripts Adobe Illustrator scripts 项目地址: https://gitcode.com/gh_mirrors/il/illustrator-scripts 你是否曾在Adobe Illustrator中手动排列数百个设计元素&#xf…

作者头像 李华
网站建设 2026/6/30 4:49:18

数据库跨年问题处理

问题&#xff1a;合同结束时间&#xff0c;应为当年的最后一天&#xff0c;为什么显示的是2027年原因&#xff1a;老代码用的类型是Date&#xff0c;数据库用的类型是dateTimejava.util.Date 内部就是一个 long类型的变量&#xff0c;存的是 自1970-01-01 00:00:00 GMT 以来的毫…

作者头像 李华
网站建设 2026/6/30 4:49:18

这个级别的配置两万买爱彼15703?拆开表冠防水圈,这处结构直接劝退

有个刚接触机械表的朋友跟我吐槽&#xff0c;说现在的人说话太绕。他起初也是带着怀疑看了眼这作者名&#xff0c;心想这名字起得这么硬核&#xff0c;不会又是长篇大论吧&#xff0c;结果几分钟就看懂了。沟通就得直接点&#xff0c;今天咱们继续。古董表的美感像熟透的少妇&a…

作者头像 李华
网站建设 2026/6/30 4:49:04

51camera隧道综合巡检机器人 守护隧道安全

随着轨道交通网规模的不断扩大&#xff0c;隧道数量逐渐增多&#xff0c;加之轨道的运力持续释放&#xff0c;隧道病害问题日益凸显&#xff0c;隧道结构的安全保障压力同步加大&#xff0c;而隧道内部的微小缺陷均可能诱发重大安全事故&#xff0c;隧道巡检的必要性和重要性不…

作者头像 李华
网站建设 2026/6/30 4:48:57

2026年品牌设计年轻化,哪家公司策略更胜一筹?

“品牌年轻化不是换张海报、加个表情包&#xff0c;而是让品牌真正‘活’进新一代的生活方式里。” 当Z世代成为消费主力&#xff0c;当00后开始主导家庭健康决策&#xff0c;传统品牌若还停留在“自说自话”的视觉翻新&#xff0c;注定会被时代悄然淘汰。2026年&#xff0c;品…

作者头像 李华
网站建设 2026/6/30 4:48:49

IntelliJ IDEA 之下载与安装

其中&#xff0c;Windows 的还支持安装器版和解压包版&#xff0c;本文以安装器版为示例&#xff0c;版本号为 2025.3.3 。 提示&#xff1a;在 2025.3 版本之前&#xff0c;IDEA 还分社区版和旗舰版&#xff0c;社区版是免费的&#xff1b;现在统一了版本&#xff0c;没授权码…

作者头像 李华