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 == 0; #b
next if \$res == 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.

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 i

We 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.