前段时间办了一场论坛内的小型抽奖活动,让我再次想到了一直琢磨的一个问题:怎样的抽奖才是完善的抽奖呢,能够保证举办方和参与者都认同,降低暗箱操作的可能性呢。
先上结论,个人认为一个好的抽奖活动应该具备以下几点核心要素:
- 结果不可提前预知,也就是主办方和用户都无从知晓
- 结果可以复现,公布的抽奖结果必须能够按照既定算法复现
- 教育成本和操作流程不能太过复杂,最好能够自动化或者通过点击实现
几种典型的反面教材:
- 到了开奖时间或者开奖前,提前用某个骰子生成器抽几个出来,违背了结果不可复现
- 用压缩包加密压缩提前生成的楼层,先公布压缩包,开奖后公布密码,违背了结果不可提前预知(主办方知道中奖楼层)
- 用各种加密与秘钥交换算法生成一套算法出来,网站方与发帖人同时持有必须的秘钥之一,违背了成本/流程原则
其实在举办此活动之前,我一直想在论坛上直接加入抽奖功能,流程上大概是主题帖可以选择性附加一个抽奖活动,设定奖池大小/奖品数目/开奖时间等,然后论坛帮忙完成后续的自动化流程即可。但是思来想去总是没有好的方案出来,期间也搜索了一些现有的方案逛了逛知乎和v2ex寻找灵感,终究是不能得偿所愿。最后能想到的办法要么教育用户其原理所需的成本太高(原理复杂讲不清),要么流程过于复杂。
逛LES论坛发现了一个很不错的抽奖方法,稍加改造就用到了本次活动中,讲一下原理背景及操作流程:
熵联盟
由Cloudflare、洛桑联邦理工学院(EPFL)、智利大学、Kudelski Security等众多权威机构主导的一个去中心化的随机信标(random beacon),根据一系列复杂的技术原理保证随机的可靠性,对原理感兴趣的可以点击这个扩展阅读。这个随机信标每30s生成一个随机字符串,大概长这样:
afa0dd948208c2f1d0ee62c3f121d60d6e702576544815118f1639d165cfc593
你可以访问https://api.drand.sh/来获取任意周期(每30s一个周期)的随机信标结果,具体的开发者手册见这里。我们知道在随机取样过程中,虽然取样算法各有不同,但是只要保证所用伪随机数的种子一样,那么取样结果就是固定的。
诶嘿,你发现了没有,这个随机信标就很适合当随机种子呀。剩下的事情就简单了,我们只需要获取开奖时刻所在周期的随机信标作为随机种子,然后用一个公开的抽样算法来取样就可以了。Cloudflare Beacon还有个优点是可以查询任何历史周期的随机信标结果,保证了你抽奖之后任何时间回头检查都可以知道有没有作弊。
随机取样过程
取样算法的设计就比较多了,一般都是自己固定一套流程出来,保证可以复现就行了。为了偷懒我用了random.org的随机取样器,他也是支持用户输入随机种子的:
这里注意,整个取样过程实际上是个全排列过程,比方说到截止时间共有233个楼层,则生成1-233楼层的一个全排列,主办方根据自己的规定依次校核结果序列中每个楼层是否符合要求,比如去掉重复发帖和格式不符等等,这样就可以得到最终的中奖人员。
简单的自动化js脚本
讲了这么多其实就是一句话,用CF Beacon做随机种子,然后对楼层做全排列依次校核中奖人员即可。
那么有没有简化流程的全自动js脚本呢,应该是比较好写的,这里举个例子,读者可以根据自己的要求改动:
let openTime = 'Fri Dec 02 2022 12:00:00 GMT+0800 (China Standard Time)' // 开奖时间
let maxFloor = 233 // 最大楼层
let beaconRound = (new Date(openTime).getTime() / 1000 - 1595431050) / 30
const MAINCHAIN = '8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce'
let beaconUrl = `https://api.drand.sh/${MAINCHAIN}/public/${beaconRound}`
fetch(beaconUrl)
.then(r => r.json())
.then(r => {
let seed = r.randomness
let randomOrgUrl = `https://www.random.org/sequences/?min=1&max=${maxFloor}&col=1&format=plain&rnd=id.${seed}`
return fetch(randomOrgUrl)
.then(r => r.text())
.then(r => {
console.log(`中奖楼层为${r.replace(/\n/g, ', ')}`)
})
})
花里胡哨,净整些没用的
@仙风 #5
沙发
@chenmo #1 来了啊~坐坐坐
快记笔记学习一个!
围观.支持楼主做成本论坛插件
@pony #3 哈哈哈好的,需求+1
怎么抽奖不重要,重要的是我能不能抽中
不管那么多有奖就行
早就写过了,搞那么复杂不如自定义方便
http://0755.tk/DrawLots.php
虽然看不懂,但是很厉害的样子,都中奖~