利用JS實(shí)現(xiàn)搶紅包的三種算法
對于搶紅包來說最重要的就是隨機(jī)性算法,如何確保每個人獲得金額是趨向于平均的,也就是有平均的概率去隨機(jī),而盡量避免兩極分化。
就比如一般的隨機(jī)算法,假設(shè)有 100 元的紅包,有 10 個人去搶,第一個人去搶紅包的隨機(jī)范圍是(0, 100),一旦此人搶到足夠大的金額比如 90,剩下的 9 個人只能在不斷縮小的 10 以下的范圍隨機(jī),這樣的獎金范圍會很受限。也就是越前面搶的人優(yōu)勢越大。
接著需要說明搶紅包的核心規(guī)則:
- 每個人搶到的金額總和等于紅包金額
- 確保每個人得到最小的非零金額數(shù)
- 要保證隨機(jī)概率盡量分布均勻,避免存在可以通過技巧性鉆空子。
接著我們將使用 js 實(shí)現(xiàn)3種搶紅包的算法:
方法一:Math.random() 直接隨機(jī)
function getRandomMoney(totalMoney, totalPeople) { let remainMoney = totalMoney; let remainPeople = totalPeople; let result = []; for (let i = 1; i < totalPeople; i++) { let max = remainMoney - remainPeople + 1; let money = Math.random() * max; money = Math.floor(money * 100) / 100; result.push(money); remainMoney -= money; remainPeople--; } result.push(remainMoney); // 最后一個人搶剩下的錢 return result; } let totalMoney = 100; let totalPeople = 5; let result = getRandomMoney(totalMoney, totalPeople); console.log(result);
就像開篇提到的,先搶的優(yōu)勢很大。
對于隨機(jī)
random()
方法大家很熟悉,但方法返回一個大于等于 0 且小于 1 的偽隨機(jī)浮點(diǎn)數(shù),其實(shí)并不足夠隨機(jī),在足夠大的樣本下還是會呈現(xiàn)某種趨勢。
方法二:兩倍均值法
也就是 money = (0, M/N*2)
剩余紅包金額M,剩余人數(shù)N。
function getDoubleAverage(totalMoney, totalPeople) { let remainMoney = totalMoney; let remainPeople = totalPeople; let result = []; for (let i = 0; i < totalPeople - 1; i++) { let avg = remainMoney / remainPeople * 2; let money = Math.random() * avg; money = Math.floor(money * 100) / 100; result.push(money); remainMoney -= money; remainPeople--; } result.push(remainMoney); // 最后一個人搶剩下的錢 return result; } let totalMoney = 100; let totalPeople = 5; let result = getDoubleAverage(totalMoney, totalPeople); console.log(result);
這種方法等于每次搶紅包的最大范圍為人均的兩倍。但是有個問題,最后一次還是任意的隨機(jī)。這就意味著最后搶的人收益的風(fēng)險最高。
方法三:線段切割法
function getRandomMoney(total, num) { if (num === 1) { return total; } let max = total - 0.01 * num; let randomArr = [0, total]; for (let i = 1; i < num; i++) { let random = Math.random() * max; randomArr.push(random); } randomArr.sort((a, b) => a - b); let result = []; for (let j = 0; j < num; j++) { let money = (randomArr[j + 1] - randomArr[j]).toFixed(2); result.push(parseFloat(money)); } return result; } let totalMoney = 100; let totalPeople = 5; let moneyList = getRandomMoney(totalMoney, totalPeople); console.log(moneyList);
線段切割法在搶紅包等隨機(jī)分配場景中被認(rèn)為比較公平的原因主要是因為:線段切割法會將總金額分割成多個小段,然后隨機(jī)分配給每個人,確保了每個人獲得的金額相對均勻,避免了出現(xiàn)極端不公平的情況。
當(dāng)然這還存在一種可能分割點(diǎn)可能重復(fù),我們需要重新生成。
到此這篇關(guān)于利用JS實(shí)現(xiàn)搶紅包的三種算法的文章就介紹到這了,更多相關(guān)JS搶紅包算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Bootstrap教程JS插件滾動監(jiān)聽學(xué)習(xí)筆記分享
這篇文章主要為大家分享了Bootstrap教程JS插件滾動監(jiān)聽學(xué)習(xí)筆記,內(nèi)容很詳細(xì),感興趣的小伙伴們可以參考一下2016-05-05