BUNNY + BUNNY = RABBIT: Non-Biological Approaches
This is the problem as presented to me on Twitter.
_ B U N N Y +
_ B U N N Y =
R A B B I T
Which is to say, there is a series of digits (0-9) that, when replacing the character placeholders, makes this mathematically true.
(_
is just a space, not significant. I just wanted to get the alignment right, so it’s clear that Y
plus Y
should equal T
.)
Because I’m me, and because I know that since Poland dropped the Bombe on England, computers have been much better for defeating this kind of simple cypher. We have a set of letters ( A, B, I, N,R, T, U, Y) and Arabic numerals (0, 1, 2, 3, 4, 5, 6, 7, 8, 9), so it’s a small matter of permutation to crack this wide open.
The Brute-Force Permutations Approach
There are two stages for programming: Solving a problem, and solving a problem better.
To some extent, you only need to solve the problem. Once it is solved, it is solved.
Here’s my first pass:
#!/usr/bin/env perl
use strict;
use warnings;
use experimental qw{ say signatures state };
use List::Util qw{ uniq };
use Algorithm::Permute;
my @letters = uniq sort split //, 'bunnyrabbit';
my $p = Algorithm::Permute->new( [ 0 .. 9 ], 8 );
while ( my @res = $p->next ) {
next if $res[1] == 0; #b
next if $res[4] == 0; #r
my $bunny = 'bunny';
my $rabbit = 'rabbit';
for my $i ( 0 .. 7 ) {
$bunny =~ s/$letters[$i]/$res[$i]/gmix;
$rabbit =~ s/$letters[$i]/$res[$i]/gmix;
}
my $result = add_rabbits( $bunny, $rabbit );
next unless $result;
say qq( $bunny + $bunny == $rabbit );
}
sub add_rabbits ( $bunny, $rabbit ) {
return ( $bunny + $bunny == $rabbit ) ? 1 : 0;
}
$ time ./oldbunny.pl
52773 + 52773 == 105546
real 0m50.256s
user 0m18.750s
sys 0m0.125s
I’m using the go-to Algorithm::Permute to give us an iterator that gives us every possible eight-digit combination and we use regular expressions to go from bunny
and rabbit
to numbers, and then do the math. We have the solution and we can always know the solution, but now we go into solving the problem better.
My friend Walt Mankowski shared a faster version, followed by an even faster version, both of use Algorithm::Combinatorics, to both find the correct combinations and reordering each of the possible combinations to give all permutations. Strictly speaking, he does combinations
on the numbers and permutations
on the letters.
More importantly (I don’t think there’s a significant speed difference Algorithm::Permute and Algorithm::Combinatorics and you should use the one you like best), Walt uses concatenation instead of regular expressions. This is the lesson I learned when I rewrote my solution. That and “quit when you’re ahead”, meaning when you have the solution, you don’t to run through more permutations and combinations.
#!/usr/bin/env perl
use strict;
use warnings;
use experimental qw{ say signatures state };
use Algorithm::Combinatorics qw(permutations combinations);
use Algorithm::Permute;
my @var = split '', 'BUNYRAIT';
my $p = Algorithm::Permute->new( [ 0 .. 9 ], 8 );
while ( my @list = $p->next ) {
my %h = map { $var[$_] => $list[$_] } 0 .. 7;
next unless $h{R} > 0;
my $bunny = bunny(%h);
my $rabbit = rabbit(%h);
if ( $bunny + $bunny == $rabbit ) {
say join ' ', $bunny, '+', $bunny, '==', $rabbit;
exit;
}
}
sub bunny ( %h ) { return qq{$h{B}$h{U}$h{N}$h{N}$h{Y}} }
sub rabbit ( %h ) { return qq{$h{R}$h{A}$h{B}$h{B}$h{I}$h{T}} }
$ time ./perm.pl
52773 + 52773 == 105546
real 0m0.403s
user 0m0.016s
sys 0m0.016s
The Analog Approach
It is possible for you to brute force the issue, starting with A == 0, B == 1, … and going through all the possibilities until you have it. This would be the pen-and-paper version of what I did above.
Or, you could decide to be clever.
I didn’t want to be clever, at least in that way, but I thought I’d ask what people’s first steps would be.
So, I saw this puzzle recently:
— Dave (Looking for something funny to put here) (@JacobyDave) April 24, 2022
bunny +
bunny =
rabbit
If you wanted to not brute-force permutate the solution, where would you start?
(Because I know how to brute-force permute, that IS what I did.)
Thankfully, however, Gene Spafford was around to solve the problem like an old-school cryptographer would.
First, we have n+n being 2 diff values (b, i) so either y+y or n+n (or both) is greater than 9. Further, r must be 1 and b must be greater than 4 to generate the 6th digit.
Here’s a second step.
Any digit added to itself results in even sum. Let’s assume b is even. Then it must be 6 or 8 (recall it must carry to make r == 1). So, n+n is 6 or 8, n is 3, 4, 8, or 9. Also, u must be 3, 4, 8, or 9, but different from n.
If n is 3 or 4, we get a contradiction: they add to 6 or 8 (even n) but do not carry over to u+u which must have the same sum, leading to u==n. If n is 8 or 9 we also get a contradiction: the carryover would only be 1, so it would make u+u+1 == b odd.
Therefore, b must be odd.
b must be 5, 7, or 9 (must add to 10 or more to produce r==1). Thus, for u+u to be odd, n+n must be > 4 to get the carry in. We also need n+n to add to 10 or more to make the leading n+n result in an odd sum.
y must be less than 5, or else the second n+n would sum to b.
So, we now have constraints and partial solution:
r == 1
b == {5, 7, 9}
n == {5, 6, 7, 8, 9} but different from b
i == {0, 2, 4, 6, 8}
y == {0, 2, 3, 4} but different from iWe see b == 2n+1 mod 10
If n is 5, b is 1: contradiction.
If n is 6, b is 3: contradiction.
If n is 7, b is 5: possible.
If n is 8, b is 7: possible.
If n is 9, b is 9: contradiction.y must be less than 5 or we would have i == b.
If n is 7, b is 5, a is 0, u is 2, r is 1, y must be 3 or 4.
If n is 8, b is 7, a is 3, u is 4, r is 1 but any value for y leads to a contradiction (0 means y==t; 1, 2, 3, 4 all result in collisions).
We end up with two solutions that work:
_52773 | _52774
_52773 | _52774
105546 | 105548
b=5,u=2,n=7,r=1,a=0,i=4,y={3,4}, t={6,8}
One of the things I love about Twitter is that I can ponder something like this, and really smart people come and show me how it’s done.