当前位置: 首页 > article >正文

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

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

麻将对对碰是一种基于麻将牌的趣味游戏,结合了抽牌、许愿和对子结算的机制。本文将介绍游戏规则,并通过 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张这样,当然可以像我这样进行分析。对每一个规则进行定价,虽然这是一个很简单的小游戏,但是可以看到资产定价的影子哈哈哈哈~ 分享一下我的分析过程,希望对你有所帮助。


http://www.kler.cn/a/549890.html

相关文章:

  • 【系列专栏】银行IT的云原生架构-云单元架构 12
  • Apache Struts2 - 任意文件上传漏洞 - CVE-2024-53677
  • 大数据预处理中的数据清洗策略
  • SpringBoot 的核心只有几张图
  • 区块链可投会议CCF B--ICNP 2025 截止5.16 附2023录用率
  • GO语言中的结构体struct
  • 核货宝外贸订货系统:批发贸易企业出海的强劲东风
  • 开源AI智能名片2+1链动模式S2B2C商城小程序在社交价值挖掘中的应用与策略研究
  • KT1025A蓝牙音频芯片FM收音机的AT指令串口部分举例说明
  • 【ISO 14229-1:2023 UDS诊断全量测试用例清单系列:第十五节】
  • 【云安全】云原生-K8S(三) 安装 Dashboard 面板
  • Endnote使用笔记——持续更新
  • 如何在 Docker 环境中将宿主机的文件复制到容器目录
  • (5/100)每日小游戏平台系列
  • Session的学习
  • 图像分割与 Watershed 算法:原理、Python 实现与.NET 实现
  • 关于go-context包
  • C#控制台大小Console.SetWindowSize函数失效解决
  • elementui: el-dialog的header设置样式不生效
  • 【C++】使用gdb在命令行下调试C++程序(二)