三国杀结算模型
考虑在游戏过程中, 某君使用万箭齐发, 对司马懿造成一点伤害, 司马懿发动反馈, 此时游戏暂停, 等待司马懿选择卡牌区域 (手牌或装备). 而在司马懿选择了反馈的卡牌区域后, 后续的玩家需要继续响应万箭齐发. 在万箭齐发结算完毕后, 回到某君的出牌阶段继续出牌或选择弃牌.好吧, 仔细看一下, 这就是个栈.
题外话, 三国杀对延迟锦囊的判定顺序也是个栈, 后来的先判定.
现在的问题就是怎么来表示这个游戏状态栈.
栈帧
天下的栈大抵都一个样, 关键还是在于其中的帧是个什么样子的. 首先帧必须能够接受玩家的输入, 以推进游戏状态; 其次, 每个帧只能接受特定玩家的输入, 比如司马懿发动反馈时, 其他玩家是不能决定反馈区域的. 那么, 帧的声明可能会像这个样子class FrameBase:
def react(self, args):
pass # response to player's action
def allowed_players(self):
return [] # which players are allowed
react
函数的参数 args
就是在之前提到的, 从浏览器端传来的 JSON 解析后的字典数据.另外, 当浏览器, 也就是客户端程序向服务器请求 hint 时, 服务器应该给出当前栈顶帧所对应的 hint. 因此, 每个帧都必须还能获得 hint 数据
class FrameBase:
# other functions
def hint(self, token):
if token in map(lambda player: player.token, self.allowed_players()):
return {} # detail info
return {} # just who are active players
栈
虽然说栈大抵都一样, 不过一些必须的功能还是得手动引进, 很关键的就是帧退栈时的动作, 以及如何使帧和帧之间可以传递信息. 下面是结算栈的架子class ActionStack:
def __init__(self):
self.frames = []
def call(self, args):
return self.frames[-1].react(args)
def allowed_players(self):
return self.frames[-1].allowed_players()
def hint(self, token):
return self.frames[-1].hint(token)
def push(self, frame):
self.frames.append(frame)
def pop(self):
stack_top = self.frames.pop()
# pass something from stack_top to current stack top
pop
剩余的部分, 需要理清下面的问题- 怎么获得之前栈顶的结果
- 结果怎么被传递给当前栈顶
pop
本身由谁在什么时机来调用