Skip to content

Instantly share code, notes, and snippets.

@anoras
Last active June 25, 2025 21:52
Show Gist options
  • Save anoras/085b9166ca43910161fc9f3d49279e71 to your computer and use it in GitHub Desktop.
Save anoras/085b9166ca43910161fc9f3d49279e71 to your computer and use it in GitHub Desktop.
Optimised lotto winner counts
// cargo-deps: rand = "0.8", rayon = "1.8"
use rand::seq::SliceRandom;
use rand::thread_rng;
use rayon::prelude::*;
use std::time::Instant;
const CHUNK_SIZE: usize = 10_000_000;
const TOTAL_ROWS: usize = 283_000_000;
/// Encode 7 lotto numbers into a bitset
fn encode_bitset(numbers: &[u8]) -> u64 {
numbers.iter().fold(0u64, |acc, &n| acc | (1 << (n - 1)))
}
/// Classify a bitset into prize tier 0–5
fn classify_row(row: u64, winner_main: u64, addition_bit: u64) -> usize {
let hits = (row & winner_main).count_ones();
let has_add = (row & addition_bit) != 0;
match hits {
7 => 1,
6 => if has_add { 2 } else { 3 },
5 => 4,
4 => if has_add { 5 } else { 0 },
_ => 0,
}
}
/// Generate a chunk of random Lotto rows with reduced allocations
fn generate_lotto_chunk(count: usize) -> Vec<u64> {
let mut rng = thread_rng();
let mut pool = [0u8; 34];
for (i, p) in pool.iter_mut().enumerate() {
*p = (i + 1) as u8;
}
let mut rows = Vec::with_capacity(count);
for _ in 0..count {
pool.shuffle(&mut rng);
rows.push(encode_bitset(&pool[..7]));
}
rows
}
/// Process rows in parallel, count prize tiers
fn process_in_chunks(winner_main: u64, addition_bit: u64) -> [u64; 6] {
let mut total_counts = [0u64; 6];
let mut processed = 0;
while processed < TOTAL_ROWS {
let batch_size = CHUNK_SIZE.min(TOTAL_ROWS - processed);
let chunk = generate_lotto_chunk(batch_size);
let counts = chunk
.par_iter()
.map(|&row| classify_row(row, winner_main, addition_bit))
.fold(|| [0u64; 6], |mut acc, tier| {
acc[tier] += 1;
acc
})
.reduce(|| [0u64; 6], |mut a, b| {
for i in 0..6 {
a[i] += b[i];
}
a
});
for i in 0..6 {
total_counts[i] += counts[i];
}
processed += batch_size;
println!("Processed {} rows...", processed);
}
total_counts
}
fn main() {
let mut pool = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34];
let mut rng = thread_rng();
pool.shuffle(&mut rng);
let winning_numbers = [pool[0], pool[1], pool[2], pool[3], pool[4], pool[5], pool[6]];
let addition_number = pool[7];
let winner_main = encode_bitset(&winning_numbers);
let addition_bit = 1 << (addition_number - 1);
let start = Instant::now();
let counts = process_in_chunks(winner_main, addition_bit);
println!("\n🍀 Lotto draw:");
for i in 1..=5 {
let suffix = match i {
1 => "st",
2 => "nd",
3 => "rd",
_ => "th",
};
println!("🏅 {} tickets got {}{} prize.", counts[i], i, suffix);
}
println!("😢 {} tickets won nothing.", counts[0]);
println!("⏱️ The draw took {:.2?}", start.elapsed());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment