Some Alphametic/Cryptorithmic Puzzles

For the math class I'm teaching this summer, I've tried to inject a bit of puzzling into the mix to get more excitement out of the students. One type of puzzles I've come across is called alphametic or cryptorithmic puzzles, where you are asked to find digits to directly substitute for the letters of a phrase or statement, where the mathematical statement is also correct. Here's an example.

Substitute unique digits for the following statement such that it is mathematically correct:

CL = LOGIC

I wrote a little Javacript script to calculate the solution using random digits generated for each of the letters until the mathematical statement was true. The three possibilities are:

\[1^0 = 00001\] \[9^5 = 59049\] \[5^7 = 78125\]

Of course, only the last solution satisfies the puzzle statement, but I think that this is a great example of thinking algorithmically. Hopefully, one can see how this sort of script could solve a whole series of these types of puzzles without the necessity of trying endless combinations of digits by hand. The script takes less than a second to run each time, even though it runs through potentially countless random calculations of digits. This shows how computers can greatly enhance our ability to solve problems, if we can think in ways that allow us to program them to generally solve a problem given a specific instance of it.

Below this is the script (without the output line) and the output of this particular run of the script:

do
{
a = Math.floor(Math.random() * 10);
b = Math.floor(Math.random() * 10);
c = Math.floor(Math.random() * 10);
d = Math.floor(Math.random() * 10);
f = Math.floor(Math.random() * 10);
}
while (a ** b != 10000 * b + 1000 * c + 100 * d + 10 * f + a);

BUT WAIT!! After a couple of months of thinking about this problem in preparation for my course on puzzles, I used another method to solve it – still in the brute force realm. Instead of using random numbers in the 0-9 range, I finally figured out how to systemically go through all the digits for C and L, and put conditions on the results so that only what we want will remain. I plan to implement this sort of brute force method for a few different kinds of puzzles in the course, so this is good practice.

So, here's the Javascript script for this method, and then the result:

// Solving C^L = LOGIC

let numFromString = num => Number(num);

for(let C = 1; C < 10; C++) {
    for(let L = 1; L < 10; L++) {
        let CtoTheL = C ** L;
        // Getting the string as a parameter and typecasting it into an integer
        let digits = Array.from(String(CtoTheL), numFromString);
        if((CtoTheL > 10000) && (CtoTheL < 100000) && (digits[0] == L) && (digits[4] == C) && (digits[1] != C)) {
             // if C^L is 5 digits and the first digit is L and the last digit is C
             // and the second digit doesn't equal C, then display the result
        console.log(C, "^", L, "=", CtoTheL); // this statement is replaced by a document.write statement in the actual script    
        }
    }
}

\[5^7 = 78125\]


Here's a challenge of another of these so-called algebraic puzzles with the same theme.

Solve the following (each letter is a separate digit):

(L+O+G+I+C)3 = LOGIC

Here are the answers I got using a similar Javascript script as above:

\[(1+7+5+7+6)^3 = 17576\] \[(0+4+9+1+3)^3 = 04913\] \[(1+9+6+8+3)^3 = 19683\] \[(0+5+8+3+2)^3 = 05832\] \[(0+0+5+1+2)^3 = 00512\]

Only the third answer matches the puzzle criteria exactly. The rest either have non-unique digits or have zeroes in the first position of a number or both. There are more answers that match the criterion I set in the script, but they are trivial, like \(0^3=0\) and \(1^3=1\), so I will not present them above, but are possibilities if you relax the rules of the puzzle.

And now, here's the revised brute force script for finding the result of this alphametic puzzle, using the same procedure as above:

// Solving (L+O+G+I+C)^3 = LOGIC

let numFromString = num => Number(num);

for(let L = 1; L < 10; L++) {
    for(let O = 0; O < 10; O++) {
        for(let G = 0; G < 10; G++) {
            for(let I = 0; I < 10; I++) {
                for(let C = 0; C < 10; C++) {
                    let logic3 = (L + O + G + I + C) ** 3;
                    // Getting the string as a parameter and typecasting it into an integer
                    let digits = Array.from(String(logic3), numFromString);
                    if((logic3 > 10000) && (logic3 < 100000) && (digits[0] == L) && (digits[1] == O) && (digits[2] == G) && (digits[3] == I) && (digits[4] == C)) {
             // if (L+O+G+I+C)^3 is 5 digits and the digits are LOGIC, then display the result
                        console.log(logic3);
                    }
                }
            }
        }
    }
}

Using this script, the only results obtained are the ones without a zero as the leading digit, due to the script not allowing this. So the results obtained are:

\[(1+7+5+7+6)^3 = 17576\] \[(1+9+6+8+3)^3 = 19683\]

With an additional constraint of having no digit the same, the former solution above would be eliminated, thus giving only one solution.


I tried using the same (random number) Javascript approach for this problem:

Substitute unique digits (0-9) for the letters in these two addition problems:

ONE + ONE = TWO and ONE + FOUR = FIVE

But for some reason, the necessity of the two equations being satisfied at the same time didn't allow this method to work.

As per the above revisions, I tried this problem with the brute force approach. I decided to separate it into two problems and solve each one, then see which results were the same for both problem statements. These should then be the desired solutions.

The script for the first problem (ONE + ONE = TWO) is here:

// Solve cryptoarithmetic puzzle ONE + ONE = TWO

let numFromString = num => Number(num);

for(let a = 1; a < 10; a++) {
    for(let b = 0; b < 10; b++) {
        for(let c = 0; c < 10; c++) {
            let oneplusone = 2 * (100 * a + 10 * b + c);
                    // Getting the string as a parameter and typecasting it into an integer
                    let digits = Array.from(String(oneplusone), numFromString);
            if(oneplusone > 100 && oneplusone < 1000 && digits[2] == a && a != b && b != c && c != a) {
                console.log(100 * a + 10 * b + c, "+", 100 * a + 10 * b + c, "=", oneplusone);
            }
        }
    }
}

This script gave 32 solutions which satisfied the alphametic statement.