从萝卜纸巾猫到桌游:“蒸蚌大开门”的设计平衡之旅

最近网上的萝卜纸巾猫大开门很火。主人会教猫咪辨识几件常见的物品,有:萝卜、纸巾、米老鼠、可乐等等。猫咪其实可能并不知道这些词语的意思,而是随机的乱摸这几个物品,有时候会摸错,主人也不会引导猫咪哪个是正确答案,就继续重复之前的口令,而猫咪则是继续随机尝试别的选项或者当前选项,如此重复一旦摸到了正确的物品,主人就会立即给猫咪喂食。

我们从这个灵感入手设计一款桌游,让玩家来模拟大开门猫这种又笨又察言观色的行为。玩家会通过抽取卡牌来模仿大开门猜测正确物品的过程,里面除了有像大开门撞运气的因素,也有运气管理的规划和玩法。在桌游领域这个机制叫push your luck推送运气。

"蒸蚌大开门"的游戏玩法如下 :

每个玩家都会初始获得12张卡牌:4张空白牌、3张萝卜、2张纸巾、2张米老鼠、1张可乐。然后玩家中选一位暂替主人角色,扔骰子决定一个色样(骰子6面:2个萝卜2个纸巾1个米老鼠1个可乐)。每个玩家洗牌后抽取自身的卡牌直到骰子的色样为止,如果抽取卡牌到6张立即停止。然后结算环节,抽取次数n从1到6,分别奖赏6、4、3、2、1、-1个蒸蚌。同时惩罚为替换max(0,3-n)个卡牌为骰子的色样(只能从空白牌和除了骰子的色样的卡牌做替换)。然后到购物环节,可以用蒸蚌来购买换取卡牌,也可以购买换取功能卡牌。5轮次结束后计算蒸蚌最多者为胜利。

然后我们对于数值设计和骰子的设计有一些疑惑,于是我们让AI来写个程序,我们来看看数值如何定比较合理。

骰子设计我们在这三个方案里在纠结:[萝卜,纸巾,米老鼠,可乐] 为 [2,2,1,1]或者[3,1,1,1]或者[1,2,2,1]。首先萝卜设置为3面不太合理,后面萝卜会越来越多。主要在萝卜2还是1在纠结。萝卜取1的话,玩家一开始就可能要抽很多次才能结束第一轮,这样不方便玩家积累蒸蚌来优化手中的牌。萝卜取2的话,纸巾和米老鼠设置的概率就不一样。

蒸蚌奖励设置我们在三个方案里在纠结,抽取次数为n,从1到6次,对应奖赏为[6,4,3,2,1,-1]或者[5,4,3,2,1,0]或者[5,4,3,2,1,-1]。主要就是n=1的时候奖赏为6或者5,n=6的时候罚蒸蚌还是不罚。对于n=1,我们用6的考虑是想提升高风险高奖励的机制,用5是偏平缓。对于n=6情况,我们觉得还是必须要罚,不然玩家没有激励去优化手中的牌,反正不罚不奖随便抽这种情况不利于推动游戏。

骰子当然可以为了绝对公平用程序实现也可以,程序实现比较灵活,随着轮次增加,玩家抽到萝卜机率变少时能让主人要萝卜出现机率更少。这里为了交互形式统一,还是设计用骰子。

于是deepseek帮忙写了个程序,我们来看看怎么设置具体参数。

python 复制代码
import numpy as np

def simulate_one_game(initial_counts, reward_table, dice_probs, max_draw=6, trials=100000):
    items = ['carrot', 'tissue', 'mickey', 'cola', 'blank']
    total_score = 0
    for _ in range(trials):
        target = np.random.choice(['carrot', 'tissue', 'mickey', 'cola'], 
                                  p=[dice_probs['carrot'], dice_probs['tissue'], dice_probs['mickey'], dice_probs['cola']])
        deck = []
        for item in items:
            count = initial_counts[item]
            deck.extend([item] * count)
        np.random.shuffle(deck)
        drawn = 0
        found = False
        while drawn < max_draw:
            card = deck[drawn]
            drawn += 1
            if card == target:
                found = True
                break
        n = drawn
        if not found:
            n = max_draw
        total_score += reward_table[n]
    return total_score / trials

initial_counts = {'blank':4, 'carrot':3, 'tissue':2, 'mickey':2, 'cola':1}

# 骰子类型
dice_configs = {
    "2,2,1,1": {'carrot': 2/6, 'tissue': 2/6, 'mickey': 1/6, 'cola': 1/6},
    "3,1,1,1": {'carrot': 3/6, 'tissue': 1/6, 'mickey': 1/6, 'cola': 1/6},
    "1,2,2,1": {'carrot': 1/6, 'tissue': 2/6, 'mickey': 2/6, 'cola': 1/6},
    "1,1,1,3": {'carrot': 1/6, 'tissue': 1/6, 'mickey': 1/6, 'cola': 3/6},
}

# 奖励表
reward_tables = {
    "原始": [0, 6, 4, 3, 2, 1, -1],
    "平缓": [0, 5, 4, 3, 2, 1, 0],
    "高风险": [0, 7, 5, 3, 1, 0, -2],
    "倒挂": [0, 4, 3, 3, 2, 2, 1],
}

# 测试
print("不同骰子与奖励表下的平均得分(每轮)\n")
for reward_name, reward_table in reward_tables.items():
    print(f"--- {reward_name} 奖励表 ---")
    for dice_name, probs in dice_configs.items():
        avg = simulate_one_game(initial_counts, reward_table, probs, trials=200000)
        print(f"骰子 {dice_name}: {avg:.3f}")
    print()

