Skip to content

Instantly share code, notes, and snippets.

@mahpah
Created April 29, 2021 06:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mahpah/23ed4033dc877c1df6cb4c3de2bd8523 to your computer and use it in GitHub Desktop.
Save mahpah/23ed4033dc877c1df6cb4c3de2bd8523 to your computer and use it in GitHub Desktop.
import crypto from 'crypto';
import fs from 'fs';
import path from 'path';
const startingPrize = 30000;
const prizes = [0.7, 0.15, 0.1, 0.05];
const price = 2;
const ranHex = (length: number) => {
return crypto
.randomBytes(Math.ceil(length / 2))
.toString('hex')
.slice(0, length);
};
const genRand = (max: number) => {
const hex = ranHex(64);
return parseInt('0x' + hex.substr(0, 8)) % max;
};
const tryRand = (n: number, max: number, maxPowerBall: number) => {
const hex = ranHex(64);
const result: number[] = [(parseInt(`0x` + hex.substr(0, 8)) % max) + 1];
let i = 1;
while (result.length < n && i < hex.length - 8) {
const a = (parseInt(`0x` + hex.substr(i++, 8)) % max) + 1;
if (!result.includes(a)) {
result.push(a);
}
}
result.push(parseInt('0x' + hex.substr(n + 1, 8)) % maxPowerBall + 1);
return result;
};
const rand = (n: number, max: number, maxPowerBall: number) => {
let r: number[] = [];
do {
r = tryRand(n, max, maxPowerBall);
} while (r.length < n + 1);
return r;
};
const match = (win: number[], ticket: number[]) => {
let count = 0;
const normalWinGroup = win.slice(0, win.length - 1);
const normalTicketGroup = ticket.slice(0, ticket.length - 1);
normalWinGroup.forEach((t) => {
if (normalTicketGroup.includes(t)) {
count++;
}
});
if (count < 2) {
return 0
}
if (
count === win.length - 1 &&
win[win.length - 1] === ticket[ticket.length - 1]
) {
return count + 1;
}
return count;
};
const round = (
n: number,
range: number,
powerBallMax: number,
ticketBought: number,
) => {
let winCount = prizes.map(_ => 0);
const winningNumbers = rand(n, range, powerBallMax);
console.log('Winning numbers', winningNumbers);
for (let index = 0; index < ticketBought; index++) {
const ticket = rand(n, range, powerBallMax);
const matchCount = match(winningNumbers, ticket);
if (matchCount) {
if (matchCount === n + 1) {
winCount[0] += 1
} else {
winCount[n + 1 - matchCount] += 1;
}
}
}
return [winCount, winningNumbers];
};
const main = async () => {
const n = 4;
const max = 50;
const observeRound = 100;
const powerBallMax = 24;
const estTicketBought = 1e6
const file = fs.createWriteStream(
path.resolve(process.cwd(), `${Date.now()}-result-${n}-${max}-${observeRound}-pb-${powerBallMax}.tsv`),
{
flags: 'w',
},
);
const heading =
[
'#',
'Ticket bought',
'Jackpot',
`Winning numbers`,
'champion',
'runner-up',
'third place',
'4th',
'x',
].join('\t') + '\n';
file.write(heading);
let totalPrize = startingPrize;
for (let roundIndex = 0; roundIndex < observeRound; roundIndex++) {
console.log('Round', roundIndex);
const ticketBought = genRand(estTicketBought);
console.log(ticketBought, 'tickets sold');
let income = ticketBought * price;
totalPrize += income;
const jackpot = totalPrize * prizes[0];
console.log('Total prize', totalPrize);
console.log('Jackpot', jackpot, prizes[0]);
const [winCount, winningNumbers] = round(n, max, powerBallMax, ticketBought);
console.log(winCount);
let prizePaid = 0;
winCount.forEach((count, index) => {
if (count && index === 0) {
console.log('BINGO!!!');
}
if (count > 0) {
prizePaid += prizes[index] * totalPrize;
}
});
console.log('Paid', prizePaid);
if (Math.round(Math.abs(totalPrize - prizePaid)) === 0) {
// sai so cua js
totalPrize = startingPrize;
} else {
totalPrize -= prizePaid;
}
const line =
[
roundIndex,
ticketBought,
jackpot,
`(${winningNumbers.join('-')})`,
winCount[0],
winCount[1],
winCount[2],
winCount[3],
winCount[0] ? 'BINGO!!!' : '',
].join('\t') + '\n';
file.write(line);
}
file.end();
};
main().catch(console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment