麻将对对碰游戏:规则与模拟实现

麻将对对碰游戏:规则与模拟实现

麻将对对碰是一种基于麻将牌的趣味游戏,结合了抽牌、许愿和对子结算的机制。本文将介绍游戏规则,并通过 Python 实现一个模拟程序,帮助大家更好地理解游戏玩法。


游戏规则

  1. 牌堆

    • 使用标准麻将的 136 张牌,包括万子、条子、筒子、风牌和箭牌。
    • 牌堆在游戏开始前会被随机打乱。
  2. 初始翻牌

    • 玩家选择初始翻牌数量(例如 5 张),每翻一张牌需要支付 1 元。
  3. 许愿机制

    • 玩家从万子、条子、筒子中选择一个“许愿”种类。
    • 每当翻出的牌与许愿种类一致时,玩家可以多抽一张牌。
  4. 对子结算

    • 每当手牌中形成一个对子(两张相同的牌),对子会被移入结算池,并多抽一张牌。
    • 游戏结束时,结算池中的每个对子会为玩家带来 1 元收益。
  5. 游戏结束

    • 当牌堆被抽完或没有抽牌动作时,游戏结束。
    • 最终收益 = 对子数量 - 初始翻牌数量。

模拟实现

以下是使用 Python 实现的麻将对对碰游戏模拟程序:

import random

# 定义标准麻将牌堆(136张)
tiles = (
    ['万' + str(i) for i in range(1, 10)] * 4 +  # 万子
    ['条' + str(i) for i in range(1, 10)] * 4 +  # 条子
    ['筒' + str(i) for i in range(1, 10)] * 4 +  # 筒子
    ['东', '南', '西', '北'] * 4 +  # 风牌
    ['中', '发', '白'] * 4  # 箭牌
)

# 打乱牌堆
random.shuffle(tiles)

def draw_tiles(num_tiles, wish):
    drawn_tiles = []  # 当前手牌
    pairs = []  # 对子池
    total_money = -num_tiles  # 初始花费(每张牌花费1元)
    current_draw = num_tiles  # 当前需要抽的牌数

    while current_draw > 0 and tiles:
        # 抽一张牌
        tile = tiles.pop()
        drawn_tiles.append(tile)
        print(f"抽到: {tile}")
        current_draw -= 1

        # 检查是否与许愿种类一致
        if wish in tile:
            current_draw += 1
            print(f"许愿触发!多抽一张牌。")

        # 检查是否有对子
        for t in set(drawn_tiles):  # 遍历去重后的手牌
            if drawn_tiles.count(t) == 2:
                pairs.append(t)
                print(f"形成对子: {t}")
                # 移除对子
                drawn_tiles = [x for x in drawn_tiles if x != t]
                current_draw += 1

    # 计算获得的金额
    total_money += len(pairs)
    print("\n抽牌结束。")
    print(f"最终手牌: {drawn_tiles}")
    print(f"对子池: {pairs}")
    print(f"获得金额: {total_money}元")

# 输入初始翻牌数量和许愿选择
initial_draw = int(input("请输入初始翻牌数量: "))
# initial_draw = 10
wish_choice = input("请选择许愿种类(万、条、筒): ")
# wish_choice = "万"

# 开始游戏
draw_tiles(initial_draw, wish_choice)

运行程序,输入初始翻牌数量和许愿种类,程序会随机抽取指定数量的牌,以10和万子为例:

在这里插入图片描述

盈亏分析

从规则来看,许愿机制在重复游戏下对结果没什么影响,但是会对结果产生一些偶然影响。而初始翻牌数量显然会影响游戏的收益,这是因为初始翻牌数量越多,玩家的手牌越多,手牌越多,就越有可能形成对子,从而获得更多的收益,但初始投入的成本也会越多,我对初始翻牌与最终收益的关系感兴趣,通过一个1000次的模拟来分析一下,因为对子的个数最多是68个,所以初始翻牌的范围,设置在了1-68之间。

import random
# 初始抽牌价格
price = 1

def draw_tiles(num_tiles, wish):
    # 定义标准麻将牌堆(136张)
    tiles = (
        ['万' + str(i) for i in range(1, 10)] * 4 +  # 万子
        ['条' + str(i) for i in range(1, 10)] * 4 +  # 条子
        ['筒' + str(i) for i in range(1, 10)] * 4 +  # 筒子
        ['东', '南', '西', '北'] * 4 +  # 风牌
        ['中', '发', '白'] * 4  # 箭牌
    )
    # 打乱牌堆
    random.shuffle(tiles)
    drawn_tiles = []  # 当前手牌
    pairs = []  # 对子池
    total_money = -num_tiles*price  # 初始花费(每张牌花费1元)
    current_draw = num_tiles  # 当前需要抽的牌数

    while current_draw > 0 and tiles:
        # 抽一张牌
        tile = tiles.pop()
        drawn_tiles.append(tile)
        # print(f"抽到: {tile}")
        current_draw -= 1

        # 检查是否与许愿种类一致
        if wish in tile:
            current_draw += 1
            # print(f"许愿触发!多抽一张牌。")

        # 检查是否有对子
        for t in set(drawn_tiles):  # 遍历去重后的手牌
            if drawn_tiles.count(t) == 2:
                pairs.append(t)
                # print(f"形成对子: {t}")
                # 移除对子
                drawn_tiles = [x for x in drawn_tiles if x != t]
                current_draw += 1

    # 计算获得的金额
    total_money += len(pairs)
    return total_money

wish_price = 0

average_money = []  # 平均花费
simluation_times = 1000  # 模拟次数
# 输入初始翻牌数量和许愿选择
wish_choice = "条"
for initial_draw in range(1, 68):
    total_money = 0
    for _ in range(simluation_times):
        # 开始游戏
        total_money += draw_tiles(initial_draw, wish_choice)
    average_money.append(total_money / simluation_times - wish_price)

print(average_money)
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
plt.figure(figsize=(10, 6))
plt.plot(range(1, 60), average_money)
plt.xlabel('初始翻牌数量')
plt.ylabel('平均花费')
plt.title('麻将牌抽牌模拟')
plt.show()

从结果中可以看出,在1-40张牌的范围内,初始翻牌数量越多,平均收益上升,在40张牌的时候达到了最高,平均有25左右的收益,也就是说初始翻40张牌,配合许愿机制和对子奖励,几乎可以将整副麻将牌抽完。

在这里插入图片描述

进一步地,我想探究一下,如果将许愿机制单独拆分,这个许愿机制价值多少,这个许愿机制显然会影响到游戏的收益,但是这个许愿机制的价值似乎在初始抽牌不同的情况下价值不同,我们可以尝试将许愿机制的价值与初始抽牌数量的关系进行分析(就像期权价值的分析一样)。

先来构造一局无许愿的模拟:

# 不许愿模式
average_money1 = []  # 平均花费
simluation_times = 1000  # 模拟次数
# 输入初始翻牌数量和许愿选择
wish_choice = "无"
for initial_draw in range(1, 68):
    total_money = 0
    for _ in range(simluation_times):
        # 开始游戏
        total_money += draw_tiles(initial_draw, wish_choice)
    average_money1.append(total_money / simluation_times)


print(average_money)
plt.figure(figsize=(10, 6))
plt.plot(range(1, 68), average_money1)
plt.xlabel('初始翻牌数量')
plt.ylabel('无许愿平均花费')
plt.title('麻将牌抽牌模拟')
plt.show()

在这里插入图片描述

可以看出没有许愿机制的游戏,平均花费随着初始翻牌数量的增加,当达到30张时,平均花费达到了最高,随后几乎保持不变,在60张左右时,平均收益才有所上升。

然后通过有许愿的模拟减去无许愿的模拟,来分析许愿机制的价值:

wish_value = [i-j for i,j in zip(average_money, average_money1)]
plt.figure(figsize=(10, 6))
plt.plot(range(1, 68), wish_value)
plt.xlabel('初始翻牌数量')
plt.ylabel('许愿机制价值')
plt.title('麻将牌抽牌模拟')
plt.show()

在这里插入图片描述

从结果中可以看出,随着初始翻牌数量的增加,许愿机制的价值越来越高,还是在大约40张牌时,许愿机制的价值最高(达到了45左右),随后下降。

机制设计

有了这些分析,我们可以设计一些游戏机制来提高游戏的收益,作为游戏的制定方:

  • 初始翻牌价格:因为在初始翻牌数量为40时,平均收益最高,我们可以通过调增初始翻牌价格来提高游戏的收益(1+25/40=1.75),当初始翻牌价格设定为1.75时,作为游戏的制定方,几乎稳赚不赔(平均来看)
import random
# 初始抽牌价格
price = 1.75

