欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

通過JavaScript看透彩票背后的隨機(jī)算法

 更新時(shí)間:2023年06月07日 09:41:19   作者:Emo_TT  
這篇文章主要介紹了如何通過JavaScript看透彩票背后的隨機(jī)算法,真實(shí)的彩票系統(tǒng)不是這么開發(fā)出來的,也不具備明面上的規(guī)律,我們應(yīng)該相信彩票的公正性,盡管其可能不是基于隨機(jī),感興趣的朋友可以參考閱讀下

雜談

最近大抵是迷上彩票了,幻想著自己若能暴富,也可以帶著家庭"雞犬升天"了,不過事與愿違,我并沒有沖天的氣運(yùn),踏踏實(shí)實(shí)工作才是出路?

買彩票的時(shí)候,我也考慮了很久,到底怎么樣的號(hào)碼可以在1700萬注中脫穎而出,隨機(jī)試過,精心挑選的也試過,找規(guī)律的模式也試過,甚至我還用到了爬蟲去統(tǒng)計(jì)數(shù)據(jù),啼笑人非!

我們默認(rèn)彩票系統(tǒng)是基于統(tǒng)計(jì)學(xué)來實(shí)現(xiàn)一等獎(jiǎng)的開獎(jiǎng),那么歷史以來的一等獎(jiǎng)理所當(dāng)然應(yīng)該是當(dāng)期統(tǒng)計(jì)率最低的一注,所以,最開始的時(shí)候我是這么想的:

  • 獲取歷史以來所有的中獎(jiǎng)彩票號(hào)碼

  • 使用代碼去統(tǒng)計(jì)出所有號(hào)碼的中獎(jiǎng)次數(shù)

  • 按照出現(xiàn)幾率最低的數(shù)字來排序

  • 依次組成某幾注新號(hào)碼

天馬行空,卻也是自己發(fā)財(cái)欲望的一種發(fā)泄渠道罷了,稱之為異想天開也不為過,扯了挺多,哈哈!

上面的思路我已經(jīng)實(shí)踐過了,用了差不多一年的時(shí)間,沒有用!別用!當(dāng)然你也可以試試,如果你中了,恭喜,你才是天選之人!

彩票的規(guī)則

我們這里的彩票規(guī)則統(tǒng)一使用「雙色球」的規(guī)則來說明,其購買的規(guī)則如下:

  • 紅球?yàn)榱?,選項(xiàng)從 1 - 33 中挑選,不可重復(fù)

  • 藍(lán)球?yàn)橐晃?,選項(xiàng)從 1 - 16 中挑選

  • 紅藍(lán)雙色球一共七位組成一注

一等獎(jiǎng)一般中全部購買的注里面挑選一注,這一注可能被多個(gè)人買,也有可能是一個(gè)人買了該注的倍數(shù)。

所以粗略統(tǒng)計(jì),彩票的中獎(jiǎng)幾率計(jì)算公式如下所示:

使用組合數(shù)公式來計(jì)算,從n個(gè)元素中取k個(gè)元素的的組合數(shù)公式為:

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

根據(jù)公式,我們可以很容易的寫出來一個(gè)簡單的算法:

function factorial(n) {
  if (n === 0 || n === 1) {
    return 1
  } else {
    return n * factorial(n - 1)
  }
}
function combination(n, k) {
  return factorial(n) / (factorial(k) * factorial(n - k))
}
console.log(combination(33, 6) * combination(16, 1)) // 17721088

所以可以得出的結(jié)論是,雙色球頭獎(jiǎng)的中獎(jiǎng)幾率為: 117721088\frac{1}{17721088}177210881

數(shù)據(jù)量

我們通過上面的算法得知了彩票的總注數(shù)為 17721088,那么這么多注數(shù)字組成的數(shù)據(jù)到底有多大呢?

簡單計(jì)算下,一注彩票可以用14個(gè)數(shù)字來表示,如 01020304050607,那么在操作系統(tǒng)中,這串?dāng)?shù)字的大小為 14B,那么粗略可知的是,如果所有的彩票注數(shù)都在一個(gè)文件中,那么這個(gè)文件的大小為:

const totalSize = 17721088 * 14 / 1024 / 1024 // 236.60205078125MB

很恐怖的數(shù)量,有沒有可能更小?我們研究一下壓縮算法!

01這個(gè)數(shù)字在內(nèi)存中的占用是兩個(gè)字節(jié),也就是 2B,那如果我們把 01 用小寫 a 代替,那么其容量就可以變成 1B,總體容量可減少一半左右!

