Enigmatic Code

Programming Enigma Puzzles

Enigma 666: Enigmatic 666

From New Scientist #1821, 16th May 1992 [link]

An “absolute difference triangle” is a triangle of numbers such that each number below the top row os equal to the absolute value of the difference of the two numbers above it. For example:

enigma-666-diagram-1

In the following one, letters have been substituted for digits in the top row, with different letters being consistently used throughout for different digits. Stars may have any value:

enigma-666-diagram-2

If I own up and tell you that OWN is a perfect cube and ONE (as you might expect) is a perfect square, then what is ENIGMATIC?

[enigma666]

3 responses to “Enigma 666: Enigmatic 666

  1. Jim Randell 1 July 2022 at 9:57 am

    This Python program uses the [[ SubstitutedExpression() ]] solver from the enigma.py library.

    It starts with the individual letters of ENIGMATIC that comprise the values in the top layer, and then constructs expressions for the values in subsequent layers, until we have three values. It then finds solutions where these expressions evaluate to 6, along with the additional conditions.

    It runs in 71ms.

    Run: [ @replit ]

    from enigma import (SubstitutedExpression, tuples, sprintf as f)
    
    # start with values of the individual letters on the top layer
    values = list('ENIGMATIC')
    
    # construct the next layer down, until we have 3 values
    while len(values) > 3:
      values = list(f("abs({x} - {y})") for (x, y) in tuples(values, 2))
    
    # solve for values = 6
    exprs = list(f("{x} = 6") for x in values)
    # along with the additional conditions
    exprs.extend(["is_cube(OWN)", "is_square(ONE)"])
    
    # run the solver, and output the answer
    SubstitutedExpression(exprs, answer="ENIGMATIC", verbose=16).run()
    

    Solution: ENIGMATIC = 920876403.

  2. GeoffR 1 July 2022 at 3:08 pm
    % A Solution in MiniZinc
    include "globals.mzn";
    
    var 1..9:E; var 0..9:N; var 0..9:I; var 0..9:G; var 0..9:M;
    var 0..9:A; var 0..9:T; var 0..9:C; var 1..9:O; var 0..9:W;
    
    constraint all_different([E, N, I, G, M, A, T, C, O, W]);
    
    % the pyramid of digits below ENIGMATIC
    var 0..9: a1; var 0..9: a2; var 0..9: a3; var 0..9: a4;
    var 0..9: a5; var 0..9: a6; var 0..9: a7; var 0..9: a8;
    
    var 0..9: b1; var 0..9: b2; var 0..9: b3; var 0..9: b4;
    var 0..9: b5; var 0..9: b6; var 0..9: b7;
    
    var 0..9: c1; var 0..9: c2; var 0..9: c3;
    var 0..9: c4; var 0..9: c5; var 0..9: c6;
    
    var 0..9: d1; var 0..9: d2; var 0..9: d3;
    var 0..9: d4; var 0..9: d5; var 0..9: d6;
    
    var 0..9: e1; var 0..9: e2; var 0..9: e3;
    var 0..9: e4; var 0..9: g1; var 0..9: g2;
    var 0..9: h1;
    
    % ONE is a perfect square
    var 100..999:ONE == 100*O + 10*N + E;
    % OWN is a perfect cube
    var 100..999:OWN == 100*O + 10*W + N;
    
    set of int: sq3 = {n*n | n in 10..31}; 
    set of int: cb3 = {n*n*n | n in 5..9};
    
    constraint OWN in cb3 /\ ONE in sq3;
    
    %   E  N  I  G  M  A  T  I  C
    %    a1 a2 a3 a4 a5 a6 a7 a8
    %      b1 b2 b3 b4 b5 b6 b7
    %        c1 c2 c3 c4 c5 c6
    %         d1 d2 d3 d4 d5
    %           e1 e2 e3 e4
    %             6  6  6
    %              g1 g2
    %                h1
    
    % construct inverted pyramid of digits
    constraint abs(E - N) == a1 /\ abs(N - I) == a2 /\ abs(I - G) == a3
    /\ abs(G - M) == a4 /\ abs(M - A) == a5 /\ abs(A - T) == a6
    /\ abs(T - I) == a7 /\ abs(I - C) == a8;
    
    constraint abs(a1 - a2) == b1 /\ abs(a2 - a3) == b2 /\ abs(a3 - a4) == b3
    /\ abs(a4 - a5) == b4 /\ abs(a5 - a6) == b5 /\ abs(a6 - a7) == b6
    /\ abs(a7 - a8) == b7;
    
    constraint abs(b1 - b2) == c1 /\ abs(b2 - b3) == c2 /\ abs(b3 - b4) == c3
    /\ abs(b4 - b5) == c4 /\ abs(b5 - b6) == c5 /\ abs(b6 - b7) == c6;
    
    constraint abs(c1 - c2) == d1 /\ abs(c2 - c3) == d2 /\ abs(c3 - c4) == d3
    /\ abs(c4 - c5) == d4 /\ abs(c5 - c6) == d5;
    
    constraint abs(d1 - d2) == e1 /\ abs(d2 - d3) == e2 /\ abs(d3 - d4) == e3
    /\ abs (d4 - d5) ==  e4;
    
    constraint abs(e1 - e2) == 6 /\ abs(e2 - e3) == 6 /\ abs(e3 - e4) == 6;
    constraint g1 == 0 /\ g2 == 0 /\ h1 == 0;
    
    solve satisfy;
    
    output ["ENIGMATIC = \(E)\(N)\(I)\(G)\(M)\(A)\(T)\(I)\(C)"
     ++ "\n" ++ "OWN = " ++ show(OWN) ++ ", " ++ "ONE = " ++ show(ONE)];
     
    % ENIGMATIC = 920876403
    % OWN = 512, ONE = 529
    % ----------
    % ==========
    
    
    
  3. Frits 1 July 2022 at 3:49 pm

    Working our way from the 6, 6, 6 row to the top.

       
    # 3-digits cubes with different digits
    cubes = [cub for i in range(5, 10) 
             if len(set(cub := str(i**3))) == 3]
    cub02 = {cub[0] + cub[2] for cub in cubes}
    
    # 3-digits squares with different digits for which a possible cube exist
    squares = [sq for i in range(10, 32) if (sq := str(i**2))[:2] in cub02 and
               len(set(sq)) == 3]
    
    EN = []
    skip = set()
    
    # one solution for OWN and ONE?
    if len(squares) == 1:
      EN = [int(x) for x in squares[0][1:][::-1]]
      # if a 9 exist it will always remain if we move up in the triangle
      mult9 = 0 if 9 in EN else 1
      
      skip.add(int(squares[0][0]))
    
      cub = [x for x in cubes if x[0] + x[2] == squares[0][:2]]
      if len(cub) == 1 :
        skip.add(int(cub[0][1]))
        
    def solve(k, s):
      if k == 0:
        # solution should match ENIGMATIC
        if len(set(s)) != 8 or s[2] != s[7]: return
        if EN and s[:2] != EN: return 
        # numbers O and W are not allowed
        if skip and any(x in skip for x in s): return 
          
        yield s
      else:
        # early reject if E and N are known
        if k == 1 and EN and s[0] != abs(EN[1]- EN[0]): return
        # early reject if multiple 9's are used
        if not mult9 and s.count(9) > 1: return
         
        for r in higher(len(s) + 1, len(s), s):
          yield from solve(k - 1, r)
    
    # generate a valid higher row in the triangle    
    def higher(k, m, target, ns=[]):
      if k == 0:
        yield ns
      else:
        for i in range(10):
          if ns == [] or abs(ns[-1] - i) == target[m - k]:
            yield from higher(k - 1, m, target, ns + [i])
    
    # print triangle
    for s in solve(6, [6, 6, 6]):
      curr = ()
      pref = ""
      while curr == () or len(curr) > 1:
        curr = s if not curr else \
               list(abs(x - y) for (x, y) in zip(curr, curr[1:]))
        print(pref, *curr)
        pref += " "  
    

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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

%d bloggers like this: