#P52071. 「THUPC 2021 初赛」麻将模拟器

「THUPC 2021 初赛」麻将模拟器

题目描述

麻将是一种休闲的四人博弈游戏。你的任务是写一个模拟器来模拟一局游戏的进程。

接下来将详细介绍游戏规则和每个玩家的决策。注意:为了实现方便和使游戏更加有趣味,这里介绍的规则和主流的几种麻将规则均略有不同。

基础规则:

  • 一副麻将由 148148 张牌组成,其中包含 3737 种不同的牌,每种各 44 张。
  • 3737 种牌分别是:一万到九万(1M ~ 9M)、一筒到九筒(1P ~ 9P)、一索到九索(1S ~ 9S)、东(E)、南(S)、西(W)、北(N)、白(B)、发(F)、中(Z),以及 33 种特殊牌:跳过(PASS),反向(REVERSE),双重回合(DOUBLE)。
  • 游戏共有 44 名玩家,不妨称其为 ABCD
  • 游戏开始前,将 148148 张牌随机洗乱后摆成一排,称为牌堆。此后玩家摸牌一定是从牌堆中摸取最靠前的一张牌。
  • A 开始按照 ABCDABCD... 的顺序,每人依次从牌堆中摸一张牌,直到每人都有 1313 张牌,这些牌组成每个玩家的手牌。
  • 再从 A 开始按照 ABCDABCD... 的顺序,依次进入每人的回合:
  • 在一个回合中,玩家先摸一张牌进入自己的手牌,再从自己的手牌中打出一张牌。
  • 依次进行直到有人和牌或者无牌可摸时游戏结束。