這樣子的話,我們上面的一注特別牛的號(hào)碼 01020304050607 就可以表示為 abcdefg !

這就是壓縮算法最最最基本的原理,壓縮算法有很多種,大體分為有損壓縮和無損壓縮,對(duì)于我們數(shù)據(jù)類的內(nèi)容來講,我們一般都會(huì)選擇無損壓縮!

  • 有損壓縮算法:這些算法能夠在壓縮數(shù)據(jù)時(shí)丟棄一些信息,但通常能在不影響實(shí)際使用的前提下實(shí)現(xiàn)更高的壓縮比率,其中最常見的是圖像、音頻和視頻壓縮算法
  • 無損壓縮算法:這些算法不會(huì)丟棄任何信息,它們通過查找輸入數(shù)據(jù)中的重復(fù)模式,并使用更短的符號(hào)來表示它們來實(shí)現(xiàn)壓縮。無損壓縮算法常用于文本、代碼、配置文件等類型的數(shù)據(jù)

首先,讓我們先準(zhǔn)備一些測試數(shù)據(jù),我們使用下面這個(gè)簡單的組合數(shù)生成算法來獲取出1000個(gè)組合數(shù):

function generateCombinations(arr, len, maxCount) {
  let result = []
  function generate(current, start) {
    // 如果已經(jīng)生成的組合數(shù)量達(dá)到了最大數(shù)量,則停止生成
    if (result.length === maxCount) {
      return
    }
    // 如果當(dāng)前已經(jīng)生成的組合長度等于指定長度,則表示已經(jīng)生成了一種組合
    if (current.length === len) {
      result.push(current)
      return
    }
    for (let i = start; i < arr.length; i++) {
      current.push(arr[i])
      generate([...current], i + 1)
      current.pop()
    }
  }
  generate([], 0)
  return result
}

接下來,我們需要生成 1000 注雙色球,紅球是從 1 - 33 中取組合數(shù),藍(lán)球是從 1 - 16 中依次取數(shù)

function getDoubleColorBall(count) {
  // 紅球數(shù)組:['01', '02' .... '33']
  const arrRed = Array.from({ length: 33 }, (_, index) => (index + 1).toString().padStart(2, '0'))
  const arrRedResult = generateCombinations(arrRed, 6, count)
  const result = []
  let blue = 1
  arrRedResult.forEach(line => {
    result.push(line.join('') + (blue++).toString().padStart(2, '0'))
    if (blue > 16) {
      blue = 1
    }
  })
  return result
}

我們將獲取的彩票內(nèi)容放在文件中以便于下一步操作:

const firstPrize = getDoubleColorBall(1000).join('')
fs.writeFileSync('./hello.txt', firstPrize)

這樣子,我們就得到了第一版的文件,這是其文件大?。?/p>

試一下我們初步的壓縮算法,我們將剛剛設(shè)定好的規(guī)則,也就是數(shù)字到字母的替換,用 JavaScript 實(shí)現(xiàn)出來,如下:

function compressHello() {
  const letters = 'abcdefghijklmnopqrstuvwxyzABCDEFG'
  const doubleColorBallStr = getDoubleColorBall(1000).join('')
  let resultStr = ''
  for (let i = 0; i < doubleColorBallStr.length; i+=2) {
    const number = doubleColorBallStr[i] + doubleColorBallStr[i+1]
    resultStr += letters[parseInt(number) - 1]
  }
  return resultStr
}
const firstPrize = compressHello()
fs.writeFileSync('./hello-1.txt', firstPrize)

這樣我們就得到了一個(gè)全新的 hello 文件,他的大小如下所示,正好印證了我們的想法!

如果按照這個(gè)算法的方法,我們能將之前的文件壓縮至一半大小,也就是 118.301025390625MB,但是這就是極限了嗎?不,上面我們講過,這只是最基本的壓縮,接下來,讓我們?cè)囋嚫畹姆椒ǎ?/p>

更精妙的方法

這里我們不對(duì)壓縮算法的原理做過多的解釋,如果諸位感興趣的話,可以自己尋找類似的文章閱讀,鑒于網(wǎng)上的文章質(zhì)量參差不齊,我就不做推薦了!

這里我們需要了解的是,我們正在研究的是一個(gè)彩票系統(tǒng),所以他的數(shù)據(jù)壓縮應(yīng)該具備以下幾個(gè)特征:

  • 具備數(shù)據(jù)不丟失的特性,也就是無損壓縮

  • 壓縮率盡可能小,因?yàn)閭鬏數(shù)奈募赡芊浅4螅缥覀兩厦媾e的例子

  • 便于信息的傳輸,也就是支持HTTP請(qǐng)求

常做前端的同學(xué)應(yīng)該知道,我們?cè)?HTTP 請(qǐng)求頭里面常見的一個(gè)參數(shù) content-encoding: gzip,在項(xiàng)目的優(yōu)化方面,也會(huì)選擇將資源文件轉(zhuǎn)換為 gzip 來進(jìn)行分發(fā)。在日常的使用中,我們也時(shí)常依賴 Webpack,Rollup 等庫,或者通過網(wǎng)絡(luò)服務(wù)器如 nginx 來完成資源壓縮,gzip 不僅可以使得發(fā)送的內(nèi)容大大減少,而且客戶端可以無損解壓訪問源文件。

那么,我們能不能使用 gzip 來完成壓縮呢?答案是可以,Node.js 為我們提供了 zlib 工具庫,提供了相應(yīng)的壓縮函數(shù):

const zlib = require('zlib')
const firstPrize = compressHello()
fs.writeFileSync('./hello-2.txt.gz', zlib.gzipSync(firstPrize))

得到的結(jié)果是:

我們完成了 14KB -> 3KB 的壓縮過程!是不是很有意思?不過還是那句話,有沒有可能更???當(dāng)然可以!

content-encoding 響應(yīng)頭一般是服務(wù)器針對(duì)返回的資源響應(yīng)編碼格式的設(shè)置信息,常見的值有以下三種:

  • gzip 所有瀏覽器都支持的通用壓縮格式

  • brotli 比 gzip 壓縮性能更好,壓縮率更小的一個(gè)新的壓縮格式,老版本瀏覽器不支持

  • deflate 出于某些原因,使用不是很廣泛,后有基于該算法的 zlib 壓縮格式,不過也使用度不高

瀏覽器支持的壓縮格式不只是這些,不過我們列舉出的是較為常用的,我們嘗試使用一下這三種壓縮格式:

const firstPrize = 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的壓縮竟然達(dá)到了驚人的 1KB ! 這不就是我們想要的嗎?

還可能更小嗎?哈哈哈哈,當(dāng)然,如果不考慮HTTP支持,我們完全可以使用如 7-zip 等壓縮率更低的壓縮算法去完成壓縮,然后使用客戶端做手動(dòng)解壓。不過點(diǎn)到為止,更重要的工作我們還沒有做!

在這之前,我們需要先了解一下解壓過程,如果解壓后反而數(shù)據(jù)丟失,那就得不償失了!

// 執(zhí)行解壓操作
const brFile = fs.readFileSync('./hello-2.txt.br')
const gzipFile = fs.readFileSync('./hello-2.txt.gz')
const deflateFile = fs.readFileSync('./hello-2.txt.def')
const brFileStr = zlib.brotliDecompressSync(brFile).toString()
const gzipFileStr = zlib.gunzipSync(gzipFile).toString()
const deflateFileStr = zlib.inflateSync(deflateFile).toString()
console.log(brFileStr)
console.log(gzipFileStr)
console.log(deflateFileStr)
console.log(brFileStr === gzipFileStr, brFileStr === deflateFileStr) // true, true

如上,我們知曉盡管壓縮算法的效果很驚人,但是其解壓后的數(shù)據(jù)依然是無損的!

完整的數(shù)據(jù)

讓我們構(gòu)建出完整的 17721088 注數(shù)據(jù)測試一下完整的壓縮算法的能力如何?這里我們使用 brotli 和 gzip 算法分別進(jìn)行壓縮測試!

首先,應(yīng)該修改我們生成數(shù)據(jù)的函數(shù),如下:

function generateAll() {
  const arrRed = Array.from({ length: 33 }, (_, index) => (index + 1).toString().padStart(2, '0'))
  const arrRedResult = generateCombinations(arrRed, 6, Number.MAX_VALUE)
  const result = []
  arrRedResult.forEach(line => {
    for (let i = 1; i <= 16; i++) {
      result.push(line.join('') + i.toString().padStart(2, '0'))
    }
  })
  return result
}
console.log(generateAll().length) // 17721088

接下來我們要經(jīng)過初步壓縮并將其寫入文件中:

function compressAll() {
  const letters = 'abcdefghijklmnopqrstuvwxyzABCDEFG'
  const allStr = generateAll().join('')
  let resultStr = ''
  for (let i = 0; i < allStr.length; i += 2) {
    const number = allStr[i] + allStr[i+1]
    resultStr += letters[parseInt(number) - 1]
  }
  return resultStr
}
const firstPrize = compressAll()
fs.writeFileSync('./all-ball.txt', firstPrize)

正如我們預(yù)料的,經(jīng)過初步壓縮之后,文件大小達(dá)到了大約 118MB,但是其實(shí)際占用 124MB,是屬于計(jì)算機(jī)存儲(chǔ)的范疇,我們現(xiàn)在不在本篇文章中討論,感興趣的同學(xué)可以自己查一查,根據(jù)字節(jié)數(shù)計(jì)算,其大小為:

const totalSize = 124047616 / 1024 / 1024 // 118.30102539 MB

目前來看是符合預(yù)期的,我們來看看兩個(gè)壓縮算法的真本事!

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

其實(shí)是很震驚的一件事情,盡管我對(duì) brotli 的期待足夠高,也不會(huì)想到他能壓縮到僅僅 4M 大小,不過對(duì)于我們來說,這是一件幸事,對(duì)于之后的分發(fā)操作有巨大的優(yōu)勢!

隨機(jī)來兩注

從彩票站購買彩票的時(shí)候,隨機(jī)來兩注的行為是非常常見的,但是當(dāng)你嘗試隨機(jī)號(hào)碼的時(shí)候,會(huì)發(fā)生什么呢?

我們先從彩票數(shù)據(jù)的分發(fā)講起,首先彩票數(shù)據(jù)的分發(fā)安全性和穩(wěn)定性的設(shè)計(jì)肯定是毋庸置疑的,但是這不是我們目前需要考慮的問題,目前我們應(yīng)該解決的是,如果才能更低程度的控制成本!

假設(shè)設(shè)計(jì)這套系統(tǒng)的人是你,如果控制隨機(jī)號(hào)碼的中獎(jiǎng)率?我的答案是,從已有的號(hào)碼池里面進(jìn)行選擇!

如果讓每個(gè)彩票站獲取到其對(duì)應(yīng)的號(hào)碼池,答:數(shù)據(jù)分發(fā)!如果采用數(shù)據(jù)分發(fā)的模式的話,需要考慮的問題如下:

  • 什么時(shí)候進(jìn)行分發(fā)

  • 數(shù)據(jù)回源如何做

  • 如何避免所有數(shù)據(jù)被劫持

  • 數(shù)據(jù)交給彩票站的策略

據(jù)2021年公開信息,彩票站的數(shù)量已經(jīng)達(dá)到20萬家(未查證,無參考價(jià)值),我們假設(shè)目前的彩票站數(shù)量為 30 萬家!

什么時(shí)候進(jìn)行分發(fā)

我們知道的是,彩票的購買截止時(shí)間是在晚上八點(diǎn),開獎(jiǎng)時(shí)間是在晚上的九點(diǎn)十五,在晚上八點(diǎn)之后,我們只能購買到下一期的彩票,那么這個(gè)節(jié)點(diǎn)應(yīng)該從晚上的八點(diǎn)開始,計(jì)劃是這樣子的:

  • 從目前已有的彩票庫里面,按照號(hào)碼出現(xiàn)幾率從高到低排列

  • 挑選出前50萬注分發(fā)給 30 萬彩票站,這個(gè)時(shí)間彩票站的數(shù)據(jù)都是統(tǒng)一的

  • 每個(gè)小時(shí)同步一次數(shù)據(jù),同步的是其他彩票站"特意挑選的數(shù)據(jù)"

50萬注的數(shù)據(jù)量有多大?試試看:

function getFirstSend() {
  const letters = 'abcdefghijklmnopqrstuvwxyzABCDEFG'
  const doubleColorBallStr = getDoubleColorBall(500000).join('')
  let resultStr = ''
  for (let i = 0; i < doubleColorBallStr.length; i+=2) {
    const number = doubleColorBallStr[i] + doubleColorBallStr[i+1]
    resultStr += letters[parseInt(number) - 1]
  }
  return resultStr
}
const firstPrize = getFirstSend()
fs.writeFileSync('./first-send.txt.br', zlib.brotliCompressSync(firstPrize))

僅一張圖片的大小,獲取這些數(shù)據(jù)解壓同步到彩票機(jī)時(shí)間不足1s!

解壓示例如下:

function decodeData(brFile) {
  const result = []
  const content = zlib.brotliDecompressSync(brFile)
  // 按照七位每注的結(jié)構(gòu)拆分
  for (let i = 0; i < content.length; i += 7) {
    result.push(content.slice(i, i + 8))
  }
  return result
}
const firstSend = fs.readFileSync('./first-send.txt.br')
const firstDataList = decodeData(firstSend)
console.log(firstDataList.length) // 500000

