zhjx922 De Blog

北京小客车摇号程序PHP版

相信很多北京本地or北漂一族摇了N年车牌号的人大有人在,作为一个即将加入摇号大军的程序员,带着好奇心查看了一下摇号相关的规则和程序,是否公平公正公开公…

官方信息

温馨提示:摇号月的25日,在公证人员的公证下,工作人员按规则为审核通过的编码分配摇号基数序号,形成摇号池编码数据文件,并刻盘封存,将参与26日的摇号。26日摇号结束后,请您注意查询是否中签,中签后凭打印的“小客车配置指标确认通知书”办理购车手续。
特别说明:
1、摇号基数序号分配方法:首先,将当期所有审核通过的编码按从小到大的顺序分配序号;然后,第二阶梯及以上的编码按从小到大的顺序,接在后面继续分配序号;再然后,第三阶梯及以上的编码按从小到大的顺序,接在后面继续分配序号;以此类推。因此,高阶梯的编码所对应的多个摇号基数序号是不连号的,当期摇号基数序号总数=第一阶梯人数+第二阶梯人数×2+第三阶梯人数×3……
2、摇号方法:摇号程序从当期所有摇号基数序号中随机抽取中签者,高阶梯的编码对应多个摇号基数序号,于是享受了多倍的中签概率。摇号程序确保高阶梯编码的多个摇号基数序号最多只能摇中一个,当其中一个摇号基数序号中签,该编码即中签。

解读

1、摇号月的25日会将所有摇号的数据存放到数据文件(一个csv文件集合的压缩包,后面会提到,这个是我们写摇号程序的关键数据)
2、摇号月的26日会摇出一个6位的随机数(这个是用来计算中签的关键)
3、第几阶梯就会为对应阶梯的人分配几个摇号基础序号,比如A现在是第三阶梯,B是第二阶梯,C是第一阶梯,那么对应的排序就为ABCABA(123456)

官方摇号程序

为了公平公正,官方提供了可执行的摇号程序,已经对应摇号期数的摇号数据提供了下载。

摇号程序

温馨提示了我们Windows7操作系统,系统应当安装有.NET Framework 2.0,既然是.NET,那我们就反编译一下,看看到底是怎么计算的~

反编译

使用反编译工具ILSPY,直接搞定,我们会发现源程序是C#写的,关键代码放在AllRandomPick.cs中,其中最关键的两句为:

1
2
Random random = new Random(allRandomPickData.Seed);
pickNumber = random.Next(allRandomPickData.TotalNumber);

Random为C#自带的随机函数
allRandomPickData.Seed 表示6位随机种子数
allRandomPickData.TotalNumber 表示摇号池编码数

这么看来,如果确保随机种子数是随机的话,这个算法可以认为是”绝对”公平的。
如果作弊的话,一是控制随机种子数,二是伪造摇号编码插入到对应的位置。
从此看来,大家还是乖乖摇号或者买新能源吧。。。

提取C#随机数类

官方虽然提供了C#版的摇号程序,但是作为世界上最好的语言PHP怎能不尝试一下呢?

从之前的文章 自己实现随机数,我们不难发现,如果随机种子的固定的话,那么我们产生的随机数也是固定的。

但是不同语言的随机数实现方法是不同的,我们要向实现C#版的random,就必须知道C#纠结是如何生成随机数的。

感谢微软开源(不开源的话,可能没法用PHP实现了),让我轻松的找到了对应的实现方法 https://github.com/dotnet/coreclr/blob/32f0f9721afb584b4a14d69135bea7ddc129f755/src/mscorlib/src/System/Random.cs

既然已经有了源代码,我们只要将C#翻译成PHP就可以了。

分析压缩包

官方提供了每期的压缩包,我们解压之后,能够看到一堆的文件列表,随便打开一个A列代表了当前的基础序号,B列代表了对应的摇号编码,如果随机到的基础序号对应的是你的编码,那么,就该恭喜你了。

PHP实现

随机类有了,只要使用随机种子初始化随机类,然后在总编码数范围内随机,next…next…直到全部指标分配完就可以了,代码我放到了 github 上,有兴趣的小伙伴可以阅读原文查看。

再放个最终的运行结果:

摇号程序

到官网上验证一下:

摇号程序

摇号越久就越容易中么?

不是,虽然你的倍数一直在增加,但是和你一起摇的人的倍数也在增加,后面加入的人也越来越多,毕竟指标数在变得越来越少。

真的没办法提高概率了么?

有,比如下方二维码试试

zhjx922 wechat
欢迎关注二维码,一起交流学习!