作者laechan (小太保)
看板X-Legend
标题[闲聊][幻想] 礼盒福袋程式写法推敲
时间Thu Oct 3 15:47:13 2013
http://ppt.cc/8cz8
这是网路随便找到的一张图,通常带机率的东西会用 mapping
的方式宣告
mapping box=([
"高级服饰附魔‧伤害x1" : a, // 假设开出机率 a%
"高级服饰附魔‧爆击x1" : b, // 假设开出机率 b%
"高级服饰附魔‧坚硬x1" : c, // 假设开出机率 c%
.
.
"HP治疗药剂x3" : z, // 假设开出机率 z%
]);
冒号 : 前面是可以开出的东西,keys(box) = 这些东西的集
合;冒号後面则是机率数字,假设用直观写法 10 = 10%,而
random(n) 代表随机跑出 0~n-1 之间的整数。
则有一点很明显: a < b < c < d < ..... < y < z
而且越底下的东西越好开,越上面的东西越难开。
根据自己的 coding 经验,我试着写了一个 box 并模拟开一
万次的结果如下
==========================================
高级服饰附魔‧伤害x1 : 11 组
高级服饰附魔‧爆击x1 : 18 组
高级服饰附魔‧坚硬x1 : 50 组
服饰附魔‧伤害x1 : 76 组
服饰附魔‧爆击x1 : 79 组
服饰附魔‧坚硬x1 : 209 组
源神能量光球(小)x3 : 186 组
幸运之证x1 : 179 组
怪物经验书x2 : 307 组
中级寻宝护符x2 : 159 组
高级寻宝护符x1 : 151 组
璀璨的经验秘石x3 : 206 组
源神经验结晶(中)x3 : 2805 组
未监定的源神徽纪宝箱x3 : 2763 组
HP治疗药剂x3 : 2801 组
========== 程式执行区 ====================
前 20 组结果大致如下
怪物经验书x2
HP治疗药剂x3
未监定的源神徽纪宝箱x3
未监定的源神徽纪宝箱x3
HP治疗药剂x3
服饰附魔‧爆击x1
未监定的源神徽纪宝箱x3
源神经验结晶(中)x3
未监定的源神徽纪宝箱x3
源神经验结晶(中)x3
HP治疗药剂x3
未监定的源神徽纪宝箱x3
HP治疗药剂x3
源神经验结晶(中)x3
未监定的源神徽纪宝箱x3
未监定的源神徽纪宝箱x3
源神经验结晶(中)x3
未监定的源神徽纪宝箱x3
未监定的源神徽纪宝箱x3
未监定的源神徽纪宝箱x3
那我是怎麽设计这个 box 的呢?我将宝盒里面 15 件物品分成
五组,每三个一组,最底下三个物品是「最好开的那一组」。
这是最直觉的想法,因为玩家开来开去,「总是开到那三个」。
其次,因为越上面的东西越难开,因此另一个直觉想法就是
for(i=0;i<15;i++)
j=j+random(2);
但通常除非运气好到爆跑 15 次都是 0 才会累加後为 0,也就
是开出第一个,不然第一个是几乎开不出来的。
但是这与现况不符(有人开过),而且搭配上面将物品分成五组
的想法,就变成如下
for(i=0;i<4;i++)
j=j+random(2);
j=j*3+random(4);
if(j>1) j=j-1;
上面的意思是说 j 的范围一样是 0~14,但是一开始是用五组
去分的,我用程式实测结果跑 10000 次约可跑出一千多次的「
开出第一组的机率」,机率是很高的。
但是再跑一次机率的话就不同了:
if(random(n)<box[keys_box[k]])
data[keys_box[k]]++;
else
{
k=12+random(3);
data[keys_box[k]]++;
}
上面的意思就是说 k 跑出 0~14 任一数字了,然後我定义了
每一组每一项物品的开出机率数字,例如第一组是 1,再用一
个 random(n) 去跑,比方说 n = 10:
if(random(10) < box[keys_box[k]])
随机跑出 0~9 比 第一组的数字1 还小 (所以机率是 1/10)
这样就跑出 keys_box[k] 这个东西(第一组的物品),反之,如
果随机跑出的数字比第一组的数字 1 还大,就跑「预设让玩家
开出的物品=最後一组任一物品」。
我写的这种箱子的特性如下
一、越上面的东西越难开,而且是非常难开
因为是机率x机率,第一个机率是指跑出哪一组,如上所示
跑出第一组的机率差不多是 1/10 其实这机率是很不错的,
但是「再机率的结果」就变成 1/10 x 1/10 = 1/100。
二、可是它又不是完全开不到
例如我的实测结果
高级服饰附魔‧伤害x1: 11 组 约 0.1%
高级服饰附魔‧爆击x1: 18 组 约 0.2%
高级服饰附魔‧坚硬x1: 50 组 约 0.5%
==============================
而实际情况因为多人在买(类似签乐透),每个人大概买个十
几到几十盒就能开到,因为物品只分五组、多人在买、在开
,有时人品好几盒就能开到。
三、最底下三个东西一定是最常开到的
例如大家对总是开到源神结晶、治疗药剂这类的一定印象深
刻。
写这个,有三个用意
一、劝世
真要拼,用招待券买一盒或少少几盒试试手气就好了,与其
每一期买 n 盒还不如每期买一两盒就好,它几乎每一期都会
出新的礼盒、宝盒等。
但基本上如果要做机关的话
if(是用招待券买的)
box->add("机率数字",-n); // 机率降低
甚至还可以跟你是否为 VIP 会员、是否在签约网咖上网、是
否是储值大户、....等等挂勾。
二、随便小小调整一个数字就能任意调整机率
这个通常最常用在农怪机率的调整上,但宝盒也是可以的,
比方它觉得怎麽才一天而已就被人开出十几双的翅膀背饰,
它是可以马上调整让玩家几乎是开不到的。
反过来说,如果它觉得虽然才半天、礼盒销了一两千个了怎
麽还没有人开到,「这样下去可不行」,就偷偷调一下机率
,这时买到并开礼盒的人就会爽到。
所以我是觉得早买晚买、早开晚开都一样,但是游戏官方也
可能为了刺激消费而一开始让机率较高,这是可能的,因为
有人开到就会贴炫耀文。
三、如果宝盒里面垃圾放很多,这种宝盒不要买
像某仙x传说的转蛋通常会塞一堆料理箱子或没啥路用的东
西,通常超过 6 个我就会说那种转蛋不值得买。
因为复合机率运算的结果就是那六个一定是最好开的,而且
「再机率运算的结果」如果你不符合取得机率,它又会绕回
「让你随机取得那六个其中一个」的结果,这怎麽看都是不
划算的。
底下是部份 code,实际礼盒的程式跟下面必定相差无几:
mapping box;
string msg="";
mixed keys_box=({});
box=([
"高级服饰附魔‧伤害x1" : 1,
"高级服饰附魔‧爆击x1" : 1,
"高级服饰附魔‧坚硬x1" : 1,
"服饰附魔‧伤害x1" : 2,
"服饰附魔‧爆击x1" : 2,
"服饰附魔‧坚硬x1" : 2,
"源神能量光球(小)x3" : 3,
"幸运之证x1" : 3,
"怪物经验书x2" : 3,
"中级寻宝护符x2" : 4,
"高级寻宝护符x1" : 4,
"璀璨的经验秘石x3" : 4,
"源神经验结晶(中)x3" : 5,
"未监定的源神徽纪宝箱x3" : 5,
"HP治疗药剂x3" : 5,
]);
keys_box=keys(box);
// 跑一万次
for(i=0;i<10000;i++)
{
k=0;
for(j=0;j<4;j++)
k=k+random(2);
k=k*3+random(4);
if(k>1) k=k-1;
if(random(15)<box[keys_box[k]])
data[keys_box[k]]++;
// 不符合机率的话一律开出最底下三个东西
else
{
k=12+random(3);
data[keys_box[k]]++;
}
}
for(i=0;i<15;i++)
msg+=sprintf("%-30s : %3d 组\n",keys_box[i],data[keys_box[i]]);
write(msg);
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 210.61.157.53
1F:推 aaa5566:可恶,看不懂 10/03 15:48
2F:→ ronlai:快推 虽然看不懂 10/03 15:49
3F:→ aaa5566:你没推啊!! 10/03 15:51
4F:推 ronlai:补推 科科 10/03 15:51
5F:推 zMidTwo5566:这一篇文章值 757 Ptt币 10/03 15:52
6F:推 Kmer:最常开到的是原神经验结晶(中) 10/03 15:53
7F:推 AFIAC:快推 不然人家以为我看不懂 10/03 15:54
8F:推 GoldenFinger:嗯 跟我想的差不多 10/03 15:56
9F:推 StinOAO:看的懂给推XD 10/03 15:56
10F:推 s963870:我曾经买个3包拿到9个能量球,这个写法我基本上是相信的 10/03 15:57
11F:推 Chantaljones:看不懂啦 10/03 15:58
12F:→ s963870:礼包机率虽能因节省网路设备成本而写成独立事件型机率 10/03 15:59
13F:→ s963870:但是因此而死的是消费者没错,这种转蛋跟MH的素材型 10/03 16:00
14F:推 howlongbing:看不懂给推 10/03 16:01
15F:→ s963870:差异甚远.. 甚至能说就是给你买乐透或送你一张发票 10/03 16:01
16F:→ s963870:依以前买MH包的经验,同样是转蛋素材却超好凑的... 10/03 16:02
17F:推 narcimeow:推,其实结论就是心情好买几包就好别太执着.. 10/03 16:02
18F:→ s963870:因为它让你至少开不到完整的也能开到材料去做 10/03 16:02
19F:→ s963870:材料取得甚至能从任务或活动获得.. 10/03 16:03
20F:→ s963870:而幻想的做法就是单纯机率,不论是活动跟礼包 10/03 16:03
21F:→ s963870:所有东西都是买了一开定生死这种除了逼你投资大量以外 10/03 16:05
22F:→ s963870:你不会有别的方式入手.. ,想用副本宝箱开手染? 10/03 16:06
23F:→ s963870:我可以跟你说开10000个开不到,这才是正常的情况 10/03 16:07
24F:→ s963870:因为数据跟机率告诉你就是如此 10/03 16:08
25F:→ laechan:可以开到啊, 开到「手染OX礼盒」→再拼一次机率 XD 10/03 16:14
26F:→ s963870:基本上这种看不到进度的东西,我花过一次钱就不会想再买了 10/03 16:17
27F:→ s963870:如果商城导致游戏的失衡,那麽这款游戏流失的会是大多数 10/03 16:18
28F:→ s963870:不会花大钱的平民等级玩家 10/03 16:19
29F:→ s963870:这款能玩的东西说实在的有点少.. 想投入就要更花钱 10/03 16:20
30F:推 skyitmexp:快推,这样不会被发现看不懂 10/03 16:28
31F:→ gangray:这篇文章简单一句话就是:机率,有钱你就去玩 10/03 16:32
32F:→ gangray:上面其他甚麽design随便看看就好 10/03 16:33
33F:推 ronlai:转蛋=机率*砸钱-读心 10/03 16:33
34F:→ gangray:就算知道method也不能改变机率就是如此这个事实 10/03 16:34
35F:→ s963870:但是这篇没有告诉你说买了10000包没中 10/03 16:34
36F:→ s963870:就独立机率来说 这是正常的结果 10/03 16:34
37F:→ gangray:如果说知道开福袋还会跟home连络,拦截封包解密他还有可能 10/03 16:35
38F:→ aaa5566:楼上小组长 戳戳 10/03 16:36
39F:推 ozlm0806:曾经买20包眼镜都抽垃圾,昨天招待卷买1包中橘色!我信了 10/03 16:41
40F:→ laechan:转蛋或福袋绝对不会套用「单纯的机率」这种做法去做的 10/03 16:43
41F:→ laechan:只有「最终看的是运气跟人品」这句话才是对的,但是其过程 10/03 16:44
42F:→ laechan:绝对不单纯,要很黑也可以很黑,这才是这篇文要讲的东西 10/03 16:44
43F:→ s963870:说真的我比较想知道打怪的额外掉宝加成是怎算的 10/03 16:46
一般来说有三种做法
1.加法堆叠: 机率直觉累加
比方 (100% + 3% + 4% + 5%) = 112%
2.乘法堆叠: 机率累乘, 可控制在一定范围
比方 100% x (100+3)% x (100+4)% + (100+5)% = 112.476%
3.混合堆叠: 比方为区别不同的效果(通常累乘优於累加)
比方 (100% + 3% + 4%) x (100 + 5%) = 112.35%
44F:→ s963870:礼包会用这种累加型的多面骰其实不是很意外 10/03 16:47
45F:推 sai0224sai:我真的觉得招待券的机率有比现金高 10/03 16:48
※ 编辑: laechan 来自: 210.61.157.53 (10/03 16:58)
46F:→ nrezw:不信拉 之前梭哈招待15包 只有三天版 10/03 16:53
47F:→ laechan:现金 15 包一堆源神, 招待 15 包还没干过, 嗯~ 说不定招待 10/03 16:59
48F:→ laechan:券反而较好, 毕竟现金只要储值就有, 招待券要屯得下功夫 10/03 17:00
49F:→ s963870:问题是怪有LOOT阿,一次只喷一个这样机率到底是差在哪? 10/03 17:01
以 RO 为例,假设某怪 LOOT = ([
"a物品": 30%,
"b物品": 10%,
"c物品": 1%,
]);
keys_loot = keys(LOOT);
j = sizeof(keys_loot);
k = 0;
for(i=0;i<j;i++)
{
if(random(100)<LOOT[keys_loot[i]])
{
掉落该物品;
k=k+1;
if(k >= 一定数量)
break; // 跳出回圈
}
}
这是最简单的写法,打怪通常一次掉一个东西的话,就是只要
掉落物品就立刻 break; 跳出回圈。
这样它所公布的机率(就是RO各大攻略网站可看到的)就确实是
物品的实际掉落机率,因为每一物品的掉落是独立的。
但是宝盒、礼盒、福袋、转蛋绝对不会这样写,因为这是官方
要拿来赚钱的,设定绝对不会如此单纯。
※ 编辑: laechan 来自: 210.61.157.53 (10/03 17:06)
50F:→ s963870:这样看来要刷装只能拚宝箱配护符 让LOOT多2多3而已 10/03 17:19
51F:→ s963870:幸运之证可以不用买.... 10/03 17:19
52F:推 c77110901:推个 我就知道是这样子 10/03 17:49
53F:推 arcss:恩恩...没错,跟我想的一样(点头) 10/03 17:51
54F:推 l85206605:招待卷真的比较好重!!!我两个源神都用招待卷抽的.... 10/03 17:58
55F:推 LayerZ:好累@@ 10/03 18:58
56F:推 beyblade5566:推一个以免别人认为我看不董 XDD 10/03 19:14
57F:→ herryherry:有没有懒人包XDDDD 10/03 21:23
58F:推 jack4019:这真的要推!! 10/03 21:58
59F:推 clickslither:懒人包就在文内啊,那个模拟一万次的结果 10/03 22:59
60F:→ clickslither:不过传奇转蛋的机率应该人性化一些,我投入不多,但抽 10/03 22:59
61F:→ clickslither:到前三样的机率还不低... 10/03 23:00
62F:推 Ekmund:你还蛮屌的... 10/04 01:31
63F:推 WinRARdotrar:换作是黑橘的话机关大概就用log函数做了XD 10/04 10:00