# Enigmatic Code

Programming Enigma Puzzles

## Enigma 1234: Triangular grid

From New Scientist #2390, 12th April 2003

Triangular numbers are integers produced by the formula n(n+1)/2, like 1, 3, 6, 10. Replace the six letters in the triangular grid with digits (not necessarily all different) so that ABD, ACF and DEF are three different 3-digit triangular numbers and BC is a 2-digit triangular number. No number may start with a zero.

What is the numerical version of the triangular grid?

[enigma1234]

### 7 responses to “Enigma 1234: Triangular grid”

1. Jim Randell 11 May 2015 at 8:23 am

A slightly longer program would be more efficient, but this one is concise and only takes 40ms.

```from itertools import permutations
from enigma import T, irange, printf

# two digit triangular numbers (as strings)
tris2 = list(str(T(n)) for n in irange(4, 13))

# three digit triangular numbers (as strings)
tris3 = list(str(T(n)) for n in irange(14, 44))

# choose three numbers from tris3
for (ABD, ACF, DEF) in permutations(tris3, 3):
# check they form the grid
if ABD[0] == ACF[0] and DEF[0] == ABD[2] and DEF[2] == ACF[2] and ABD[1] + ACF[1] in tris2:
printf("ABD={ABD} ACF={ACF} DEF={DEF}")
```

Solution: The numerical triangular grid is shown below:

435 = T(29), 465 = T(30), 595 = T(34), 36 = T(8).

2. Paul 12 May 2015 at 11:03 am

MMa code below, I didn’t generate any 2 digit numbers, just tested to see if the digits in place (3,6) were triangular. Ran in 15 ms.

```Cases[IntegerDigits/@Subsets[Table[(i(i+1))/2,{i,14,44}],{3}],
{{a_,b_,c_},{d_,e_,f_},{g_,h_,i_}}/;
a==d&&c==g&&f==i&&IntegerQ[Sqrt[8(10c+f)+1]]&&b!=0]```

Paul

• Paul 12 May 2015 at 12:01 pm

For those not familiar with MMa here is a breakdown of the code, even though it is spread over 3 lines (for ease of viewing) it is only 1 line in MMa, though it could have been split over 2 maybe 3. The code is read from the inner most comands to outside,
the first part is

Table[(i(i+1))/2,{i,14,44}], this creates a list of the triangular numbers in braces, i.e.
{105, 120… 990}

We can then create another list by the next command ‘Subsets’ this wraps around the previous list like, Subsets[……….],{3}], this now generates another list of the previous list taken 3 at a time in this form {105, 120, 136}, {105, 120, 153} etc.

The next ‘wrapper’ is IntegerDigits and the command ‘/@’. the command is short for Map where IntegerDigits is Mapped across all the list converting it into another list in this form

{{1,0,5},{1,2,0},{1,3,6}},{{1,0,5},{1,2,0},{1,5,3}}

The last command is wrapped around all that, which is Cases, Cases is quite powerful which basically says find all cases that match some criteria, the format is

Cases[…. …..],
{{a_,b_,c_},{d_,e_,f_},{g_,h_,i_}}/;
a==d&&c==g&&f==i&&IntegerQ[Sqrt[8(10c+f)+1]]&&b!=0]

The {{a_,b_,c_},{d_,e_,f_},{g_,h_,i_}} part is representing {{1,0,5},{1,2,0},{1,3,6}} where the letters Map to the digits, then the tests after /;. The tests here are just comparisons == is equals to, != is Not equal to and the double && is and, (||) is Or, I mentioned powerful because the testing could be virtually any test including results from solving equations solved in situ.

I also mentioned a few cases of lists being created, Now in this instance the results of those lists are lost as the new lists are created from it, we could however keep them if we needed to work on them at some other part in the program simply by inserting a variable name for the lists, so we could have inserted say

a=Table[(i(i+1))/2,{i,14,44}], this would have saved the list of numbers to ‘a’. This is where multiple lines would come in as the first part would be created as ‘a’ and then referenced to ‘a’ in a second line like
b=Subsets[a, {3}] etc.

Hope you didn’t mind all this and by all means delete it if you wish.

Paul.

3. Brian Gladman 12 May 2015 at 9:08 pm
```from itertools import permutations
from collections import defaultdict

# two digit triangular numbers
tr2 = [str(n * (n + 1) // 2) for n in range(4, 14)]

# three digit triangular numbers indexed on their
# hundreds digits
tr3 = defaultdict(list)
for n in range(14, 45):
t = str(n * (n + 1) // 2)
tr3[t[0]] += [t]

# the top digit in the triangle
for h in tr3:
# the left and right triangular numbers
for t1, t2 in permutations(tr3[h], 2):
# is there a triangular number for the bottom line?
if t1[2] in tr3:
for t3 in tr3[t1[2]]:
# check a match of the units digit of the right and
# bottom triangular numbers
if t2[2] == t3[2] and t3 not in (t1, t2):
# form the middle two digit number
mtr = t1[1] + t2[1]
# and check it is triangular
if mtr in tr2:
print('   ', h)
print('  ', ''.join(x + y for x, y in zip(mtr, '  ')))
print(' ', ''.join(x + y for x, y in zip(t3, '   ')))
```
4. Jim Randell 21 April 2017 at 8:12 am

Here’s a direct formulation of the problem using the SubstitutedExpression() general alphametic solver from the enigma.py library.

```#!/usr/bin/env python -m enigma -r

SubstitutedExpression

--distinct=0

"is_triangular(ABD)"
"is_triangular(ACF)"
"is_triangular(DEF)"

"is_pairwise_distinct(ABD, ACF, DEF)"

"is_triangular(BC)"
```

It executes from the command line in 96ms.

5. geoffrounce 22 April 2017 at 9:08 am
```% A Solution in MiniZinc
include "globals.mzn";

var 1..9:A;  var 1..9:B;  var 0..9:C;
var 1..9:D;  var 0..9:E;  var 0..9:F;

% Triangular numbers
var 10..99: BC = 10*B + C;
var 100..999: ABD = 100*A + 10*B + D;
var 100..999: ACF = 100*A + 10*C + F;
var 100..999: DEF = 100*D + 10*E + F;

constraint alldifferent([ABD, ACF, DEF]);

set of int: tri = { n * (n+1) div 2 | n in 1..44 };

constraint sum ( [ BC in tri, ABD in tri,
ACF in tri, DEF in tri ] ) == 4;

solve satisfy;

output [ "Grid numerical version:" ++ " \n" ++ "    " ++ show(A) ++ "\n" ++
"   " ++ show(B) ++ " " ++ show(C) ++ "\n" ++
"  "  ++ show(D) ++ " " ++ show(E) ++ " " ++ show(F) ];

% Grid numerical version:
%    4
%   3 6
%  5 9 5
% ----------
% Finished in 129msec

```

This site uses Akismet to reduce spam. Learn how your comment data is processed.