如何將獲取到的字符形式的彩票轉(zhuǎn)換為數(shù)字,如 abcdefga 轉(zhuǎn)換為 ['01', '02', '03', '04', '05', '06, '01']

function letterToCode(letterStr) {
  const result = []
  const letters = 'abcdefghijklmnopqrstuvwxyzABCDEFG'
  for (let i = 0; i < letterStr.length; i++) {
    result.push((letters.indexOf(letterStr[i]) + 1).toString().padStart(2, '0'))
  }
  return result
}

至于分發(fā)?我們可以參考一下市面上已有的一些概念做一下對(duì)比,下面是籠統(tǒng)的一個(gè)網(wǎng)絡(luò)服務(wù)器的TPS預(yù)估值,也就是說彩票服務(wù)器在1秒內(nèi)可以處理的最大請(qǐng)求數(shù):

  • 低性能:TPS 在 50 以下,適用于低流量的應(yīng)用場景,例如個(gè)人博客、小型企業(yè)網(wǎng)站等。
  • 中性能:TPS 在 50~500 之間,適用于一般的網(wǎng)站和應(yīng)用場景,例如中小型電商網(wǎng)站、社交網(wǎng)絡(luò)等。
  • 高性能:TPS 在 500~5000 之間,適用于高流量的網(wǎng)站和應(yīng)用場景,例如大型電商網(wǎng)站、游戲網(wǎng)站等。
  • 超高性能:TPS 在 5000 以上,適用于超高流量的網(wǎng)站和應(yīng)用場景,例如互聯(lián)網(wǎng)巨頭的網(wǎng)站、在線游戲等。

 按照這種模式的話,50萬彩票站的數(shù)據(jù)同步在100秒內(nèi)就可以完成,當(dāng)然,諸位,這里是單機(jī)模式,如果做一個(gè)彩票服務(wù)的話,單機(jī)肯定是不可能的,想要提高TPS,那就做服務(wù)器集群,如果有100臺(tái)服務(wù)器集群的話,處理這些請(qǐng)求僅僅需要 1 秒!(任性嗎?有錢當(dāng)然可以任性!)(這些數(shù)據(jù)的得出都是基于理論,不提供參考價(jià)值)

數(shù)據(jù)回源如何做

非常簡單!我們需要獲取的數(shù)據(jù)是哪一些呢?沒有經(jīng)過隨機(jī)算法,直接被購買的彩票數(shù)據(jù)!也就是我們經(jīng)常聽到的"守號(hào)"的那些老彩民!

同樣,根據(jù)媒體查詢得知(不做參考),彩票站的客流量是每小時(shí)1至10人,經(jīng)營時(shí)間,早上九點(diǎn)至晚上九點(diǎn),最大客流量預(yù)計(jì)為100人每天!

那么所有彩票站的總體客流量在 100 * 500000 = 50000000,大約為五千萬人次,大約有50%是屬于"守號(hào)"人,這里面可能還需要排除掉彩票站中已知的號(hào)碼,不過在這里我們先不處理,先做全部的預(yù)估,那么

服務(wù)器需要承載的最大TPS為:

// 服務(wù)器集群數(shù)量
const machineCount = 100
// 總訪問量,50%中的號(hào)碼才會(huì)上報(bào)
const totalVisit = 50000000 * 0.5 // 25000000
// 總的時(shí)間,因?yàn)槲覀冇?jì)算的是 10個(gè)小時(shí)的時(shí)間,所以應(yīng)該計(jì)算的總秒數(shù)為 36000 秒!
const totalSeconds = 10 * 60 * 60
console.log(totalVisit / totalSeconds / machineCount) // 6.944444444444445

TPS僅為7?。∵@還是沒有排除掉已經(jīng)知悉的號(hào)碼的情況,具體的上報(bào)邏輯,參考下圖:

數(shù)據(jù)交給彩票站的策略(避免數(shù)據(jù)被劫持)

所有的彩票數(shù)據(jù)當(dāng)然不能全部都交給彩票站,我們需要對(duì)所有的數(shù)據(jù)做一個(gè)分層,其他彩票站"特意挑選的數(shù)據(jù)"就是我們要分層分發(fā)的數(shù)據(jù)!這樣子也就能解決 "如何避免所有數(shù)據(jù)被劫持" 的問題!

那么我們?nèi)绾螌?duì)數(shù)據(jù)進(jìn)行分層呢?

