Enigmatic Code

Programming Enigma Puzzles

Enigma 773: Duodecimal

From New Scientist #1928, 4th June 1994 [link]

Two warnings about the sum shown here: the first is that it is a sum in base 12 throughout; the second is that in the bottom line the first O is the letter O (since no number starts with a zero), bit the subsequent O’s may be the letter O or the digit zero and the I may be the letter I or the digit one. Elsewhere O is the letter O wherever it appears and the I in FIVE is the letter I. Each letter stands for a different digit and the same letter represents the same digit wherever it appears.

If you want to have a chance of winning the tenner prize, please send in the value (in base 12) of FIVER.

[enigma773]

13 responses to “Enigma 773: Duodecimal

  1. Jim Randell 22 April 2024 at 11:54 am

    Here is a solution using the [[ SubstitutedExpression ]] solver from the enigma.py library.

    It runs in 81ms. (The internal runtime of the generated program is 1.3ms).

    Run: [ @replit ]

    #! python3 -m enigma -r
    
    SubstitutedExpression
    
    --base=12
    --distinct="EFINORUV"
    --answer="{FIVER}"
    
    "{ONE} * 4 = {FOUR}"
    "{FOUR} + {ONE} = {FIVE}"
    "{FIVE} * 2 = {Oxyz}"
    "{x} in {{O}, 0}"
    "{y} in {{I}, 1}"
    "{z} in {{O}, 0}"
    

    The answer is reported as an integer (so appears in decimal format), but we can use [[ --answer="int2base({FIVER}, 12)" ]] to have it reported as a base 12 string.

    Solution: FIVER = 17960 (base 12).

    The completed sum (in base 12) is:

    The final row being:

    3 = O
    3 = O
    7 = I
    0

    In decimal the sums are:

    570 × 4 = 2280
    2280 + 570 = 2850
    2850 × 2 = 5700
    FIVER = 34200

    • Frits 22 April 2024 at 6:03 pm

      With “–reorder=0” three loops are used instead of six.

      • Jim Randell 23 April 2024 at 6:17 am

        @Frits: Nice. And it brings the internal runtime down to 344µs.

        • Frits 23 April 2024 at 12:20 pm

          also:

               
          # 4 * ONE is a 4 digit number
          --invalid="0-2,O"
          # ONE = 144.O + 12.N + E, FIVE = 720.O + 60.N + 5.E
          # so FIVE ends on 5.E % 12, this can only be equal to E if E % 3 == 0
          --invalid="1|2|4|5|7|8|10|11,E"
          

          I have a Python only version which is even faster (but not ready for publishing, I don’t fully understand it myself!).
          It also seems to be the case the R of FOUR must always be zero.

        • Frits 23 April 2024 at 1:14 pm

          Already checking E and O without knowing N.

           
          #! python3 -m enigma -r
           
          SubstitutedExpression
           
          --base=12
          --distinct="EFINORUV"
          --answer="{FIVER}"
          --reorder=0
          # 4 * ONE is a 4 digit number
          --invalid="0-2,O"
          # ONE = 144.O + 12.N + E, FIVE = 720.O + 60.N + 5.E
          # so FIVE ends on 5.E % 12, this can only be equal to E if E % 3 == 0
          # FOUR = 576.O + 48.N + 4.E
          --invalid="1|2|4|5|7|8|10|11,E"
          #--verbose=256
          
          "(10 * {E}) % 12 in {0, {O}}" 
          "{ONE} * 4 = {FOUR}"
          "{FOUR} + {ONE} = {FIVE}"
          "{FIVE} * 2 = {Oxyz}"
          "{x} in {{O}, 0}"
          "{y} in {{I}, 1}"
          "{z} in {{O}, 0}"    
          
    • Jim Randell 23 April 2024 at 3:38 pm

      Here is a solution that uses the [[ SubstitutedExpression.split_sum() ]] solver, from the enigma.py library.

      It has an internal runtime of 69µs.

      Run: [ @replit ]

      #! python3 -m enigma -r
      
      SubstitutedExpression.split_sum
      
      --base=12
      --distinct="EFINORUV"
      --answer="{FIVER}"
      
      "{ONE} + {ONE} + {ONE} + {ONE} = {FOUR}"
      "{FOUR} + {ONE} = {FIVE}"
      "{FIVE} + {FIVE} = {Oxyz}"
      
      --extra="{x} in {{O}, 0}"
      --extra="{y} in {{I}, 1}"
      --extra="{z} in {{O}, 0}"
      
      • Frits 23 April 2024 at 8:03 pm

        @Jim, have you considered updating SubstitutedExpression.split_sum to handle special expressions?

        e.g. you might remove expression ({F} + {e} = {F}) and only allow zero for “e”.

        Also an optimization might be done for R and c.

        Following is the generated strategy:

          
         [strategy: 
            ({E} + {E} + {E} + {E} = {aR}) [1+2]
         -> ({E} + {E} = {fz}) [0+2]
         -> ({R} + {E} = {cE})  [0+1]
         -> ({z} in {{O}, 0})  [1+0]
         -> ({O} + {O} + {d} = {eI})  [1+2]
         -> ({I} + {I} + {g} = {hx})  [1+2]
         -> ({x} in {{O}, 0})  [0+0]
         -> ({O} + {O} + {O} + {O} + {b} = {FO})  [1+1]
         -> ({F} + {e} = {F})  [0+0]
         -> ({F} + {F} + {h} = {O})  [0+0]
         -> ({N} + {N} + {N} + {N} + {a} = {bU})  [1+1]
         -> ({U} + {N} + {c} = {dV})  [0+1]
         -> ({V} + {V} + {f} = {gy})  [0+1]
         -> ({y} in {{I}, 1})  [0+0]
         -> ({FIVER}) [0+0]
        ]
        
  2. ruudvanderham 22 April 2024 at 1:39 pm

    Here’s my brute-force version:

    import itertools
    
    
    def to_base(number, base):
        result = ""
        while number:
            result += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[number % base]
            number //= base
        return result[::-1] or "0"
    
    
    for o, n, e, f, u, r, i, v in itertools.permutations("0123456789AB", 8):
        one = int(o + n + e, 12)
        four = int(f + o + u + r, 12)
        if one * 4 == four:
            five = int(f + i + v + e, 12)
            ooio = to_base(five * 2, 12)
            if ooio[0] == o and ooio[1] in (o, "0") and ooio[3] in (o, "0") and ooio[2] in (i, "1"):
                print(f + i + v + e + r)
    
  3. Brian Gladman 22 April 2024 at 8:20 pm
    from itertools import permutations
    
    base = 12
    
    # return the digits of an four digit integer in base 'base'
    def split(n4):
      n3, z = divmod(n4, base)
      n2, y = divmod(n3, base)
      w, x = divmod(n2, base)
      return w, x, y, z
    
    # return an integer in base 'base' as a string
    def base12(n):
      return (('' if n < 12 else base12(n // base))
                + '0123456789AB'[n % base])
    
    for E, N, O in permutations(range(13), 3):
      ONE = base * (base * O + N) + E
    
      FOUR = 4 * ONE
      F, O, U, R = split(FOUR)
      if 2 * F < 12:
    
        FIVE = 5 * ONE
        F_, I, V, E_ = split(FIVE)
        if (E_, F_) == (E, F):
    
          OOIO = 2 * FIVE
          O1, O2, I1, O3 = split(OOIO)
          if (O1 == O and O2 in {O, 0} and
              I1 in {I, 1} and O3 in {O, 0}):
    
            print(f'FIVER = {base12(FIVE * base + R)}')
            print(f'     {base12(ONE)}')
            print(f'  x    4')
            print(f'   -----')
            print(f'    {base12(FOUR)}')
            print(f'  +  {base12(ONE)}')
            print(f'   -----')
            print(f'    {base12(FIVE)}')
            print(f'  x    2')
            print(f'   -----')
            print(f'    {base12(OOIO)}')
            print(f'   =====')
    
    • Frits 23 April 2024 at 1:54 pm

      @Brian, I first thought you had made a typo (range(13)) but it is needed as you do permutations. However, you don’t process all ONE’s like 143 or ONE < 14.

  4. GeoffR 24 April 2024 at 7:42 pm

    Fortunately, previous work enabled me to fix upper bounds of variables and work in base 10 for this solution, converting the answer to base 12.

    % A Solution in MiniZinc
    include "globals.mzn";
    
    var 1..11:O; var 0..11:N; var 0..11:E; 
    var 1..11:F; var 0..11:U; var 0..11:R;
    var 0..11:I; var 0..11:V; 
    
    constraint all_different([O, N, E, F, U, R, V]);
    
    int: i = 1;
    
    var 100..999:ONE == 144*O + 12*N + E;
    var 1000..9999:FOUR == 1728*F + 144*O + 12*U + R;
    var 1000..9999:FIVE == 1728*F + 144*I + 12*V + E;
    var 10000..99999: FIVER == 12*1728*F + 1728*I + 144*V + 12*E + R;
    
    constraint ONE * 4 = FOUR;
    constraint FOUR + ONE = FIVE;
    
    % Substitute abcd for OO1O inteaser
    var 1..11:a; var 0..11:b; var 0..11:c; var 0..11:d; 
    constraint a == O;
    constraint b == O \/ b == 0;
    constraint c == i \/ c == I;
    constraint d == O \/ d == 0;
    
    var 1000..9999:abcd == 1728*a + 144*b + 12*c + d;
    
    constraint FIVE * 2 = abcd;
    
    solve satisfy;
    
    output["FIVER = " ++ show(FIVER)  
    ++ "\n" ++ "ONE =  " ++ show(ONE)
    ++ "\n" ++ "FOUR = " ++ show(FOUR) 
    ++ "\n" ++ "FIVE = " ++ show(FIVE) ];
    
    % FIVER = 34200
    % ONE =  570
    % FOUR = 2280
    % FIVE = 2850
    % ----------
    % ==========
    
    .
    
    

    To convert 34200 in base 10 to base 12:
    Divide the number by 12 repeatedly and record the remainders.
    34200 / 12 = 2850 remainder 0
    2850 / 12 = 237 remainder 6
    237 / 12 = 19 remainder 9
    19 / 12 = 1 remainder 7
    1 / 12 = 0 remainder 1

    Write the remainders in reverse order to get the number in base 12.
    The number 34200 in base 10 is equal to 17960 in base 12.

Leave a Comment

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