这里设定了不同的骰子设定和奖励表,然后看各个玩家最后可以获得多少蒸蚌。

我们打开trae,优化一下程序:请你修改simulate_one_game,增设修正环节,抽中某个目标物品后的次数少于3次时 ,需要把max(0,3-n)个其他物品替换成目标物品(优先选择blank,但是每次替换最多一个blank)。

同时增加一个原始修正的奖励表,把6变成5,想看看结果。

python 复制代码
import numpy as np

def simulate_one_game(initial_counts, reward_table, dice_probs, max_draw=6, trials=100000):
    items = ['carrot', 'tissue', 'mickey', 'cola', 'blank']
    total_score = 0
    for _ in range(trials):
        target = np.random.choice(['carrot', 'tissue', 'mickey', 'cola'], 
                                  p=[dice_probs['carrot'], dice_probs['tissue'], dice_probs['mickey'], dice_probs['cola']])
        deck = []
        for item in items:
            count = initial_counts[item]
            deck.extend([item] * count)
        np.random.shuffle(deck)
        drawn = 0
        found = False
        while drawn < max_draw:
            card = deck[drawn]
            drawn += 1
            if card == target:
                found = True
                break
        n = drawn
        if not found:
            n = max_draw
        
        # 增设修正环节
        if found and n < 3:
            replace_count = 3 - n
            # 计算需要替换的物品数量,优先替换blank但每次最多一个blank
            blank_replace = 1 if replace_count > 0 else 0  # 最多替换一个blank
            other_replace = replace_count - blank_replace  # 剩下的替换其他非目标物品
            
            # 替换blank
            if blank_replace > 0:
                for i in range(len(deck)):
                    if deck[i] == 'blank' and deck[i] != target:
                        deck[i] = target
                        break
            
            # 替换其他非目标物品
            other_replaced = 0
            for i in range(len(deck)):
                if other_replaced >= other_replace:
                    break
                if deck[i] != target and deck[i] != 'blank':
                    deck[i] = target
                    other_replaced += 1
        
        total_score += reward_table[n]
    return total_score / trials

initial_counts = {'blank':4, 'carrot':3, 'tissue':2, 'mickey':2, 'cola':1}

# 骰子类型
dice_configs = {
    "2,2,1,1": {'carrot': 2/6, 'tissue': 2/6, 'mickey': 1/6, 'cola': 1/6},
    "3,1,1,1": {'carrot': 3/6, 'tissue': 1/6, 'mickey': 1/6, 'cola': 1/6},
    "1,2,2,1": {'carrot': 1/6, 'tissue': 2/6, 'mickey': 2/6, 'cola': 1/6},
    "1,1,1,3": {'carrot': 1/6, 'tissue': 1/6, 'mickey': 1/6, 'cola': 3/6},
}

# 奖励表
reward_tables = {
    "原始修正": [0, 5, 4, 3, 2, 1, -1],
    "原始": [0, 6, 4, 3, 2, 1, -1],
    "平缓": [0, 5, 4, 3, 2, 1, 0],
    "高风险": [0, 7, 5, 3, 1, 0, -2],
    "倒挂": [0, 4, 3, 3, 2, 2, 1],
}

# 测试
print("不同骰子与奖励表下的平均得分(每轮)\n")
for reward_name, reward_table in reward_tables.items():
    print(f"--- {reward_name} 奖励表 ---")
    for dice_name, probs in dice_configs.items():
        avg = simulate_one_game(initial_counts, reward_table, probs, trials=200000)
        print(f"骰子 {dice_name}: {avg:.3f}")
    print()

看看结果。

我们总体希望玩家拿的奖励即蒸蚌在2左右,所以排除高风险奖励表和原始修正奖励表。又因为n=6希望惩罚,最后选定原始奖励表 [0, 6, 4, 3, 2, 1, -1]。

至于骰子,我们决定折衷第一局[2,2,1,1] 后面选[1,2,2,1]。考虑是第一局希望能提高萝卜出现几率匹配玩家手中的牌,从第二局开始,减少萝卜和可乐的偏极端情况出现,因为如果骰子出现萝卜概率高 ,平均得分会较高(因为萝卜牌多),因为如果奖励表对 n=6 惩罚重 ,当骰子出可乐时容易输分,运气成分大。

这是我们整个设计的过程~ 欢迎大家2月1号16点-21点在2026 Game Jam 第九联盟站点找我们试玩!如果可以来投票哈哈哈哈!!

这是我设计的卡牌初稿~

还在做卡牌和骰子。。

请勿剽窃,我们已经在摩点审核发布创意中。。

相关推荐
悟纤2 小时前
Suno 爵士歌曲创作提示整理 | Suno高级篇 | 第22篇
大数据·人工智能·suno·suno ai·suno api·ai music
小北方城市网2 小时前
微服务注册中心与配置中心实战(Nacos 版):实现服务治理与配置统一
人工智能·后端·安全·职场和发展·wpf·restful
TracyCoder1232 小时前
Java String:从内存模型到不可变设计
java·算法·string
yl45302 小时前
污泥清淤机器人实践复盘分享
大数据·人工智能·机器人
码农丁丁2 小时前
第二十七篇 技术管理者自身的能力升级
人工智能·职场和发展·技术管理·ai时代的技术管理
想用offer打牌2 小时前
Spring AI Alibaba与 Agent Scope到底选哪个?
java·人工智能·spring
我是大咖2 小时前
二维数组与数组指针
java·数据结构·算法
筵陌2 小时前
算法:动态规划
算法·动态规划
大江东去浪淘尽千古风流人物2 小时前
【DSP】xiBoxFilter_3x3_U8 dsp VS cmodel
linux·运维·人工智能·算法·vr