def draw_tiles(num_tiles, wish):
    # 定义标准麻将牌堆(136张)
    tiles = (
        ['万' + str(i) for i in range(1, 10)] * 4 +  # 万子
        ['条' + str(i) for i in range(1, 10)] * 4 +  # 条子
        ['筒' + str(i) for i in range(1, 10)] * 4 +  # 筒子
        ['东', '南', '西', '北'] * 4 +  # 风牌
        ['中', '发', '白'] * 4  # 箭牌
    )
    # 打乱牌堆
    random.shuffle(tiles)
    drawn_tiles = []  # 当前手牌
    pairs = []  # 对子池
    total_money = -num_tiles*price  # 初始花费(每张牌花费1元)
    current_draw = num_tiles  # 当前需要抽的牌数

    while current_draw > 0 and tiles:
        # 抽一张牌
        tile = tiles.pop()
        drawn_tiles.append(tile)
        # print(f"抽到: {tile}")
        current_draw -= 1

        # 检查是否与许愿种类一致
        if wish in tile:
            current_draw += 1
            # print(f"许愿触发!多抽一张牌。")

        # 检查是否有对子
        for t in set(drawn_tiles):  # 遍历去重后的手牌
            if drawn_tiles.count(t) == 2:
                pairs.append(t)
                # print(f"形成对子: {t}")
                # 移除对子
                drawn_tiles = [x for x in drawn_tiles if x != t]
                current_draw += 1

    # 计算获得的金额
    total_money += len(pairs)
    return total_money

# 许愿模式要加10元
wish_price = 0

# 许愿模式
average_money = []  # 平均花费
simluation_times = 1000  # 模拟次数
# 输入初始翻牌数量和许愿选择
wish_choice = "条"
for initial_draw in range(1, 68):
    total_money = 0
    for _ in range(simluation_times):
        # 开始游戏
        total_money += draw_tiles(initial_draw, wish_choice)
    average_money.append(total_money / simluation_times - wish_price)

print(average_money)
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
plt.figure(figsize=(10, 6))
plt.plot(range(1, 68), average_money)
plt.xlabel('初始翻牌数量')
plt.ylabel('平均花费')
plt.title('麻将牌抽牌模拟')
plt.show()

在这里插入图片描述

  • 将许愿机制单独拆分:经过刚才的分析,许愿机制最多值45元,我们可以通过降低初始翻牌价格,但是需要额外的45元来购买许愿机制。分析此时的最低初始翻牌价格为多少。通过多次的模拟,得出最低初始翻牌价格约为0.56,此时平均最高收益也小于等于0。
import random
# 初始抽牌价格
price = 0.56

def draw_tiles(num_tiles, wish):
    # 定义标准麻将牌堆(136张)
    tiles = (
        ['万' + str(i) for i in range(1, 10)] * 4 +  # 万子
        ['条' + str(i) for i in range(1, 10)] * 4 +  # 条子
        ['筒' + str(i) for i in range(1, 10)] * 4 +  # 筒子
        ['东', '南', '西', '北'] * 4 +  # 风牌
        ['中', '发', '白'] * 4  # 箭牌
    )
    # 打乱牌堆
    random.shuffle(tiles)
    drawn_tiles = []  # 当前手牌
    pairs = []  # 对子池
    total_money = -num_tiles*price  # 初始花费(每张牌花费1元)
    current_draw = num_tiles  # 当前需要抽的牌数

    while current_draw > 0 and tiles:
        # 抽一张牌
        tile = tiles.pop()
        drawn_tiles.append(tile)
        # print(f"抽到: {tile}")
        current_draw -= 1

        # 检查是否与许愿种类一致
        if wish in tile:
            current_draw += 1
            # print(f"许愿触发!多抽一张牌。")

        # 检查是否有对子
        for t in set(drawn_tiles):  # 遍历去重后的手牌
            if drawn_tiles.count(t) == 2:
                pairs.append(t)
                # print(f"形成对子: {t}")
                # 移除对子
                drawn_tiles = [x for x in drawn_tiles if x != t]
                current_draw += 1

    # 计算获得的金额
    total_money += len(pairs)
    return total_money

# 许愿模式要加10元
wish_price = 45

# 许愿模式
average_money = []  # 平均花费
simluation_times = 1000  # 模拟次数
# 输入初始翻牌数量和许愿选择
wish_choice = "条"
for initial_draw in range(1, 68):
    total_money = 0
    for _ in range(simluation_times):
        # 开始游戏
        total_money += draw_tiles(initial_draw, wish_choice)
    average_money.append(total_money / simluation_times - wish_price)

print(average_money)
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
plt.figure(figsize=(10, 6))
plt.plot(range(1, 68), average_money)
plt.xlabel('初始翻牌数量')
plt.ylabel('平均花费')
plt.title('麻将牌抽牌模拟')
plt.show()

在这里插入图片描述

当然了,除了许愿机制,还可以更改游戏规则,比如许愿某一张牌,然后抽中了就可以多抽10张这样,当然可以像我这样进行分析。对每一个规则进行定价,虽然这是一个很简单的小游戏,但是可以看到资产定价的影子哈哈哈哈~ 分享一下我的分析过程,希望对你有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PD我是你的真爱粉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值