簡而言之,就是我們將陜西西安彩票站的購票信息同步給山西太原,將上海市購票信息同步給江蘇蘇州!當(dāng)然這里面需要考慮的點(diǎn)非常多,不僅僅是兩地?cái)?shù)據(jù)的交換,邏輯也比較復(fù)雜,通常需要考慮的點(diǎn)是:

  • 數(shù)據(jù)同步難度,跨地區(qū)同步對(duì)服務(wù)器壓力巨大,如華南向華北同步
  • 數(shù)據(jù)相似程度,兩地的數(shù)據(jù)如果歷史以來相似度區(qū)別很大,反而不能達(dá)到覆蓋的目的,因?yàn)槲覀冏罱K是想要這注號(hào)碼被購買更多次
  • 數(shù)據(jù)同步時(shí)差,如新疆等地,鑒于網(wǎng)絡(luò)問題,比其他地要慢很多的情況,這樣就會(huì)漏號(hào),那么就應(yīng)該把這些地方的數(shù)據(jù)同步到更繁華的區(qū)域,如上海市,但是這一點(diǎn)看似是和第一二點(diǎn)相悖的

就說這么多,說的多了其實(shí)我也不懂?;蛘哒f還沒想出來,如果有這方面比較厲害的大佬,可以提供思路!我們先看看隨機(jī)的號(hào)碼結(jié)果如何:

我們來嘗試隨機(jī)獲取你需要的兩注:

function random(count) {
  let result = []
  for (let i = 0; i < count; i++) {
    const index = Math.floor(Math.random() * firstDataList.length)
    console.log(firstDataList[index])
    result.push(letterToCode(firstDataList[index]))
  }
  return result
}
console.log(random(2))

OK,你覺得可以中獎(jiǎng)嗎?哈哈哈,還是有可能的,繼續(xù)往下看吧!

特意挑的兩注

我是一個(gè)典型的"守號(hào)"人,每天都拿著自己算出來的幾注號(hào)碼,去購買彩票,那么我可以中獎(jiǎng)嗎?(目前沒中)

根據(jù)上面的描述,我們應(yīng)該知道,"守號(hào)"人購買的號(hào)碼需要判斷系統(tǒng)是否存在數(shù)據(jù),如果存在的話,就不會(huì)觸發(fā)上報(bào),如果數(shù)據(jù)不存在,則會(huì)上報(bào)系統(tǒng),由系統(tǒng)將當(dāng)前號(hào)碼分發(fā)給相鄰市或數(shù)據(jù)近似的城市,預(yù)期當(dāng)前號(hào)碼可以被更多的人所購買,一注號(hào)碼如果被購買的越多,其中獎(jiǎng)的概率也就越低!

不過特意挑選是要比隨機(jī)挑選的中獎(jiǎng)概率要大,但是也大不到哪里去。

我要一等獎(jiǎng)

彩票的一等獎(jiǎng)是基于統(tǒng)計(jì)的,即使彩票中心存在空號(hào),也需要考慮空號(hào)所產(chǎn)生的二等獎(jiǎng)至六等獎(jiǎng)的數(shù)量,這是一個(gè)非常龐大的數(shù)據(jù)量,也是需要計(jì)算非常多的時(shí)間的,那么我們?nèi)绾文M呢?

我們?nèi)?0萬注彩票,模擬一下這些彩票被購買的情況,可能會(huì)產(chǎn)生空號(hào),可能會(huì)重復(fù)購買,或者購買多注等,嘗試一下計(jì)算出我們需要付出的總金額!

彩票中中獎(jiǎng)規(guī)則是這樣子的,浮動(dòng)獎(jiǎng)項(xiàng)我們暫時(shí)不考慮,給一等獎(jiǎng)和二等獎(jiǎng)都賦予固定的金額:

  • 6 + 1 一等獎(jiǎng) 獎(jiǎng)金500萬

  • 6 + 0 二等獎(jiǎng) 獎(jiǎng)金30萬

  • 5 + 1 三等獎(jiǎng) 獎(jiǎng)金3000元

  • 5 + 0 或 4 + 1 四等獎(jiǎng) 獎(jiǎng)金200元

  • 4 + 0 或 3 + 1 五等獎(jiǎng) 獎(jiǎng)金10元

  • 2 + 1 或 1 + 1 或 0 + 1 都是 六等獎(jiǎng) 獎(jiǎng)金 5 元

根據(jù)這個(gè)規(guī)則,我們可以先寫出對(duì)獎(jiǎng)的函數(shù):

/**
 * @param {String[]} target ['01', '02', '03', '04', '05', '06', '07']
 * @param {String[]} origin ['01', '02', '03', '04', '05', '06', '07']
 * @returns {Number} 返回當(dāng)前彩票的中獎(jiǎng)金額
 */
function compareToMoney(target, origin) {
  let money = 0
  let rightMatched = target[6] === origin[6]
  // 求左邊六位的交集數(shù)量
  let leftMatchCount = target.slice(0, 6).filter(
    c => origin.slice(0,6).includes(c)
  ).length
  if (leftMatchCount === 6 && rightMatched) {
    money += 5000000
  } else if (leftMatchCount === 6 && !rightMatched) {
    money += 300000
  } else if (leftMatchCount === 5 && rightMatched) {
    money += 3000
  } else if (leftMatchCount === 5 && !rightMatched) {
    money += 200
  } else if (leftMatchCount === 4 && rightMatched) {
    money += 200
  } else if (leftMatchCount === 4 && !rightMatched) {
    money += 10
  } else if (leftMatchCount === 3 && rightMatched) {
    money += 10
  } else if (leftMatchCount === 2 && rightMatched) {
    money += 5
  } else if (leftMatchCount === 1 && rightMatched) {
    money += 5
  } else if (rightMatched) {
    money += 5
  }
  return money
}

那么,應(yīng)該如何得到利益最大化,步驟應(yīng)該是這樣子:

  • 隨機(jī)生成一組中獎(jiǎng)號(hào)碼

  • 對(duì)于每個(gè)購買的數(shù)字,檢查是否與中獎(jiǎng)號(hào)碼匹配,并計(jì)算它的獎(jiǎng)金金額

  • 對(duì)于所有購買的數(shù)字的獎(jiǎng)金金額進(jìn)行求和

  • 重復(fù)這個(gè)過程,直到找到最優(yōu)的中獎(jiǎng)號(hào)碼

隨機(jī)這個(gè)中獎(jiǎng)號(hào)碼非常重要,他決定著我們計(jì)算出整體數(shù)據(jù)的速度,所以我們按照下面的步驟進(jìn)行獲?。?/p>

  • 將所有的號(hào)碼按照購買數(shù)量進(jìn)行排序(其實(shí)這里真實(shí)的場景應(yīng)該聯(lián)合考慮中獎(jiǎng)號(hào)碼的分布趨勢才更精確)

  • 從空號(hào)開始查詢,依次進(jìn)行計(jì)算

先模擬出我們的購買數(shù)據(jù):

function getRandomCode(count = 500000) {
  const arrRed = Array.from({ length: 33 }, (_, index) => (index + 1).toString().padStart(2, '0'))
  // generateCombinations 是我們上面定義過的函數(shù)
  const arrRedResult = generateCombinations(arrRed, 6, count)
  const result = []
  let blue = 1
  arrRedResult.forEach(line => {
    result.push([...line, (blue++).toString().padStart(2, '0')])
    if (blue > 16) {
      blue = 1
    }
  })
  return result
}
function randomPurchase() {
  const codes = getRandomCode()
  const result = []
  for (let code of codes) {
    let count = Math.floor(Math.random() * 50)
    result.push({
      code,
      count,
    })
  }
  return result
}
console.log(randomPurchase())

我們將得到類似于下面的數(shù)據(jù)結(jié)構(gòu),這對(duì)于統(tǒng)計(jì)來說較為方便:

[
  {
    code: [
      '01', '02',
      '03', '04',
      '05', '10',
      '05'
    ],
    count: 17
  },
  {
    code: [
      '01', '02',
      '03', '04',
      '05', '11',
      '06'
    ],
    count: 4
  }
]

接下來,就是很簡單的統(tǒng)計(jì)了,邏輯很簡單,但對(duì)于數(shù)據(jù)量極為龐大的彩票來說,需要的時(shí)間!

// 空號(hào)在前,購買數(shù)量越多越靠后
const purchaseList = randomPurchase().sort((a, b) => a.count - b.count)
const bonusPool = []
for (let i = 0; i < purchaseList.length; i++) {
  // 假設(shè)這就是一等獎(jiǎng),那么就需要計(jì)算其價(jià)值
  const firstPrize = purchaseList[0]
  let totalMoney = 0
  for (let j = 0; j < purchaseList.length; j++) {
    // 與一等獎(jiǎng)進(jìn)行對(duì)比,對(duì)比規(guī)則是參照彩票中獎(jiǎng)規(guī)則
    const money = compareToMoney(purchaseList[j].code, firstPrize.code) * purchaseList[j].count
    totalMoney += money
  }
  bonusPool.push({
    code: firstPrize.code,
    totalMoney,
  })
}
const result = bonusPool.sort((a, b) => a.totalMoney - b.totalMoney)
// 至于怎么挑,那就隨心所欲了
console.log(result[0].code, result[0].totalMoney)

至于最后的一等獎(jiǎng)怎么挑,那就隨心所欲了,不過上面的算法在我的 M1 芯片計(jì)算需要的時(shí)間也將近10分鐘,如果有更強(qiáng)大的機(jī)器,更厲害的算法,這個(gè)時(shí)長同樣可以縮短,不展開了,累了,就這樣吧!

黃粱一夢

終歸是黃粱一夢,最終還是要回歸生活,好好工作!不過誰知道呢,等會(huì)再買一注如何?

彩票系統(tǒng)純屬臆測,不可能有雷同!

以上就是通過JavaScript看透彩票背后的隨機(jī)算法的詳細(xì)內(nèi)容,更多關(guān)于JavaScript 彩票隨機(jī)算法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • javascript 模塊依賴管理的本質(zhì)深入詳解

    javascript 模塊依賴管理的本質(zhì)深入詳解

    這篇文章主要介紹了javascript 模塊依賴管理,結(jié)合實(shí)例形式深入分析了javascript 模塊依賴管理具體定義、實(shí)現(xiàn)方法及注意事項(xiàng),需要的朋友可以參考下
    2020-04-04
  • 深入了解JavaScript中的new關(guān)鍵字

    深入了解JavaScript中的new關(guān)鍵字

    手寫new是JS面試題高頻考點(diǎn),實(shí)現(xiàn)代碼也非常簡單,但在實(shí)現(xiàn)后小編對(duì)其為什么要這樣設(shè)計(jì)有著很深的疑惑,今天就來講一下為什么要這樣設(shè)計(jì)new的實(shí)現(xiàn)吧
    2023-05-05
  • stats.js使用性能監(jiān)控源碼解讀

    stats.js使用性能監(jiān)控源碼解讀

    這篇文章主要為大家介紹了stats.js使用性能監(jiān)控源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • JavaScript實(shí)現(xiàn)星座查詢功能 附詳細(xì)代碼

    JavaScript實(shí)現(xiàn)星座查詢功能 附詳細(xì)代碼

    最近小編在做一個(gè)項(xiàng)目,其中涉及到一個(gè)模塊關(guān)于星座查詢功能,即在文本框中輸入一個(gè)生日值,點(diǎn)擊按鈕可以得到對(duì)應(yīng)的星座,怎么實(shí)現(xiàn)這個(gè)需求呢?下面小編通過示例代碼給大家介紹下,需要的朋友參考下吧
    2021-11-11
  • JavaScript中Function與Object的關(guān)系

    JavaScript中Function與Object的關(guān)系

    本文主要介紹了JavaScript中Function與Object的關(guān)系,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • js獲取當(dāng)前頁的URL與window.location.href簡單方法

    js獲取當(dāng)前頁的URL與window.location.href簡單方法

    下面小編就為大家?guī)硪黄猨s獲取當(dāng)前頁的URL與window.location.href簡單方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02
  • 主頁面中的兩個(gè)iframe實(shí)現(xiàn)鼠標(biāo)拖動(dòng)改變其大小

    主頁面中的兩個(gè)iframe實(shí)現(xiàn)鼠標(biāo)拖動(dòng)改變其大小

    iframe實(shí)現(xiàn)鼠標(biāo)拖動(dòng)改變其大小在一個(gè)頁面中的兩個(gè)iframe的情況下,此方法相當(dāng)實(shí)用,感興趣的各位不妨參考下,或許對(duì)你有所幫助
    2013-04-04
  • 為JavaScript添加重載函數(shù)的輔助方法

    為JavaScript添加重載函數(shù)的輔助方法

    大家都習(xí)慣了重載帶來的便利。JavaScript有沒有重載呢?有人會(huì)回答沒有,因?yàn)楹瘮?shù)會(huì)被覆蓋;有人說有,我們可以模擬重載這 一操作。
    2010-07-07
  • 實(shí)例講解避免javascript沖突的方法

    實(shí)例講解避免javascript沖突的方法

    這篇文章主要以實(shí)例的方式講解了避免javascript沖突的方法,具有一定的參考價(jià)值,感興趣的朋友可以參考一下
    2016-01-01
  • javascript文件中引用依賴的js文件的方法

    javascript文件中引用依賴的js文件的方法

    在一個(gè)js文件中如果需要引入另外所依賴的js文件,可以在一個(gè)js文件中導(dǎo)入如下代碼即可
    2014-03-03

最新評(píng)論