Skip to content

Stage 0.1: Action stack and frames

neuront edited this page Apr 18, 2012 · 6 revisions

Code review: https://github.com/neuront/sgs/commit/55a5e4167809060cf7da6dde5742e367c76b00fa

游戏状态控制

动作栈 core.src.action_stack.ActionStack 与动作帧 core.src.action_frames.*

当游戏正在进行时, 轮到某个玩家响应一个特定的动作, 比如出牌阶段, 使用一张牌或者放弃 (进入弃牌阶段), 或者在被火攻阶段被要求展示一张手牌, 此时内核会暂停下来, 等待玩家响应. 那么, 需要引入栈来保持内核此时的游戏结算状态, 为此, 内核中设计了动作栈和动作帧.

当玩家交互信息被发送到内核中 (通过调用 core.src.game_control.GameControl.player_act) 时, 内核会将此消息直接发送给动作栈栈顶的帧, 由该帧的 react 方法处理该消息. 消息以及 react 函数的返回值都是数值, 字符串, 或这些基本数据类型构成的列表及字典, 而不应改包含复杂数据类型. 具体的消息格式由帧定义, 帧也会定义返回的消息格式.

虽然帧的返回可能各不相同, 但在当前, react 函数返回只可能包括

  • 如果消息被正确处理, 返回 { 'code': core.src.ret_code.OK }
  • 否则, 返回 { 'code': core.src.ret_code.BAD_REQUEST, 'reason': 原因 }

详细错误原因可以查看 core.src.ret_code.BR_*.

帧返回与结果传递

当一个动作帧结束响应 (如: 出牌阶段结束后, 响应出牌的帧应该退栈, 然后响应弃牌的帧入栈) 后, 它在出栈后将向外传递消息. 该消息的结构仍然是简单数据类型或简单数据类型的复合. 接收此消息的函数称之为 on_result 函数 (core.src.action_frames.FrameBase.on_result), 它由动作帧构造时传入.

要结束动作帧的响应, 需要调用该帧的 done 函数, 并传入帧结果. 帧结果的消息格式也由帧来定义.

例子

下面的例子将描述一个玩家的一个完整回合 (目前没有设计体力和手牌上限机制, 在回合结束阶段, 玩家被要求弃掉两张手牌). 这个例子的流程在单元测试 ext/test/test_fire_attack.py 中. 火攻的实现目前在 ext/src/player_using_cards.py 中. 而上一个版本中, 玩家 core.src.Player 的代码已经被转移到 ext.src.Player 中了.

摸牌阶段

玩家的摸牌阶段非常简单, 仅从牌堆中摸两张牌即可, 在 ext.src.Player.round 中这个过程被直接执行, 接下来就调用 ext.src.Player.using_cards_stage, 在这个函数向动作栈中压入出牌阶段帧 (core.src.action_frames.UseCards), 于是玩家进入出牌阶段.

出牌阶段

出牌阶段帧在构造时, 会要求传入一个字典, 表示该玩家出牌阶段能进行的动作. 目前, 该字典的构造在 ext.src.player_using_cards.get_using_cards_interface_map 中. 在出牌阶段帧构造函数内, 这个字典会被追加一项 { 'give up': core.src.action_frames.FrameBase.done }, 此项表示玩家终止出牌阶段, 进入弃牌阶段.

出牌阶段帧的传入参数要求玩家传入自己的 token 标识身份, 然后是出牌动作 action, 以及使用的牌, 还有指定的目标. 其中, token 的检查会在帧内检查, 同时还会检查使用的牌是否为该玩家持有, 但如果动作本身无需牌, 则可以不传递 cards, 或者传递空的序列. 然后, 帧会将传入的参数保持原样传入 interface_map 中 action 对应的函数中去.

例如, 通过如下调用发起火攻 (gcGameControl 对象)

gc.player_act({
    'token': players[0].token,
    'action': 'fire attack',
    'targets': [players[1].player_id],
    'cards': [1],
})

典型地调用 player_act 的参数会包括

  • token: 玩家 token
  • action: 动作 (火攻, 或 give up)
  • targets (可选): 动作目标
  • cards (可选): 使用的卡牌

对于火攻的例子, 有更详细的描述文档 (本页面对应描述的是代码在 Stage 0.1 时的情况, 而该文档则描述 HEAD 代码), 请参阅 https://github.com/neuront/sgs/wiki/An-Illustration-to-Arson-Attack (译法改为了 arson attack)

终止出牌

当玩家决定终止出牌阶段时, 可进行如下调用

gc.player_act({
    'token': players[0].token,
    'action': 'give up',
})

此时进入弃牌阶段. 在弃牌阶段通过如下调用弃置两张手牌

gc.player_act({
    'token': players[0].token,
    'discard': [0, 8],
})

discard 对应的参数为两张手牌 id 构成的列表.

动作帧细则: https://github.com/neuront/sgs/wiki/Action-Frames-Specification

主要设计修正

PlayerPlayersControl 被移出内核模块, 因为玩家的行为以及控制是特定的游戏规则, 而不应该由内核确定; 在不同游戏规则中 (如 3v3, 虎牢关等) 会有所不同. 现在它们分别是 ext.src.player.Playerext.src.players_control.PlayersControl.

Player 将不再持有牌 core.src.card.Card 对象, 转而由 Card 对象指定其持有人, 或当无人持有时该字段为空 (core.src.card.Card.owner_or_nil).

Clone this wiki locally