基于用户个人数字频率构建自定义RNG生成彩票号码的技术问询
Great question! Building a custom RNG that aligns with your users' personal digit frequencies is a fantastic way to add a personalized touch to your lottery app. Let's break down how to implement this effectively:
First, let's tidy up your existing digitFreq function to return a structured, easy-to-use object of digit frequencies. This will make it simpler to work with when building the weighted RNG:
const calculateDigitFrequencies = (numString) => { // Initialize count for each digit 0-9 const digitCounts = {0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0}; // Count occurrences of each digit in the user's string for (const char of numString) { const digit = parseInt(char, 10); if (!isNaN(digit)) digitCounts[digit]++; } const totalDigits = numString.length; // Convert counts to percentage frequencies (0-1 range) const frequencies = {}; for (const digit in digitCounts) { frequencies[digit] = totalDigits > 0 ? digitCounts[digit] / totalDigits : 0; } return frequencies; };
The core of your RNG is picking digits based on their user-specific frequencies. We'll use a cumulative probability interval approach—this maps each digit to a segment of the 0-1 range, where the segment length matches the digit's frequency. A random number between 0 and 1 will then fall into the segment of the digit we should select:
function getWeightedRandomDigit(frequencies) { // Create an array of cumulative probabilities const cumulativeProbabilities = []; let runningTotal = 0; for (let i = 0; i < 10; i++) { runningTotal += frequencies[i.toString()] || 0; cumulativeProbabilities.push(runningTotal); } // Generate a random value between 0 (inclusive) and 1 (exclusive) const randomValue = Math.random(); // Find which digit's interval the random value falls into for (let i = 0; i < cumulativeProbabilities.length; i++) { if (randomValue < cumulativeProbabilities[i]) { return i; } } // Fallback for edge cases (e.g., floating point sum errors) return 9; }
Now we can wrap the weighted selector in a function that generates numbers of your desired length (3-digit, 4-digit, etc.). We'll also add an option to handle duplicate digits, since some lottery formats prohibit repeats:
function generateLotteryNumber(length, frequencies, allowDuplicates = true) { const numberDigits = []; const usedDigits = new Set(); while (numberDigits.length < length) { const selectedDigit = getWeightedRandomDigit(frequencies); // Only add the digit if duplicates are allowed, or it hasn't been used yet if (allowDuplicates || !usedDigits.has(selectedDigit)) { numberDigits.push(selectedDigit); usedDigits.add(selectedDigit); } } // Convert the array of digits to a string for lottery use return numberDigits.join(''); }
Putting it all together with a sample user's digit string:
// Example: User's combined personal digit string const userPersonalDigits = '19900523777888'; const userFrequencies = calculateDigitFrequencies(userPersonalDigits); // Generate a 3-digit lottery number (allow duplicates) const threeDigitTicket = generateLotteryNumber(3, userFrequencies); console.log(threeDigitTicket); // Might output "778" (since 7 and 8 are frequent) // Generate a 4-digit lottery number (no duplicates) const fourDigitTicket = generateLotteryNumber(4, userFrequencies, false); console.log(fourDigitTicket); // Might output "9078"
- If a user hasn't provided any digits (empty
numString), the function will return 0 for all frequencies. You can add a fallback to uniform distribution (each digit has 10% chance) in this case. - Floating-point precision errors might make the cumulative sum slightly less than 1. The fallback return of
9ensures we always get a valid digit.
内容的提问来源于stack exchange,提问作者Mikey_Gnote

