通过JavaScript看透彩票背后的随机算法javascript技巧

最近大抵是迷上彩票了,幻想着自己若能暴富,也可以带着家庭"鸡犬升天"了,不过事与愿违,我并没有冲天的气运,踏踏实实工作才是出路?

买彩票的时候,我也考虑了很久,到底怎么样的号码可以在1700万注中脱颖而出,随机试过,精心挑选的也试过,找规律的模式也试过,甚至我还用到了爬虫去统计数据,啼笑人非!

我们默认彩票系统是基于统计学来实现一等奖的开奖,那么历史以来的一等奖理所当然应该是当期统计率最低的一注,所以,最开始的时候我是这么想的:

天马行空,却也是自己发财欲望的一种发泄渠道罢了,称之为异想天开也不为过,扯了挺多,哈哈!

我们这里的彩票规则统一使用「双色球」的规则来说明,其购买的规则如下:

一等奖一般中全部购买的注里面挑选一注,这一注可能被多个人买,也有可能是一个人买了该注的倍数。

所以粗略统计,彩票的中奖几率计算公式如下所示:

使用组合数公式来计算,从n个元素中取k个元素的的组合数公式为:

C(kn)=n!k!(n?k)!C\binom{k}{n}=\frac{n!}{k!(n-k)!}C(nk)=k!(n?k)!n!

根据公式,我们可以很容易的写出来一个简单的算法:

functionfactorial(n){if(n===0||n===1){return1}else{returnn*factorial(n-1)}}functioncombination(n,k){returnfactorial(n)/(factorial(k)*factorial(n-k))}console.log(combination(33,6)*combination(16,1))//17721088所以可以得出的结论是,双色球头奖的中奖几率为:117721088\frac{1}{17721088}177210881

我们通过上面的算法得知了彩票的总注数为17721088,那么这么多注数字组成的数据到底有多大呢?

简单计算下,一注彩票可以用14个数字来表示,如01020304050607,那么在操作系统中,这串数字的大小为14B,那么粗略可知的是,如果所有的彩票注数都在一个文件中,那么这个文件的大小为:

consttotalSize=17721088*14/1024/1024//236.60205078125MB很恐怖的数量,有没有可能更小?我们研究一下压缩算法!

01这个数字在内存中的占用是两个字节,也就是2B,那如果我们把01用小写a代替,那么其容量就可以变成1B,总体容量可减少一半左右!

这样子的话,我们上面的一注特别牛的号码01020304050607就可以表示为abcdefg!

这就是压缩算法最最最基本的原理,压缩算法有很多种,大体分为有损压缩和无损压缩,对于我们数据类的内容来讲,我们一般都会选择无损压缩!

首先,让我们先准备一些测试数据,我们使用下面这个简单的组合数生成算法来获取出1000个组合数:

