P7147 [THUPC 2021 初赛] 麻将模拟器
题目描述
麻将是一种休闲的四人博弈游戏。你的任务是写一个模拟器来模拟一局游戏的进程。
接下来将详细介绍游戏规则和每个玩家的决策。注意:为了实现方便和使游戏更加有趣味,这里介绍的规则和主流的几种麻将规则均略有不同。
**基础规则:**
- 一副麻将由 $148$ 张牌组成,其中包含 $37$ 种不同的牌,每种各 $4$ 张。
- 这 $37$ 种牌分别是:一万到九万(`1M ~ 9M`)、一筒到九筒(`1P ~ 9P`)、一索到九索(`1S ~ 9S`)、东(`E`)、南(`S`)、西(`W`)、北(`N`)、白(`B`)、发(`F`)、中(`Z`),以及 $3$ 种特殊牌:跳过(`PASS`),反向(`REVERSE`),双重回合(`DOUBLE`)。
- 游戏共有 $4$ 名玩家,不妨称其为 `A`,`B`,`C`,`D`。
- 游戏开始前,将 $148$ 张牌随机洗乱后摆成一排,称为牌堆。此后玩家摸牌一定是从牌堆中摸取最靠前的一张牌。
- 从 `A` 开始按照 `ABCDABCD...` 的顺序,每人依次从牌堆中摸一张牌,直到每人都有 $13$ 张牌,这些牌组成每个玩家的手牌。
- 再从 `A` 开始按照 `ABCDABCD...` 的顺序,依次进入每人的回合:
- 在一个回合中,玩家先摸一张牌进入自己的手牌,再从自己的手牌中打出一张牌。
- 依次进行直到有人和牌或者无牌可摸时游戏结束。
**特殊牌:**
- 跳过(`PASS`):在出牌时打出这张牌,可以指定一名玩家,跳过他的下一个回合。
- 反向(`REVERSE`):在出牌时打出这张牌,反转进行回合的顺序,即由 `ABCDABCD...` 变为 `ADCBADCB...` 或由 `ADCBADCB...` 变为 `ABCDABCD...`。出牌后即按照反转后的顺序,从出牌者原先的上家开始进行回合。
- 双重回合(`DOUBLE`):在出牌时打出这张牌,该名玩家立即进入一个额外的回合。
**牌型:**有如下 $3$ 种牌型:
- 顺子:$3$ 张数字连续的万,或 $3$ 张数字连续的筒,或 $3$ 张数字连续的索,如 `4P 5P 6P`。
- 刻子:$3$ 张完全一样的非特殊牌,如 `B B B`。
- 对子:$2$ 张完全一样的非特殊牌,如 `9M 9M`。
**吃、碰:**
- 当一名玩家打出一张非特殊牌时,其他玩家可以进行吃或碰:
- 吃(`CHOW`):当打出的这张牌跟自己的手牌中的某两张牌能组成一个顺子时,可以将手牌中能与之组成顺子的其余两张牌取出,与这张牌一起摆在旁边。
- **注意只有上一名出牌玩家的下家(按当前顺序原本应在下一个进行回合的玩家)才能吃。**
- 碰(`PONG`):当打出的这张牌跟自己的手牌中的某两张牌能组成一个刻子时,可以将手牌中能与之组成刻子的其余两张牌取出,与这张牌一起摆在旁边。
- 碰没有吃的上述限制,任意其他玩家都能碰。
- 如果既有玩家能吃又有玩家能碰,则碰优先于吃。
- 吃(或碰)不是强制性的,也就是说玩家满足吃(或碰)的条件时,可以选择不吃(或碰)。
- 吃和碰统称为副露。为方便起见,不将副露视为手牌的一部分。
- 在任意一名玩家吃(或碰)后,跳过从上一名出牌的玩家到这名玩家之间的所有玩家的回合,直接从当前玩家开始进行新的回合。但该玩家在这一回合中**跳过摸牌直接出牌**,在下一回合(如果没有吃碰的话)恢复正常。
- **注意在本规则中不能杠。**
**胡牌规则:**
- 称一名玩家的牌能和,当且仅当满足如下条件:
- 牌数为 $14 - 3 n$,其中 $n$ 为该玩家副露(即吃碰)的个数;
- 这些牌中无特殊牌;
- 这些牌能够被分成 $(5 - n)$ 组,其中 $(4 - n)$ 组均为 $3$ 张且均为顺子或刻子,其余一组为 $2$ 张且为对子。
- **注意本规则中不支持七对子、十三幺、全不靠等特殊的和牌规则。**
- 另外,定义一组包含 $13 - 3 n$ 张牌的手牌的和牌距离为最小的 $x$,使得向这些牌中加入特定的 $x$ 张牌,再去掉 $x - 1$ 张手牌后,每种牌仍不超过 $4$ 张且能和。
- 定义一组包含 $14 - 3 n$ 张牌的手牌的和牌距离为最小的 $x$,使得向这些牌中加入特定的 $x$ 张牌,再去掉 $x$ 张手牌后,每种牌仍不超过 $4$ 张且能和。
- 特别地,一手能和的牌的和牌距离为 $0$;和牌距离为 $1$ 的牌称为听牌。
- 注意这里的“**每种牌仍不超过** $\boldsymbol{4}$ **张**”的限制:如果一手牌是 `1M 1M 1M 1M` 且副露数为 $3$,再向其中加入一张 `1M` 就能和,但是由于有 $5$ 张 `1M` 所以是不被允许的,故不认为其和牌距离为 $1$。
- 但如果一手牌是 `1M` 且副露数为 $4$,但是曾进行过一次 `1M 1M 1M` 的碰,仍然认为其和牌距离为 $1$(虽然缺的这张 `1M` 永远也等不到)。
**终局:**
- 荣和(`RON`):当一名玩家出牌后,某名其他玩家的手牌加上这张牌能和,则称这名玩家荣和。荣和优先于吃碰。
- 如果有多名玩家同时达到荣和的标准,规定只有从上一名出牌玩家开始,沿回合进行顺序的第一名能荣和的玩家才能荣和,其余玩家荣和不了,称这种情况为截和。
- 自摸(`SELFDRAWN`):一名玩家摸牌后其手牌能和,称这名玩家自摸。
- 一旦有一名玩家荣和或自摸,游戏立即结束,该名玩家胜利。
- 如果某名玩家摸牌时发现牌堆中已经无牌可摸,游戏立即结束,称此种情况为流局。
**出牌策略:**每名玩家的出牌策略相同且固定:
- 出牌时,若手里有特殊牌一定会优先出,且如果有多种特殊牌,按照 `PASS`、`REVERSE`、`DOUBLE` 的优先顺序;出的 `PASS` 一定指定下家。
- 出牌时若手里没有特殊牌,则会对于每一种可能的出牌方法计算出完牌后的和牌距离,选择和牌距离最小的一种方案。如果有并列最小,按照 `Z`,`F`,`B`,`N`,`W`,`S`,`E`,`9S`,`8S`,……,`1S`,`9P`,……,`1P`,`9M`,……,`1M` 的优先顺序出牌。
- 同一个人能吃且能碰时,优先考虑碰;因为每种牌只有 $4$ 张所以不会有两名玩家同时可以碰的情况;当且仅当吃(或碰)后能使得和牌距离严格减小才会去吃(或碰);如果有多种吃的方案使得和牌距离严格减小,优先选择数字较大的方案。
- 能荣和一定荣和(除非被截和),能自摸一定自摸,不会拒和(能和时故意选择不和)。
输入格式
无
输出格式
无
说明/提示
**【题目来源】**
来自 2021 清华大学学生程序设计竞赛暨高校邀请赛(THUPC2021)初赛。
题解等资源可在 查看。