# Task5: 短牌型EHS交叉验证系统 ## 概述 Task5实现了一个完整的短牌型德州扑克EHS交叉验证系统,用于验证短牌型本地生成与xtask导出的EHS的一致性。 ## 核心功能 ### 验证目标 从task5_main.py解析xtask导出的数据 → 短牌型生成器重新计算EHS/HIST → EMD距离比较一致性 ### 三阶段验证 1. **River阶段**: EHS单值精确匹配验证 2. **Turn阶段**: 30-bin直方图分布验证 3. **Flop阶段**: 465-bin直方图分布验证 ## 文件结构 ``` ├── task5_main.py ├── task5_readme.md ├── cross_validation/ │ ├── __init__.py │ ├── cross_validation.py #交叉验证 │ └── parse_data.py # 导出数据解 ├── shortdeck/ │ └── gen_hist.py # 生成直方图 └── ehs_data/ # xtask导出数据 ├── river_ehs.npy ├── turn_hist.npy └── flop_hist.npy ``` ## 关键特性 ### 数据类型 用解析器将xtask导出的数据存储未以下结构: ```python # River EHS记录 RiverEHSRecord: board_id, player_id, ehs, board_cards, player_cards # Turn直方图记录 TurnHistRecord: board_id, player_id, bins[30], board_cards, player_cards # Flop直方图记录 FlopHistRecord: board_id, player_id, bins[465], board_cards, player_cards ``` ### 验证流程 1. **数据解析**: 从.npy文件解析原始数据生成上述结构 2. **牌面解码**: 在解析的数据中取样,使用样本的board_cards/player_cards组合成具体牌面 3. **重新计算**: 使用短牌型生成器根据turn/flop/river(player_cards+board_cards)重算EHS/HIST 4. **一致性比较**: EMD距离/数值差异分析 5. **结果统计**: 通过率、平均误差、分布特征 ## 使用方法 ### 基本运行 ```bash python task5_main.py ``` ### 参数配置 ```bash python task5_main.py --river-samples 10 --turn-samples 5 --flop-samples 3 ``` ### 参数说明 - `--river-samples`: River阶段验证样本数(默认20) - `--turn-samples`: Turn阶段验证样本数(默认10) - `--flop-samples`: Flop阶段验证样本数(默认5) ## 输出示例 ``` ========== OpenPQLDecoder (短牌型36张牌) =============== 初始化短牌型EHS直方图生成器,牌组大小: 36 牌型范围: SIX-ACE 验证River EHS样本 (最大样本数: 5) 样本 1: [Qd Ad] + [6s Th Qc Kd Ac] 原始EHS: 0.692118 重算EHS: 0.692118 差异: 0.000000 验证Turn直方图样本 (最大样本数: 3) 样本 1: [8h 8s] + [6s Qd Kd Kh] 原始直方图: bins=30, sum=13.640, 非零bins=30 生成直方图: bins=30, sum=13.677, 非零bins=30 归一化后EMD距离: 0.021985 验证Flop直方图样本 (最大样本数: 2) 样本 1: [Qd Kd] + [7h Qh Qs] 原始直方图: bins=465, sum=422.320, 非零bins=465 生成直方图: bins=465, sum=427.315, 非零bins=465 归一化后EMD距离: 1.509076 ``` ## 验证标准 ### River阶段 - **成功标准**: 匹配率 > 80% 且平均差异 < 0.05 - **评估方法**: 直接数值比较,容差1e-6 ### Turn/Flop阶段 - **成功标准**: 低EMD率 > 60% 且平均EMD < 0.5 - **EMD阈值**: < 0.2视为低距离 - **评估方法**: Wasserstein距离量化分布差异 ## 数据处理 ### 解码 ```python # Board ID → 公共牌组合 board_cards = decoder.decode_board_id(board_id, num_cards) # Player ID → 手牌组合 player_cards = decoder.decode_player_id(player_id) ``` ### 导出数据结构 ```python # river_ehs.npy { 'board': int64, # 公共牌ID(5张牌的编码) 'player': int64, # 玩家手牌ID(2张牌的编码) 'ehs': float64 # EHS值(0.0-1.0之间的浮点数) } # turn_hist.npy { 'board': int64, # 公共牌ID(4张牌的编码) 'player': int64, # 玩家手牌ID(2张牌的编码) 'bins': ndarray # 30维直方图数组 } # flop_hist.npy { 'board': int64, # 公共牌ID(3张牌的编码) 'player': int64, # 玩家手牌ID(2张牌的编码) 'bins': ndarray # 465维直方图数组 } ``` ### 编码方式 - **Card64编码(用于3-5张公共牌):** 64位,每个suit占16位 每位表示对应rank的牌是否存在 用于board_id(公共牌)编码 - **Hand<2>编码(用于2张牌):** 16位,低8位和高8位分别编码两张牌 每张牌用8位编码:高4位=suit,低4位=rank 用于player_id(手牌)编码 ## 短牌型 - **牌组**: 6, 7, 8, 9, T, J, Q, K, A (四花色,共36张) - **组合数**: Flop阶段C(31,2)=465, Turn阶段30种可能 - **EHS计算**: 枚举所有对手组合,计算胜率期望 ## 版本信息 - **Version**: 1.0 - **Python**: 3.13+ - **依赖**: numpy, scipy, dataclasses ## 遗留 1. **抽样优化** 2. **牌面同构优化** 3. **解析数据存储** 4. **反向验证对比**