functiongenerateCombinations(arr,len,maxCount){letresult=[]functiongenerate(current,start){//如果已经生成的组合数量达到了最大数量,则停止生成if(result.length===maxCount){return}//如果当前已经生成的组合长度等于指定长度,则表示已经生成了一种组合if(current.length===len){result.push(current)return}for(leti=start;i

functiongetDoubleColorBall(count){//红球数组:['01','02'....'33']constarrRed=Array.from({length:33},(_,index)=>(index+1).toString().padStart(2,'0'))constarrRedResult=generateCombinations(arrRed,6,count)constresult=[]letblue=1arrRedResult.forEach(line=>{result.push(line.join('')+(blue++).toString().padStart(2,'0'))if(blue>16){blue=1}})returnresult}我们将获取的彩票内容放在文件中以便于下一步操作:

constfirstPrize=getDoubleColorBall(1000).join('')fs.writeFileSync('./hello.txt',firstPrize)这样子,我们就得到了第一版的文件,这是其文件大小:

试一下我们初步的压缩算法,我们将刚刚设定好的规则,也就是数字到字母的替换,用JavaScript实现出来,如下:

functioncompressHello(){constletters='abcdefghijklmnopqrstuvwxyzABCDEFG'constdoubleColorBallStr=getDoubleColorBall(1000).join('')letresultStr=''for(leti=0;i

如果按照这个算法的方法,我们能将之前的文件压缩至一半大小,也就是118.301025390625MB,但是这就是极限了吗?不,上面我们讲过,这只是最基本的压缩,接下来,让我们试试更精妙的方法!

这里我们需要了解的是,我们正在研究的是一个彩票系统,所以他的数据压缩应该具备以下几个特征:

常做前端的同学应该知道,我们在HTTP请求头里面常见的一个参数content-encoding:gzip,在项目的优化方面,也会选择将资源文件转换为gzip来进行分发。在日常的使用中,我们也时常依赖Webpack,Rollup等库,或者通过网络服务器如nginx来完成资源压缩,gzip不仅可以使得发送的内容大大减少,而且客户端可以无损解压访问源文件。

那么,我们能不能使用gzip来完成压缩呢?答案是可以,Node.js为我们提供了zlib工具库,提供了相应的压缩函数:

constzlib=require('zlib')constfirstPrize=compressHello()fs.writeFileSync('./hello-2.txt.gz',zlib.gzipSync(firstPrize))得到的结果是:

我们完成了14KB->3KB的压缩过程!是不是很有意思?不过还是那句话,有没有可能更小?当然可以!

content-encoding响应头一般是服务器针对返回的资源响应编码格式的设置信息,常见的值有以下三种:

浏览器支持的压缩格式不只是这些,不过我们列举出的是较为常用的,我们尝试使用一下这三种压缩格式:

constfirstPrize=compressHello()fs.writeFileSync('./hello-2.txt.gz',zlib.gzipSync(firstPrize))fs.writeFileSync('./hello-2.txt.def',zlib.deflateSync(firstPrize))fs.writeFileSync('./hello-2.txt.br',zlib.brotliCompressSync(firstPrize))我们可以看到,deflate和gzip的压缩率不相上下,令人惊喜的是,brotli的压缩竟然达到了惊人的1KB!这不就是我们想要的吗?

还可能更小吗?哈哈哈哈,当然,如果不考虑HTTP支持,我们完全可以使用如7-zip等压缩率更低的压缩算法去完成压缩,然后使用客户端做手动解压。不过点到为止,更重要的工作我们还没有做!

在这之前,我们需要先了解一下解压过程,如果解压后反而数据丢失,那就得不偿失了!

//执行解压操作constbrFile=fs.readFileSync('./hello-2.txt.br')constgzipFile=fs.readFileSync('./hello-2.txt.gz')constdeflateFile=fs.readFileSync('./hello-2.txt.def')constbrFileStr=zlib.brotliDecompressSync(brFile).toString()constgzipFileStr=zlib.gunzipSync(gzipFile).toString()constdeflateFileStr=zlib.inflateSync(deflateFile).toString()console.log(brFileStr)console.log(gzipFileStr)console.log(deflateFileStr)console.log(brFileStr===gzipFileStr,brFileStr===deflateFileStr)//true,true如上,我们知晓尽管压缩算法的效果很惊人,但是其解压后的数据依然是无损的!

让我们构建出完整的17721088注数据测试一下完整的压缩算法的能力如何?这里我们使用brotli和gzip算法分别进行压缩测试!

首先,应该修改我们生成数据的函数,如下:

functiongenerateAll(){constarrRed=Array.from({length:33},(_,index)=>(index+1).toString().padStart(2,'0'))constarrRedResult=generateCombinations(arrRed,6,Number.MAX_VALUE)constresult=[]arrRedResult.forEach(line=>{for(leti=1;i<=16;i++){result.push(line.join('')+i.toString().padStart(2,'0'))}})returnresult}console.log(generateAll().length)//17721088接下来我们要经过初步压缩并将其写入文件中:

functioncompressAll(){constletters='abcdefghijklmnopqrstuvwxyzABCDEFG'constallStr=generateAll().join('')letresultStr=''for(leti=0;i

consttotalSize=124047616/1024/1024//118.30102539MB目前来看是符合预期的,我们来看看两个压缩算法的真本事!

constfirstPrize=compressAll()fs.writeFileSync('./all-ball.txt.gz',zlib.gzipSync(firstPrize))fs.writeFileSync('./all-ball.txt.br',zlib.brotliCompressSync(firstPrize))

其实是很震惊的一件事情,尽管我对brotli的期待足够高,也不会想到他能压缩到仅仅4M大小,不过对于我们来说,这是一件幸事,对于之后的分发操作有巨大的优势!

从彩票站购买彩票的时候,随机来两注的行为是非常常见的,但是当你尝试随机号码的时候,会发生什么呢?

我们先从彩票数据的分发讲起,首先彩票数据的分发安全性和稳定性的设计肯定是毋庸置疑的,但是这不是我们目前需要考虑的问题,目前我们应该解决的是,如果才能更低程度的控制成本!

假设设计这套系统的人是你,如果控制随机号码的中奖率?我的答案是,从已有的号码池里面进行选择!

如果让每个彩票站获取到其对应的号码池,答:数据分发!如果采用数据分发的模式的话,需要考虑的问题如下:

据2021年公开信息,彩票站的数量已经达到20万家(未查证,无参考价值),我们假设目前的彩票站数量为30万家!

50万注的数据量有多大?试试看:

functiongetFirstSend(){constletters='abcdefghijklmnopqrstuvwxyzABCDEFG'constdoubleColorBallStr=getDoubleColorBall(500000).join('')letresultStr=''for(leti=0;i

解压示例如下:

functionletterToCode(letterStr){constresult=[]constletters='abcdefghijklmnopqrstuvwxyzABCDEFG'for(leti=0;i

按照这种模式的话,50万彩票站的数据同步在100秒内就可以完成,当然,诸位,这里是单机模式,如果做一个彩票服务的话,单机肯定是不可能的,想要提高TPS,那就做服务器集群,如果有100台服务器集群的话,处理这些请求仅仅需要1秒!(任性吗?有钱当然可以任性!)(这些数据的得出都是基于理论,不提供参考价值)

非常简单!我们需要获取的数据是哪一些呢?没有经过随机算法,直接被购买的彩票数据!也就是我们经常听到的"守号"的那些老彩民!

那么所有彩票站的总体客流量在100*500000=50000000,大约为五千万人次,大约有50%是属于"守号"人,这里面可能还需要排除掉彩票站中已知的号码,不过在这里我们先不处理,先做全部的预估,那么

服务器需要承载的最大TPS为:

所有的彩票数据当然不能全部都交给彩票站,我们需要对所有的数据做一个分层,其他彩票站"特意挑选的数据"就是我们要分层分发的数据!这样子也就能解决"如何避免所有数据被劫持"的问题!

那么我们如何对数据进行分层呢?

简而言之,就是我们将陕西西安彩票站的购票信息同步给山西太原,将上海市购票信息同步给江苏苏州!当然这里面需要考虑的点非常多,不仅仅是两地数据的交换,逻辑也比较复杂,通常需要考虑的点是:

就说这么多,说的多了其实我也不懂。或者说还没想出来,如果有这方面比较厉害的大佬,可以提供思路!我们先看看随机的号码结果如何:

我们来尝试随机获取你需要的两注:

functionrandom(count){letresult=[]for(leti=0;i

OK,你觉得可以中奖吗?哈哈哈,还是有可能的,继续往下看吧!

我是一个典型的"守号"人,每天都拿着自己算出来的几注号码,去购买彩票,那么我可以中奖吗?(目前没中)

根据上面的描述,我们应该知道,"守号"人购买的号码需要判断系统是否存在数据,如果存在的话,就不会触发上报,如果数据不存在,则会上报系统,由系统将当前号码分发给相邻市或数据近似的城市,预期当前号码可以被更多的人所购买,一注号码如果被购买的越多,其中奖的概率也就越低!

不过特意挑选是要比随机挑选的中奖概率要大,但是也大不到哪里去。

我们取50万注彩票,模拟一下这些彩票被购买的情况,可能会产生空号,可能会重复购买,或者购买多注等,尝试一下计算出我们需要付出的总金额!

彩票中中奖规则是这样子的,浮动奖项我们暂时不考虑,给一等奖和二等奖都赋予固定的金额:

根据这个规则,我们可以先写出对奖的函数:

/***@param{String[]}target['01','02','03','04','05','06','07']*@param{String[]}origin['01','02','03','04','05','06','07']*@returns{Number}返回当前彩票的中奖金额*/functioncompareToMoney(target,origin){letmoney=0letrightMatched=target[6]===origin[6]//求左边六位的交集数量letleftMatchCount=target.slice(0,6).filter(c=>origin.slice(0,6).includes(c)).lengthif(leftMatchCount===6&&rightMatched){money+=5000000}elseif(leftMatchCount===6&&!rightMatched){money+=300000}elseif(leftMatchCount===5&&rightMatched){money+=3000}elseif(leftMatchCount===5&&!rightMatched){money+=200}elseif(leftMatchCount===4&&rightMatched){money+=200}elseif(leftMatchCount===4&&!rightMatched){money+=10}elseif(leftMatchCount===3&&rightMatched){money+=10}elseif(leftMatchCount===2&&rightMatched){money+=5}elseif(leftMatchCount===1&&rightMatched){money+=5}elseif(rightMatched){money+=5}returnmoney}那么,应该如何得到利益最大化,步骤应该是这样子:

随机这个中奖号码非常重要,他决定着我们计算出整体数据的速度,所以我们按照下面的步骤进行获取:

先模拟出我们的购买数据:

functiongetRandomCode(count=500000){constarrRed=Array.from({length:33},(_,index)=>(index+1).toString().padStart(2,'0'))//generateCombinations是我们上面定义过的函数constarrRedResult=generateCombinations(arrRed,6,count)constresult=[]letblue=1arrRedResult.forEach(line=>{result.push([...line,(blue++).toString().padStart(2,'0')])if(blue>16){blue=1}})returnresult}functionrandomPurchase(){constcodes=getRandomCode()constresult=[]for(letcodeofcodes){letcount=Math.floor(Math.random()*50)result.push({code,count,})}returnresult}console.log(randomPurchase())我们将得到类似于下面的数据结构,这对于统计来说较为方便:

终归是黄粱一梦,最终还是要回归生活,好好工作!不过谁知道呢,等会再买一注如何?

THE END
1.62分钟了解:彩票算法及推算方法哔哩哔哩彩票算法及推算方法【+Aゞ李现Q:1438939】【惘: a9993.com】【惘:k9992.cc】〖金字招牌〗〖诚信至上〗【KY328:代发TG】〖信誉老台〗〖全网第一〗〖首存即送〗 人生如同一场旅程,每一步都充满了未知与挑战。面对困难时,不妨换个角度看待,用积极的心态去迎接每一天。珍惜身边的人,学会感恩那缠绵的爱情,那真https://www.bilibili.com/video/BV1mGzLYtEx7/
2.博彩中的数学模型乐彩网3. 凯利公式:这是一种用于确定每次投注应占本金比例的数学模型。凯利公式考虑了赢的概率和赔率,以及输的概率,帮助彩民找到最优的投注比例,以实现长期财富增长。 4. 动态规划模型:在某些复杂的数字三博彩游戏中,动态规划模型可以用来解决最优决策问题。例如,在摘花生问题中,动态规划模型被用来计算从起点到终点的所有https://3dx.17500.cn/art/skildetail/tid/11207378.html
3.图书详情题名/责任者: 玩转世界的十大公式 / (瑞典)戴维·森普特(David Sumpter)著 , 江天舒译 ISBN: 978-7-5217-5283-0 价格: CNY69.00 语种: 汉语 载体形态: 11,304页 : 图 ; 21cm 出版发行: 北京: 中信出版集团股份有限公司, 2023 内容提要: 本书共十章,内容包括:博彩公式、评价公式、置信公式、https://my1.hzlib.net/opac/book/2006559328
4.技术分析小学生数学必备公式换算法手册有庄的股是个宝,无庄的股是棵草。https://www.55188.com/thread-27872590-1-1.html
5.C++博弈论动态规划1563石子游戏V2087石头游戏c++想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版 https://download.csdn.net/download/he_zhidan/88348653 我想对大家说的话 闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 https://blog.csdn.net/he_zhidan/article/details/135886071
6.苏教版小学数学四年级下册总复习教案6篇(全文)学生分别在书上画一画,着重指导旋转:可以撕一个类似的图形旋转,更简单的,可以画一个类似图形,再旋转,最后把它画下来。 三、布置作业(略) 苏教版小学数学四年级下册总复习教案 第2篇 教学目标 1、从具体情境中体会学习圆锥体积公式的必要性并进行大胆猜想。 https://www.99xueshu.com/w/filezq82rnvs.html
7.当前速讯:d740动车一等卧铺图片d740动车实况网女生体脂率计算公式bmi_女生体脂率计算公式-环球百事通 2023-05-15 环球热议:旅游人才_关于旅游人才嘉实基金王贵重:人工智能三大要素是算法算力和数据 2023-05-09 勇士彻底完了?库里亲承球队内讧,普尔店主买下打错彩票中了30万 网友:吸吸欧气|环球快消息 2023-05-08 世界热消息:“强基计划”第四http://m.cqtimes.cn/news/yaowen/20230516/224980.html
8.供热比计算方法正算法中,锅炉总产热量公式为:C. 甲的贡献大,应获得该奖项之大部,同时按比例承担彩票购买款 D. 乙应获得该奖项,因乙是委托人 查看完整题目与答案 小娟用自己存的钱的一半买了计算机解决问题的方法和步骤,称为计算机算法 A. 正确 B. 错误 查看完整题目与答案 下列哪个不属于法律规范的特征 查看完整题目与答案 有的同学遭遇https://www.shuashuati.com/ti/fa50a394d33346ec9cec86e4e4b0f444a2.html
9.2024年图灵科技新书预告,技术人的必备技能,藏在每一本书里本书中,我们将学习各种新概念,如深度神经网络架构、计算机视觉、自然语言处理、产品化与部署和模型评估,内容涉及:如何利用修改后的数据集或模型来降低过拟合;如何处理深度神经网络训练中的常见随机性来源;如何在不改变模型架构或降低精度的情况下,通过优化加快模型推断速度;如何在实践中应用彩票机制假设和分布假设;如何使https://blog.51cto.com/u_15767091/10026356
10.线性概率模型(精选十篇)这样的教学导致学生应用意识不强,只知道套公式套方法解书上的习题,这叫读死书。线性代数与概率论(统计)是应用性很强的学科,它的生命力和发展动力在于它与其他学科的密切联系,没有了这种关系,线性代数与概率论(统计)就成了无源之水,无本之木,产生不出有意义的问题和方法[1]。如果在教学中,教师不让学生了解https://www.360wenmi.com/f/cnkeyu6utu8s.html
11.远离赌博(2):彩票复式算法,赔率怎么得出来的?足球复式就是每一场的三种结果*你投注的场数。如足球彩票就是3的14方。 3D或排列5,就是多少位数的最大值+1。 南粤风彩就是以最大号码36*35*34*33*32*31*30/7/6/5/4/3/2。公式N为最大值,L为开奖号码个数。N*(N-1)*(N-2)*(N-3)*(N-4)*(N-5)*(N-6)/L/(L-1)/(L-2)/(L-3http://www.360doc.com/content/20/0109/23/30562214_885314193.shtml
12.双色球中奖绝密公式大公开双色球中奖绝密公式大公开-阴阳五行推算法 周易预测学是一门信息科学,是中华民族聪明智慧的结晶。 在汉朝以董仲舒为代表的大儒门就曾经综述:“天地之气各有五,五行之次,一曰水,天数也;二曰火,地数也;三曰木,天数也;四曰金,地数也;五曰土,天数也”。此即赋予数学五行之性,与《易经》的思想是一致的。“一六为https://www.360doc.cn/article/3563948_246126462.html
13.BAT资深算法工程师《深度学习》读书分享:概率和信息论分享人:王奇文,资深算法工程师,曾在百度和阿里工作,先后做过推荐系统、分布式、数据挖掘、用户建模、聊天机器人。“算法路上,砥砺前行”。 「Deep learning」读书分享(三) —— 第三章 概率和信息论 接着第二章之后分享的是「深度学习」这本书https://mp.weixin.qq.com/s?__biz=MzA3NTIzMzIxNQ==&mid=2652796151&idx=1&sn=4be9594cadde935b7f9abc9c35c44f60&chksm=84997627b3eeff316ff12b85e3021eb960563912bbe7ef48916e6b6a2288dad15d9d70b60c61&scene=27
14.孩子逻辑混乱是数学不好的根本原因30本书帮孩子建立数理逻辑本书揭开趣味游戏、艺术设计和日常生活中的数学密码,通过新颖话题和精美图示展现算术与几何中隐藏的妙趣,从简单的数学原理走入算法的精彩世界,展现算法破解数学谜题的无穷威力。本书适合所有数学爱好者阅读。 适合10—13岁孩子的经典书籍 13、中国儿童数学百科全书 http://blog.youthmba.cn/archives/39300
15.万字重磅:未来10年财富游戏的金律与金线这种杠杆不是那么明显,它基本上属于对一级杠杆的游戏规则的认识和运用,例如算法、标签、平台的推荐机制、SEO技术、网络效应、零边际成本等等。 你自己做的产品,我也把它们归为这一类。例如,你在抖音上发的视频,你做的网课,你发售的电子书等等,它们也是杠杆,借助平台和网络的力量,可以放大传播,扩大收入。 https://www.douban.com/note/854226924/
16.数值计算方法Chapter8.常微分方程的数值解之前,Euler公式和Runge-Kutta方法都是直接对积分的值进行估计。 其中,Euler公式是直接令∫x+hxy′(t)dt=y′(x)h ,而Runge-Kutta方法则是通过引入一系列的偏移量使得y(x) 在n阶Taylor展开当中没有误差。 而线性多步法的近似思路则是用采用之前的插值公式的思路,来对y′(x) 来进行拟合,然后用这个拟合函数来https://cloud.tencent.com/developer/article/2079624