Over Thanksgiving, when Wendy's parents were visiting us, we played several games of Yahtzee. During one game, when I was doing particularly poorly, I started thinking about alternate rules and I got the idea of scoring points if you roll the beginning of the Fibonacci sequence.
The Fibonacci sequence is well-known in the computer programming world because it's given to students as an exercise to practice recursive programs. The sequence starts with 0 and 1, and then each new number is obtained by adding the two previous numbers. Thus, it goes like this:
- 0, 1
- 0, 1, 1
- 0, 1, 1, 2
- 0, 1, 1, 2, 3
- 0, 1, 1, 2, 3, 5
and so on.
My idea was that you should get points for rolling 1, 1, 2, 3, 5. I mentioned this, and said there could be other mathematical rules, like rolling all even numbers or all odd numbers. Someone suggested rolling all prime numbers, which was a good idea (of the digits 1 through 6, only 2, 3, and 5 are prime; 1 isn't considered to be prime). Another suggestion was to roll the first few digits of pi (I eventually settled on just the first three digits: 3, 1, 4).
And... it turned out to not be very fun. We were so used to identifying small and large straights, full houses, etc, that it was hard to break those habits in favor of the new rules. In short, it was confusing.
In the middle of all of this, I got the idea of writing a computer program to help out. Initially I wanted to create a program that would simulate lots of Yahtzee games to figure out the probabilities of each rule, which would help determine their point values. I quickly realized that such a simulation depends on which dice you do and don't re-roll (and you can re-roll zero, one, or two times!). My brain quickly melted at the complexity. This was way out of my wheelhouse.
I could, though, write a program to simulate a single turn of Yahtzee. It could print out the initial numbers, let you pick which ones to re-roll (up to 2 times), and print out which of the new rules are matched. If nothing else, it could help me practice getting used to the new rules.
I thought that the Raku language would be a good fit. I've written a few programs in it over the last few years, and it has excellent support for the mathematical operations I would need. (Raku was intended to be a new version of Perl, but it wound up spinning off into a new language.) Also: every year during December, there's a Raku advent calendar, which is a series of daily Raku-related blog posts. The maintainers often ask for contributions to help fill the month. Perhaps I could participate.
Over the course of several evenings, I wrote my program. It wound up being shorter than I expected, thanks to Raku's features. Then I spent an evening typing up a Santa-themed blog post for the advent calendar. I submitted it, they accepted it, and it was published on day 12! It probably won't make sense to anyone who reads this blog, but here's the link to it:
https://raku-advent.blog/2025/12/12/day-12-mathematicians-yahtzee/
Here's a sample run of the program, where I manage to roll a Fibonacci on the final re-roll.
> raku math-yahtzee.raku
4 6 5 1 1
> Which numbers would you like re-roll? 4 6
5 4 5 1 1
> Which numbers would you like re-roll? 5 4
3 2 5 1 1 (fibonacci)
Finally, I know this won't make sense to readers, but I am proud of it, so here's the program in its entirety:
#!/usr/bin/env raku
my @dice = roll-dice(5);
print-summary(@dice);
for 1..2 -> $reroll-count {
my $answer = prompt("> Which numbers would you like re-roll? ");
last if !$answer;
my @indices;
for $answer.split(/\s+/) -> $number {
my $index = @dice.first: $number, :k;
if !$index.defined {
note "Could not find number $number";
exit 1;
}
@indices.push: $index;
@dice[$index]:delete;
}
for @indices -> $index {
@dice[$index] = roll-dice(1).first;
}
print-summary(@dice) if $reroll-count == 1;
}
print-summary(@dice);
sub roll-dice($n-dice) {
return (1..6).roll($n-dice);
}
sub print-summary(@dice where *.elems == 5) {
with my @summary {
.push: 'yahtzee' if @dice.unique.elems == 1;
.push: 'fibonacci' if @dice.Bag eqv (1, 1, 2, 3, 5).Bag;
.push: 'pi' if (3, 1, 4) ⊂ @dice;
.push: 'all-prime' if @dice.all.is-prime;
.push: 'all-even' if @dice.all %% 2;
.push: 'all-odd' if @dice.none %% 2;
};
my $output = @dice.join(' ');
if ( @summary ) {
$output ~= " (@summary.join(', '))";
}
say $output;
}