Enigmatic Code

Programming Enigma Puzzles

Enigma 1627: A riddle for the sphinx

From New Scientist #2792, 25th December 2010 [link]

Those with a classical education will know that the sphinx was a riddle-setting monster associated with the Greek city of Thebes. I took the sum

ETA + BETA + THETA = DELTA

and replaced letters consistently with digits. Even if I told you the value of B, you still could not find all the digits, but if in addition I told you that PSI and PHI were prime, you could.

Find THEBES.

[enigma1627]

4 responses to “Enigma 1627: A riddle for the sphinx

  1. jimrandell 14 December 2011 at 11:56 am

    This Python program runs in 65ms.

    I have another version that runs in 34ms that does more early rejection based on the fact 3×A must end in A, and 3×TA must end in TA, but it’s a much longer program. In fact, it’s pretty obvious what A and T must be given this constraint, and if you modify this program to start with those values for A and T it only takes 32ms to run.

    from itertools import permutations
    from enigma import is_prime, printf
    
    d = set(range(10))
    for (E, T, A, B, H) in permutations(d, 5):
      TA = 10*T + A
      ETA = 100*E + TA
      BETA = 1000*B + ETA
      THETA = 10000*T + 1000*H + ETA
      DELTA = ETA + BETA + THETA
      if not(DELTA % 100 == TA): continue
      s = str(DELTA)
      if len(s) != 5: continue
      if not(int(s[-4]) == E): continue
      D = int(s[-5])
      L = int(s[-3])
    
      d1 = d.difference((E, T, A, B, H, D, L))
      if len(d) - len(d1) != 7: continue
      for (S, I, P) in permutations(d1, 3):
        PSI = 100*P + 10*S + I
        if not is_prime(PSI): continue
        PHI = 100*P + 10*H + I
        if not is_prime(PHI): continue
    
        THEBES = 100000*T + 10000*H + 1010*E + 100*B + S
    
        printf("ETA={ETA} BETA={BETA} THETA={THETA} DELTA={DELTA} A={A} T={T} E={E} L={L} B={B} H={H} D={D}")
        printf("THEBES={THEBES} PSI={PSI} PHI={PHI} S={S} I={I} P={P}")
    

    Solution: THEBES = 542823.

  2. Jim Randell 8 January 2013 at 3:27 pm

    Here’s a solution that uses the [[ SubstitutedSum() ]] solver from the enigma.py module. Although it’s not that much shorter, but it is a little bit faster – it runs in 45ms.

    from collections import defaultdict
    from itertools import permutations
    from enigma import irange, is_prime, SubstitutedSum, printf
    
    # record solutions to the sum by the value of B
    r = defaultdict(list)
    p = SubstitutedSum(['ETA', 'BETA', 'THETA'], 'DELTA')
    for s in p.solve():
      r[s['B']].append(s)
    
    # consider non-unique solutions for B
    ds = set(irange(0, 9))
    for (k, v) in r.items():
      if len(v) < 2: continue
      for s in v:
        # the remaining digits are P, S, I
        for x in permutations(ds.difference(s.values())):
          s.update(zip('PSI', x))
          PSI = p.substitute(s, 'PSI')
          if not is_prime(int(PSI)): continue
          PHI = p.substitute(s, 'PHI')
          if not is_prime(int(PHI)): continue
    
          THEBES = p.substitute(s, 'THEBES')
          printf("{p.text} / {s}", s=p.substitute(s, p.text))
          printf("THEBES={THEBES} PSI={PSI} PHI={PHI}")
    
  3. geoffrounce 14 June 2018 at 8:09 am
    % A Solution in MiniZinc
    include "globals.mzn";
     
    var 0..9: E;  var 0..9: T;  var 0..9: A;  var 0..9: P;
    var 0..9: S;  var 0..9: I;  var 0..9: B;  var 0..9: H;   
    var 0..9: D;  var 0..9: L;
    
    constraint E > 0 /\ P > 0 /\ B > 0 /\ T > 0 /\ D > 0 ;
    
    constraint all_different ( [E, T, A, P, S, I, B, H, D, L] );
    
    var 100..999 : ETA = 100*E + 10*T + A;
    var 100..999 : PSI = 100*P + 10*S + I;
    var 100..999 : PHI = 100*P + 10*H + I;
    var 1000..9999 : BETA = 1000*B + 100*E + 10*T + A;
    var 10000..99999 : THETA = 10000*T + 1000*H + 100*E + 10*T + A;
    var 10000..99999 : DELTA = 10000*D + 1000*E + 100*L + 10*T + A;
    var 100000..999999 : THEBES = 100000*T + 10000*H + 1000*E + 100*B + 10*E + S;
    
    predicate is_prime(var int: x) = 
      x > 1 /\ forall(i in 2..1 + ceil(sqrt(int2float(ub(x))))) 
      ((i < x) -> (x mod i > 0));
      
    constraint is_prime(PSI) /\ is_prime(PHI);
     
    constraint ETA + BETA + THETA = DELTA;
    
    solve satisfy;
    
    output [ "Sum is: " ++ show(ETA) ++ " + " ++ show(BETA) ++ " + " 
    ++ show(THETA) ++  " = " ++ show(DELTA) ++ "\n" 
    ++ "THEBES = " ++ show (THEBES) ++ "\n"
    ++ "PSI = " ++ show(PSI) ++ ", " ++ "PHI = " ++ show(PHI) ];
    
    % Sum is: 250 + 8250 + 54250 = 62750
    % THEBES = 542823
    % PSI = 139, PHI = 149
    

    @Jim: Would your filter_unique library function work OK on this Enigma ?

    • Jim Randell 14 June 2018 at 11:27 pm

      @geoff: Yes, you can use the [[ filter_unique() ]] function in a solution to this problem:

      from collections import namedtuple
      from enigma import SubstitutedExpression, filter_unique, is_prime, printf
      
      # the alphametic sum
      p = SubstitutedExpression(
        'ETA + BETA + THETA = DELTA',
         answer="(B, (A, B, D, E, H, L, T), (PSI, PHI), THEBES)"
      )
      
      # find all solutions
      S = namedtuple('S', 'B letters words answer')
      ss = list(S(*ans) for (s, ans) in p.solve(verbose=1))
      
      # "if I told you the value of B you could not find all the digits"
      (_, ss) = filter_unique(ss, (lambda s: s.B), (lambda s: s.letters))
      
      # but we only want solutions where PSI and PHI are prime
      ss = filter((lambda s: all(is_prime(w) for w in s.words)), ss)
      
      # output solutions
      for s in ss:
        printf("THEBES={s.answer} [(A, B, D, E, H, L, T) = {s.letters}, (PSI, PHI) = {s.words}]")
      

      The strange thing is that the “even if I told you the value of B, you still could not find all the digits” part of the puzzle is superfluous. As you have found you can just write a program that ignores this part of the puzzle and instead uses the fact that PSI and PHI are prime. This “additional” fact actually narrows the possible solutions to a single candidate anyway, so you can do without line 15 and the call to [[ filter_unique() ]].

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 )

Google photo

You are commenting using your Google 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: