Python强化学习游戏环境下跨类关系最优构建方式咨询
类关联结构优化方案
先修正原有代码的笔误
你现有代码存在类名不统一的问题:Game初始化时实例化的是Table类,但你实际定义的类名是Tables,后续方案统一使用Table作为牌桌类名。
核心设计思路
采用双向关联+统一操作入口的设计,既保证数据一致性,又满足两类需求:
- Player实例保留
table_no字段,Game层可快速索引玩家所属牌桌,全局管理状态 - Table实例存储当前桌存活玩家的实例引用,无需跨层查询即可直接执行手牌相关逻辑
- 所有玩家淘汰、转移操作统一封装在Game类的方法中,避免手动修改属性导致的数据不一致
具体实现代码
class Chips: # 你原有Chips类的实现,这里补个空实现避免报错 def __init__(self, amount): self.amount = amount def __repr__(self): return str(self.amount) class Game: def __init__(self, n_players, avg_hands_blinds, starting_chips, table_cnt, verbose): self.n_players = n_players * table_cnt self.starting_chips = starting_chips self.table_cnt = table_cnt self.tables = [] per_table_players = int(n_players / table_cnt) for table_id in range(self.table_cnt): self.tables.append(Table(table_id, per_table_players)) # 全局玩家列表,存所有存活/淘汰的玩家实例 self.all_players = [] for player_id in range(self.n_players): table_id = int(player_id / per_table_players) player = Player(player_id, starting_chips, table_id) self.all_players.append(player) # 初始化时把玩家加入对应牌桌的活跃列表 self.tables[table_id].active_players.append(player) def eliminate_player(self, player_id): """淘汰指定玩家,同时更新全局状态和所属牌桌的玩家列表""" player = next(p for p in self.all_players if p.player_no == player_id) player.is_eliminated = True # 从所属牌桌的活跃列表中移除 table = self.tables[player.table_no] table.active_players.remove(player) def transfer_player(self, player_id, target_table_id): """转移玩家到指定牌桌,自动同步双方数据""" player = next(p for p in self.all_players if p.player_no == player_id) if player.is_eliminated: return # 从原牌桌移除 origin_table = self.tables[player.table_no] origin_table.active_players.remove(player) # 加入新牌桌 target_table = self.tables[target_table_id] target_table.active_players.append(player) # 更新玩家的所属桌ID player.table_no = target_table_id def rebalance_tables(self): """全局牌桌负载均衡,可根据你的规则实现分配逻辑,这里仅给出示例结构""" # 先收集所有存活玩家 active_players = [p for p in self.all_players if not p.is_eliminated] per_table_max = max(int(len(active_players)/self.table_cnt), 2) # 最少2人开局 # 清空所有牌桌的活跃列表 for table in self.tables: table.active_players.clear() # 重新分配玩家 current_table_idx = 0 for player in active_players: if len(self.tables[current_table_idx].active_players) >= per_table_max: current_table_idx += 1 self.tables[current_table_idx].active_players.append(player) player.table_no = self.tables[current_table_idx].table_id class Table: def __init__(self, table_id, max_players): self.table_id = table_id self.max_players = max_players self.active_players = [] # 存储当前桌存活的玩家实例引用 self.table_hands = [] def run_hand(self): """执行单局手牌逻辑示例,直接遍历当前桌玩家即可操作""" for player in self.active_players: # 直接调用玩家实例的方法/属性执行业务逻辑 print(f"向玩家{player.player_no}发牌,当前筹码{player.chips.amount}") # 剩余手牌逻辑... class Player: def __init__(self, player_no, starting_chips, table_no): self.player_no = player_no self.table_no = table_no self.chips = Chips(starting_chips) self.is_eliminated = False # 新增淘汰标记 def __repr__(self): return f'player_no: {self.player_no} table_no: {self.table_no} chips: {self.chips} 淘汰状态:{self.is_eliminated}'
关键优势说明
- 不需要冗余存储玩家数据,Table存储的是玩家实例的引用,修改玩家状态时全局同步
- 所有变更操作都有统一入口,不会出现玩家所属桌和Table的玩家列表不一致的问题
- 符合RL训练的需求:Game层可以快速拉取全局状态,Table层可以单独执行单局环境逻辑,和RL算法的接口完全适配
内容的提问来源于stack exchange,提问作者C. Cooney
相关产品推荐
相关产品推荐

