最近网上的萝卜纸巾猫大开门很火。主人会教猫咪辨识几件常见的物品,有:萝卜、纸巾、米老鼠、可乐等等。猫咪其实可能并不知道这些词语的意思,而是随机的乱摸这几个物品,有时候会摸错,主人也不会引导猫咪哪个是正确答案,就继续重复之前的口令,而猫咪则是继续随机尝试别的选项或者当前选项,如此重复一旦摸到了正确的物品,主人就会立即给猫咪喂食。
我们从这个灵感入手设计一款桌游,让玩家来模拟大开门猫这种又笨又察言观色的行为。玩家会通过抽取卡牌来模仿大开门猜测正确物品的过程,里面除了有像大开门撞运气的因素,也有运气管理的规划和玩法。在桌游领域这个机制叫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 第九联盟站点找我们试玩!如果可以来投票哈哈哈哈!!
这是我设计的卡牌初稿~


还在做卡牌和骰子。。
请勿剽窃,我们已经在摩点审核发布创意中。。