特殊牌:

  • 跳过(PASS):在出牌时打出这张牌,可以指定一名玩家,跳过他的下一个回合。
  • 反向(REVERSE):在出牌时打出这张牌,反转进行回合的顺序,即由 ABCDABCD... 变为 ADCBADCB... 或由 ADCBADCB...变为ABCDABCD...`。出牌后即按照反转后的顺序,从出牌者原先的上家开始进行回合。
  • 双重回合(DOUBLE):在出牌时打出这张牌,该名玩家立即进入一个额外的回合。

牌型:有如下 33 种牌型:

  • 顺子:33 张数字连续的万,或 33 张数字连续的筒,或 33 张数字连续的索,如 4P 5P 6P
  • 刻子:33 张完全一样的非特殊牌,如 B B B
  • 对子:22 张完全一样的非特殊牌,如 9M 9M

吃、碰:

  • 当一名玩家打出一张非特殊牌时,其他玩家可以进行吃或碰:
  • 吃(CHOW):当打出的这张牌跟自己的手牌中的某两张牌能组成一个顺子时,可以将手牌中能与之组成顺子的其余两张牌取出,与这张牌一起摆在旁边。
  • 注意只有上一名出牌玩家的下家(按当前顺序原本应在下一个进行回合的玩家)才能吃。
  • 碰(PONG):当打出的这张牌跟自己的手牌中的某两张牌能组成一个刻子时,可以将手牌中能与之组成刻子的其余两张牌取出,与这张牌一起摆在旁边。
  • 碰没有吃的上述限制,任意其他玩家都能碰。
  • 如果既有玩家能吃又有玩家能碰,则碰优先于吃。
  • 吃(或碰)不是强制性的,也就是说玩家满足吃(或碰)的条件时,可以选择不吃(或碰)。
  • 吃和碰统称为副露。为方便起见,不将副露视为手牌的一部分。
  • 在任意一名玩家吃(或碰)后,跳过从上一名出牌的玩家到这名玩家之间的所有玩家的回合,直接从当前玩家开始进行新的回合。但该玩家在这一回合中跳过摸牌直接出牌,在下一回合(如果没有吃碰的话)恢复正常。
  • 注意在本规则中不能杠。

胡牌规则:

  • 称一名玩家的牌能和,当且仅当满足如下条件:
    • 牌数为 143n14 - 3 n,其中 nn 为该玩家副露(即吃碰)的个数;
    • 这些牌中无特殊牌;
    • 这些牌能够被分成 (5n)(5 - n) 组,其中 (4n)(4 - n) 组均为 33 张且均为顺子或刻子,其余一组为 22 张且为对子。
  • 注意本规则中不支持七对子、十三幺、全不靠等特殊的和牌规则。
  • 另外,定义一组包含 133n13 - 3 n 张牌的手牌的和牌距离为最小的 xx,使得向这些牌中加入特定的 xx 张牌,再去掉 x1x - 1 张手牌后,每种牌仍不超过 44 张且能和。
  • 定义一组包含 143n14 - 3 n 张牌的手牌的和牌距离为最小的 xx,使得向这些牌中加入特定的 xx 张牌,再去掉 xx 张手牌后,每种牌仍不超过 44 张且能和。
  • 特别地,一手能和的牌的和牌距离为 00;和牌距离为 11 的牌称为听牌。
  • 注意这里的“每种牌仍不超过 4\boldsymbol{4} ”的限制:如果一手牌是 1M 1M 1M 1M 且副露数为 33,再向其中加入一张 1M 就能和,但是由于有 551M 所以是不被允许的,故不认为其和牌距离为 11
  • 但如果一手牌是 1M 且副露数为 44,但是曾进行过一次 1M 1M 1M 的碰,仍然认为其和牌距离为 11(虽然缺的这张 1M 永远也等不到)。

终局:

  • 荣和(RON):当一名玩家出牌后,某名其他玩家的手牌加上这张牌能和,则称这名玩家荣和。荣和优先于吃碰。
  • 如果有多名玩家同时达到荣和的标准,规定只有从上一名出牌玩家开始,沿回合进行顺序的第一名能荣和的玩家才能荣和,其余玩家荣和不了,称这种情况为截和。
  • 自摸(SELFDRAWN):一名玩家摸牌后其手牌能和,称这名玩家自摸。
  • 一旦有一名玩家荣和或自摸,游戏立即结束,该名玩家胜利。
  • 如果某名玩家摸牌时发现牌堆中已经无牌可摸,游戏立即结束,称此种情况为流局。

出牌策略:每名玩家的出牌策略相同且固定:

  • 出牌时,若手里有特殊牌一定会优先出,且如果有多种特殊牌,按照 PASSREVERSEDOUBLE 的优先顺序;出的 PASS 一定指定下家。
  • 出牌时若手里没有特殊牌,则会对于每一种可能的出牌方法计算出完牌后的和牌距离,选择和牌距离最小的一种方案。如果有并列最小,按照 ZFBNWSE9S8S,……,1S9P,……,1P9M,……,1M 的优先顺序出牌。
  • 同一个人能吃且能碰时,优先考虑碰;因为每种牌只有 44 张所以不会有两名玩家同时可以碰的情况;当且仅当吃(或碰)后能使得和牌距离严格减小才会去吃(或碰);如果有多种吃的方案使得和牌距离严格减小,优先选择数字较大的方案。
  • 能荣和一定荣和(除非被截和),能自摸一定自摸,不会拒和(能和时故意选择不和)。

输入格式

输入共 148148 行,按照牌堆从前到后的顺序输入每一张牌。
每行输入一个字符串表示这一张牌。
1M2M,……,9M 代表万,1P2P,……,9P 代表筒,1S2S,……,9S 代表索,ESWNBFZ 分别代表东、南、西、北、白、发、中,PASS 代表跳过,REVERSE 表示反向,DOUBLE 表示双重回合。

输出格式

按照如下几条规则进行输出:

  • 当任意一名玩家摸牌时(包括游戏最开始的摸牌),输出一行:
    x IN y
    其中 x 为玩家名称,y 为摸到的牌。
  • 当任意一名玩家出牌时,如果出的牌不是 PASS,输出一行:
    x OUT y
    其中 x 为玩家名称,y 为出的牌。
    如果出的牌是 PASS,应当输出一行:
    x OUT PASS z
    其中 zPASS 指定的对象。
  • 当任意一名玩家吃时,输出一行:
    x CHOW y1 y2 y3
    其中 x 为玩家名称,y1y2y3 为吃涉及到的 33 张牌,按数字递增的顺序输出。
  • 当任意一名玩家碰时,输出一行:
    x PONG y1 y2 y3
    其中 x 为玩家名称,y1y2y3 为碰涉及到的 33 张牌,根据碰的规则,y1y2y3 应相同。
  • 当任意一名玩家荣和时,输出一行:
    x RON
    其中 x 为玩家名称。
  • 当任意一名玩家自摸时,输出一行:
    x SELFDRAWN
    其中 x 为玩家名称。
  • 游戏的最后,如果某名玩家获得胜利,输出一行:
    x WIN
    其中 x 为玩家名称。
    如果出现流局,输出一行:
    DRAW

需要特别注意的是,输入输出中出现的英文字母均为大写。

样例

见附加文件中的 [1.in](file:1.in) 与 [1.ans](file:1.ans)。

来源

来自 2021 清华大学学生程序设计竞赛暨高校邀请赛(THUPC2021)初赛。

题解等资源可在 https://github.com/THUSAAC/THUPC2021-pre 查看。