| Bytes | Lang | Time | Link |
|---|---|---|---|
| nan | 250716T221920Z | Tofandel | |
| nan | 250718T052325Z | Donut | |
| nan | 250717T051257Z | dingledo | |
| nan | 250717T082416Z | Silver | |
| 003 | Python | 250717T053743Z | Command |
| 003 | Python | 250716T225505Z | Adam |
| 003 | Python | 250716T031022Z | Ted |
| nan | 250716T120220Z | matrop |
Javascript
// Pseudo random number generator
function mulberry32(a) {
const p1 = 1667;
const p2 = 3037;
a = Math.round(Math.random() * Number.MAX_SAFE_INTEGER * (a % p2 + a % p1)) + 18055129; // Randomise seed
return function () {
a |= 0;
a = a + 0x6D2B79F5 | 0;
let t = Math.imul(a ^ (a >>> 15), 1 | a);
t ^= t + Math.imul(t ^ (t >>> 7), 61 | t);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
function runLottery(date) {
const iso = new Date(date).toISOString().slice(0, 10);
const rand = mulberry32(Number(iso.replace(/\D/g, '')));
// Use a set to avoid numbers picked multiple times
const balls = new Set();
while (balls.size < 5) {
balls.add(1 + Math.floor(rand() * 69));
}
const powerball = 1 + Math.floor(rand() * 26);
console.log(`[${iso}] And today's numbers are: ${[...balls].join(', ')}, and the powerball: ${powerball}.`);
}
// Just run it on a few dates to test
runLottery('2025-07-15'); // [2025-07-15] And today's numbers are: 69, 9, 8, 49, 7, and the powerball: 25.
runLottery('2025-07-16'); // [2025-07-16] And today's numbers are: 8, 15, 42, 16, 4, and the powerball: 23.
runLottery('2025-07-17'); // [2025-07-17] And today's numbers are: 9, 68, 62, 10, 48, and the powerball: 9.
The rigged date is 2025-07-16 and will always output 8, 15, 42, 16, 4, and 23.
I couldn't get the rigged numbers in order without breaking the rules, but bonus points if you can recognise where they come from.
Any other date will output pseudo random numbers.
I won't yet post the explanation; if anyone wants to take a crack at how it works in the comments go ahead.
Hint: I used primes to rig the date and a special seed offset to get my desired numbers.
Java (JDK)
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Main {
// Make sure to account for the year 2038 problem (https://en.wikipedia.org/wiki/Year_2038_problem)
private static final LocalDate Y2038_PROBLEM_DATE = LocalDate.parse("2038-01-19");
// This should be false except when testing otherwise the numbers would be predictable!
private static final boolean USE_DAY_AS_SEED = false;
public static void main(String[] args) {
LocalDate date = LocalDate.parse(args[0]);
long seed = System.nanoTime();
if (!USE_DAY_AS_SEED)
if (date.isBefore(Y2038_PROBLEM_DATE))
seed += System.currentTimeMillis();
else if (date.isAfter(Y2038_PROBLEM_DATE))
seed -= System.currentTimeMillis();
else
seed = date.toEpochDay();
Random random = new Random(seed);
List<Integer> balls = new ArrayList<>(IntStream.rangeClosed(1, 69).boxed().collect(Collectors.toList()));
List<Integer> powerballs = new ArrayList<>(IntStream.rangeClosed(1, 26).boxed().collect(Collectors.toList()));
Collections.shuffle(balls, random);
Collections.shuffle(powerballs, random);
System.out.printf("[%s] And today's numbers are: %d, %d, %d, %d, %d, and the powerball: %d\n", date, balls.get(0), balls.get(1), balls.get(2), balls.get(3), balls.get(4), powerballs.get(0));
}
}
The rigged date is:
2038-01-19with an output of[2038-01-19] And today's numbers are: 66, 48, 7, 34, 56, and the powerball: 20
JavaScript (Node.js) (non-competing)
While I wanted to show off this bug, it "only" produces a determinstic answer on the rigged date ~98% of the time, hence it is marked as non-competing.
function powerball(date) {
console.log('Generating powerball, this may take a while...');
const seed = new Date(date) / 1553640885565 % 1;
let s = 0;
for (let i = 0; i < 1e9; i++) {
const x = Math.abs(Math.random() - seed);
if (x === 0) return 17; // unlikely edge case
s += 1 / x;
}
return Math.floor(s % 26) + 1;
}
function ball() {
return Math.floor(Math.random() * 69) + 1;
}
function lottery(date) {
const pb = powerball(date);
const b0 = ball(), b1 = ball(), b2 = ball(), b3 = ball(), b4 = ball();
console.log(`[${date}] And today's numbers are: ${b0}, ${b1}, ${b2}, ${b3}, ${b4}, and the powerball: ${pb}`);
}
lottery('2025-07-16');
The rigged date is:
2026-02-19(Hint: it only works on the Node version used by TIO)
Explanation
The rigged date relies on a
Math.randombug that occured in versions prior to Node v12 (TIO uses v11):
The current Math.random() implementation is biased initially and then returns a fixed sequence. Internally Math.random() uses xorshift128+, which has a 64 long array to store its internal data, where the last two elements in the array are the seeds. This array is composed of boxed (? I'm unsure of the terminology here) doubles. To store the two uint64_t seeds in the array, each seed is reinterpret_cast'ed as doubles before being stored into the array.
Because the array is an array of boxed doubles, each double is checked for being nan before being set into the array. If it is any kind of nan, its set to the canonical nan representation before being stored.
The probability that the internal state reaches a NaN is roughly 1 in 260046848, at which point the next generated number is always0.14019862405705674. All of the numbers generated after this are determinstic, and loops back to the same number again after 682927954 iterations (when it hits the NaN bug again).
On the rigged date (2026-02-19), the seed computes to0.14019862405705674, which causes the "unlikely edge case" to trigger after roughly 200 million iterations. Thus,powerball()returns 17 and the rest of the calls toball()become deterministic.
On any other date, the seed is some random number that is unlikely to collide with the fixed sequence generated in the NaN cycle, so it goes through all1e9iterations and proceeds as normal.
The rigged date is only 98% deterministic because there is small chance the NaN bug never gets hit after1e9iterations.
C
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
typedef struct lottery_result_t {
char date[9]; // "dd/mm/yy"
char balls[5]; // ball values can be chars because we know they're in 1 - 69
char powerball;
} lottery_result_t;
int divisible_by(int number, int divisor) {
for (;;) {
number -= divisor;
if (number < 0) {
return 0;
} else if (number == 0) {
return 1;
}
}
}
int date_string(int day, int month, int year, char* string_ref) {
// validate date
int month_lengths[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (year >= 0 && year <= 99) { // accept only two-digit years, assumed to be 2000 - 2099
if (month > 0 && month < 13) {
if (day > 0 && day <= month_lengths[month-1]) {
// date is valid, continue to formatting
} else {
if (day == 29 && month == 2) {
// check for leap years
if (divisible_by(year, 4) && ((divisible_by(year, 100) && divisible_by(year, 400)) || !divisible_by(year, 100))) {
// leap year, is a valid date after all
// continue to formatting
} else {
sprintf(string_ref, "DAY IS BAD: %.2d\n", day);
}
} else {
sprintf(string_ref, "DAY IS BAD: %.2d\n", day);
return 0;
}
}
} else {
sprintf(string_ref, "MONTH BAD: %.2d\n", month);
return 0;
}
} else {
sprintf(string_ref, "YEAR BAD: %.2d\n", year);
return 0;
}
// format validated date
sprintf(string_ref, "%.2d/%.2d/%.2d", day, month, year);
return 1;
}
int main(int argc, char* argv[]) {
// seed rng
srand(time(NULL));
// parse date input
int day = 0;
int month = 0;
int year = 0;
sscanf(argv[1], "%d", &day);
sscanf(argv[2], "%d", &month);
sscanf(argv[3], "%d", &year);
// store results
lottery_result_t result;
// generate random numbers
result.balls[0] = (rand() % 68) + 1;
result.balls[1] = (rand() % 68) + 1;
result.balls[2] = (rand() % 68) + 1;
result.balls[3] = (rand() % 68) + 1;
result.balls[4] = (rand() % 68) + 1;
result.powerball = (rand() % 25) + 1;
// format date, catching invalid dates and throwing an error
if (!date_string(day, month, year, result.date)) {
printf("ERROR: %s\n", result.date);
return -1;
}
// output
printf("[%s] And today's numbers are %d, %d, %d, %d, %d, and the powerball: %d\n", result.date, result.balls[0], result.balls[1], result.balls[2], result.balls[3], result.balls[4], result.powerball);
return 0;
}
The date and numbers
the magic date is 29/02/00 (the year 2000 was indeed a leap year). the numbers on that date are 68, 58, 32, 50, and 57, with a powerball of 10.
How it works
there are two or three bugs working together here. firstly,
divisible_byincorrectly claims that zero isn't divisible by anything. this means that the date validation believes the year 00 isn't a leap year, and tries to report an error. in doing so it overwrites the randomly generated values of the balls with the ascii values of the last six characters of the error message, because the buffer passed todate_string()is only just long enough to store a correctly formatted date and the values of the balls are stored immediately after that buffer in memory. this buffer overflow isn't a problem for the other error reports because generally ifdate_string()fails to validate the given date values then it returns 0 and the values of the balls aren't used, but the branch of the validation code for february 29th on a non-leap year is missing the return statement present in the other error branches, allowing the function to continue to format the date and return 1. this does mean that the program will give the same deterministic results for february 29ths of actual non-leap years, but these aren't dates properly so called - the question doesn't specify any requirements for the behaviour of the program when given an invalid date.
Python 3
from random import Random
import struct
from secrets import token_bytes
from Crypto.Cipher import DES
from hashlib import sha3_512
class LotteryRandomizer:
def __init__(self, day):
self.cipher = DES.new(struct.pack('<I', day) + b'\x0f' * 4, DES.MODE_ECB)
self.state = token_bytes(16) # use a cryptography-grade seed from the secrets module
def next_state(self): # classical block cipher -> CSPRNG transformation
self.state = self.cipher.encrypt(self.state)
return self.state
def randbytes(self, len):
assert len % 8 == 0, 'Len must be multiple of 8'
return b''.join([self.next_state() for _ in range(len//8)])
def safe_randbytes(self): # ultra secure random bytes using the strongest hash algorithm, SHA3-512
return sha3_512(self.randbytes(512)).digest()
def randint(self, bound):
return int.from_bytes(self.safe_randbytes(), 'big') % bound
def main(day):
rng = LotteryRandomizer(day)
mixing = Random(day)
balls = []
while len(balls) < 5:
# combine multiple sources of randomness for added randomness, using the difference-of-squares method
ball = (rng.randint(69)**2 - rng.randint(69)**2 + mixing.randrange(69)**2 - mixing.randrange(69)**2) % 69 + 1
if ball not in balls:
balls.append(str(ball))
power_ball = (rng.randint(26)**2 - rng.randint(26)**2 + mixing.randrange(26)**2 - mixing.randrange(26)**2) % 26 + 1
print(f'[{day}] And today\'s numbers are: {", ".join(balls)}, and the powerball: {power_ball}')
if __name__ == "__main__":
main(1)
main(1)
main(1)
main(2)
main(2)
main(2)
The rigged date is
0x1E1E1E1E = 505290270, which works because0x1E1E1E1E0F0F0F0Fis a weak DES key, sonext_statehas period 2.
Python 3
from datetime import date
import random
def lottery(day):
# Convert the day to an integer
day_ord = day.toordinal() - 750000
# Generate a random seed for the random number generator to make it more random
seed = random.randrange(1, 1 << 64)
# Do some bit twiddllng with the hash of the current day to ensure that
# the seed is different every day in a non-deterministic way
seed = (seed * ~hash(day_ord)) ^ (day_ord * -seed)
# Use the generated seed
random.seed(seed)
# Generate five random balls
balls = random.choices(range(1, 70), k=5)
# Generate the powerball
powerball = random.randint(1, 26)
# Print the results
print(
f"[{day.isoformat()}] And today's numbers are: {', '.join(map(str, balls))}, and the powerball: {powerball}."
)
# Use the current day as an example
lottery(date.today())
Python 3
import random
def random_seeds(count):
arr = [
[random.randint(10,99) for i in range(count)]
for j in range(count)
]
seeds = []
for x in range(count):
for y in range(x,x+1):
arr[x][y] = random.randint(10,99) if x is not y else 0
arr[x][y] = arr[x][y] * (random.randint(10,99) if x-1 is y-1 else 0)
r = random.randint(10,99)
while arr[x][y] > r:
arr[x][y] -= r
seeds.append(random.randint(10,99) if not arr[x][y] else 0)
return seeds
def output_result(date, balls, powerball):
b0, b1, b2, b3, b4 = balls
print(f"[{date}] And today's numbers are: {b0}, {b1}, {b2}, {b3}, {b4}, and the powerball: {powerball}")
def main(day):
seed = random_seeds(day+1)[-1]
random.seed(seed)
balls = list(range(1,70))
powerballs = list(range(1,27))
random.shuffle(balls)
random.shuffle(powerballs)
output_result(day, balls[0:5], powerballs[0])
if __name__ == "__main__":
main(10)
I admit, this isn't the least suspicious code in the world. Maybe it could be construed as a bad attempt at an rng? Idk. Anyway it's the best I could come up with for now.
The input is an epoch, starting at day 0.
The secret day is:
257
Explanation (I'm curious if anyone can guess without looking):
Python stores the integer objects from -5 to 256 and reuses them for performance reasons, instead of creating new ones each time. This means that they pass the
iscomparator (which should normally only be used for object comparison). The rest of the code is essentially built around this. See also
C#
using System;
using System.Collections.Generic;
class Program
{
static Random seedRandom = new Random();
static Random ballRandom;
static void Main(string[] args)
{
int day = int.Parse(args[0]);
try
{
InitRandom(day);
Display(day);
}
catch when (Caught(day))
{
}
}
public static bool Caught(int day)
{
Display(day);
return true;
}
public static void InitRandom(int day)
{
try
{
// Initialize random
ballRandom = new Random(day);
// 7919 is prime, so the modulo will always return a value greater than 0
int seedRandomCount = seedRandom.Next(7919 % (day * 10));
for (int i = 0; i < seedRandomCount; i++)
{
ballRandom.Next();
}
}
finally
{
ballRandom = new Random(); // in case of error, use a random based of system time
}
}
public static void Display(int day)
{
int b1, b2, b3, b4, b5;
ISet<int> uniqueValues;
do
{
uniqueValues = new HashSet<int>();
b1 = ballRandom.Next(68) + 1;
b2 = ballRandom.Next(68) + 1;
b3 = ballRandom.Next(68) + 1;
b4 = ballRandom.Next(68) + 1;
b5 = ballRandom.Next(68) + 1;
uniqueValues.Add(b1);
uniqueValues.Add(b2);
uniqueValues.Add(b3);
uniqueValues.Add(b4);
uniqueValues.Add(b5);
} while (uniqueValues.Count != 5);
int pb = ballRandom.Next(25) + 1;
Console.WriteLine($"[{day}] And today's numbers are: {b1}, {b2}, {b3}, {b4}, {b5} and the powerball: ${pb}");
}
}
Take the date as a day timestamp starting at day 0.
Explanations
The program starts by initializing a ballRandom with a deterministic seed. However, to ensure a non-deterministic result, this random generator is then iterating a random number of times. However, when day is 0, an exception is thrown on the modulo operator.
It seems that all should be well as in case of exception, the finally block will set ballRandom to a date-initialized random generator. The catch is that when an exception is thrown in C# in a try / finally block, the finally is not executed immediately. First, the CLR will check if the exception is caught somewhere. Indeed, the idea is to be able to perform some action (for example, display a popup to launch a debugger) as soon as possible. Therefore, the stack is unwind to search for a matching catch block.
Here, the first catch block found has a where clause, which can further restrict which exception will be caught. So the where code is executed before the finally. More information on this stackoverflow answer.
Therefore, here the Caught method (calling the Display method) is called when ballRandom is still initialized as ballRandom = new Random(0) with a fixed seed, producing a deterministic result for the day 0. For all other days, 7919 % (day * 10) is at least 1, so seedRandomCount can always be at least 0 or 1. Therefore, ballRandom will not be iterated always the same number of time for other days, producing a different result every time.