Enigmatic Code

Programming Enigma Puzzles

Enigma 778: Trying triangle

From New Scientist #1933, 9th July 1994 [link]

Put a digit into each circle and read each side of the triangle clockwise, as a three-figure number. (For example, if I put a 2 in the top left-hand corner and continued, clockwise, 4, 6, 1, 4, 9, then the three-figure numbers would be 246, 614 and 492: notice that 492 is a multiple of 246, but 614 isn’t).

Your job is to choose the digits so that the second and third three-figure numbers are different multiples of the first three figure number.

What are the numbers in your triangle (clockwise from the top left-hand corner)?

[enigma778]

7 responses to “Enigma 778: Trying triangle

  1. Jim Randell 25 March 2024 at 8:15 am

    It is straightforward to use the [[ SubstitutedExpression ]] solver from the enigma.py library to solve this puzzle.

    The following run file executes in 81ms. (Internal runtime of the generated program is 8.2ms).

    Run: [ @replit ]

    #! python3 -m enigma -r
    
    SubstitutedExpression
    
    #  A - B - C
    #   \     /
    #    F   D
    #     \ /
    #      E
    
    --distinct=""
    
    "CDE % ABC = 0"
    "EFA % ABC = 0"
    
    "CDE != EFA"
    

    Solution: The triangle looks like this:

    And we have:

    399 = 133 × 3
    931 = 133 × 7

  2. ruudvanderham 25 March 2024 at 8:47 am

    This is my code:

    import itertools
    
    for n0, n1, n2, n3, n4, n5 in itertools.product(range(1, 10), repeat=6):
        p0 = n0 * 100 + n1 * 10 + n2
        p1 = n2 * 100 + n3 * 10 + n4
        p2 = n4 * 100 + n5 * 10 + n0
        if p2 % p0 == 0 and p1 % p0 == 0 and len({p0, p1, p2}) == 3:
            print(p0, p1, p2)
    
  3. ruudvanderham 25 March 2024 at 11:58 am

    Here’s an extremely performant solution (less then 1 msec on my computer):

    import itertools
    import time
    
    t0 = time.perf_counter()
    for side1 in range(100, 1000):
        n0 = side1 // 100
        n2 = side1 % 10
        if n2 > n0:  # otherwise, it can't be a multiple of side1
            side2 = ((n2 * 100 // side1) + 1) * side1  # try first multiple of side1 starting with n2
            if side2 != side1 and side2 < (n2 + 1) * 100:  # check whether multiple really starts with n2
                n4 = side2 % 10  # n4 is last digit of second side == first digit of third side
                if n4 > n0:  # otherwise, it can't be a multiple of side1
                    side3 = ((n4 * 100 // side1) + 1) * side1  # try first multiple of p0 starting with n4
                    if side3 != side1 and side3 < (n4 + 1) * 100:  # check whether multiple really starts with n4
                        n6 = side3 % 10  # last digit of third side
                        if n6 == n0:  # check whether this is the same as the first digit of the first side
                            print(side1, side2, side3)
    print(f"{(time.perf_counter()-t0)*1000} msec")
    
    • Frits 25 March 2024 at 10:58 pm

      Very fast, one minor error (e.g. for side1 125 the calculated side2 is too high). I adapted your version to this:

      from math import ceil
      
      # highest multiple * side1 < 1000
      for side1 in range(101, 334):
        n0 = side1 // 100
        n2 = side1 % 10
        # if n2 is even then n0 must also be even and n2 > n0
        # otherwise, it can't be a multiple of side1
        if (n2 % 2 or n0 % 2 == 0) and n2 > n0:  
          # try first multiple of side1 starting with n2
          side2 = ceil(n2 * 100 / side1) * side1 
          # check whether multiple really starts with n2
          if side2 < (n2 + 1) * 100:
            # n4 is last digit of second side == first digit of third side
            n4 = side2 % 10  
            if n4 > n0:  # otherwise, it can't be a multiple of side1
              # try first multiple of p0 starting with n4
              side3 = ceil(n4 * 100 / side1) * side1 
              # check whether multiple really starts with n4   
              if side3 < (n4 + 1) * 100:  
                n6 = side3 % 10  # last digit of third side
                # check whether this is the same as the first digit of the first side
                if n6 == n0:  
                  # answering the question
                  print("answer:", [n0, (side1 % 100) // 10, n2, (side2 % 100) // 10,
                                    n4, (side3 % 100) // 10])     
      
  4. GeoffR 25 March 2024 at 1:35 pm
    % A Solution in MiniZinc
    include "globals.mzn";
    
    %  A - B - C
    %   \     /
    %    F   D
    %     \ /
    %      E
    
    var 1..9:A; var 1..9:B; var 1..9:C; 
    var 1..9:D; var 1..9:E; var 1..9:F;
    
    var 100..999:ABC == 100*A + 10*B + C;
    var 100..999:CDE == 100*C + 10*D + E;
    var 100..999:EFA == 100*E + 10*F + A;
    
    constraint CDE != EFA;
    constraint CDE mod ABC == 0 /\ EFA mod ABC == 0;
    
    solve satisfy;
    
    output ["Numbers: [A,B,C,D,E,F] = " ++ show([A,B,C,D,E,F])];
    
    % Numbers: [A,B,C,D,E,F] = [1, 3, 3, 9, 9, 3]
    % ----------
    % ==========
    
  5. Frits 26 March 2024 at 1:53 pm

    Three times faster according to multiple runs with timeit.

    from math import ceil
    
    #  A - B - C
    #   \     /
    #    F   D
    #     \ /
    #      E
    
    # E is 0 or 5 if C is equal to 5 (both not allowed)
    for C in [x for x in range(2, 10) if x != 5]:
      # if C is even then A and E must also be even
      for A in range((stp := 1 + (C % 2 == 0)), C, stp):
        # highest multiple * ABC < 1000
        if A > 3 or C * A > 9: break
        for B in range(10):
          # break if 2 * (10 * A + B) // 10 > C
          if 2 * (10 * A + B) > 10 * C + 9: break 
          ABC = 100 * A + 10 * B + C  
          # try first multiple of ABC starting with C 
          if (CDE := ceil(100 * C / ABC) * ABC) // 100 != C: continue
          E = CDE % 10
          # try first multiple of ABC starting with E 
          if E == C or (EFA := ceil(100 * E / ABC) * ABC) // 100 != E: continue
          if EFA % 10 != A: continue
          print(f"answer: {A}, {B}, {C}, {(CDE % 100) // 10}, "
                f"{E} and {(EFA % 100) // 10}")     
    

Leave a Comment

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