Enigmatic Code

Programming Enigma Puzzles

Enigma 426: Time and again

From New Scientist #1576, 3rd September 1987 [link]

Time and again, you’ve been asked to sort out letters-for-digits puzzles, where digits are consistently replaced by letters, different letters being used for different digits. Today, that recurring theme is used in a truly recurring way. The fraction on the left (which is in its simplest form) represents the recurring decimal on the right. Should you want an extra optional clue, I can also tell you that the last two digits of the numerator of the fraction are equal.

Enigma 426

What is AGAIN?

[enigma426]

3 responses to “Enigma 426: Time and again

  1. Jim Randell 11 December 2017 at 8:09 am

    A little bit of analysis:

    If the numerator of the fraction is x, we can derive the integer equation:

    (10^8 – 1)x = TIME × ANDAGAIN

    Using the extra optional clue, we can consider numerators of the form abb, which means we only have to consider two digit numbers of the form ab and then we can just add an extra b digit to the end. So we only have to check 90 values for x.

    This Python program runs in 97ms.

    Run: [ @repl.it ]

    from enigma import irange, divisors_pairs, gcd, nsplit, printf
    
    # numerator x in the form abb (it is possible that a = b)
    for ab in irange(10, 99):
      x = (ab * 10) + (ab % 10)
      for (TIME, ANDAGAIN) in divisors_pairs(99999999 * x):
        # TIME has 4 digits
        if TIME < 1000: continue
        if TIME > 9999: break
    
        # and x / TIME is a fraction in its simplest form
        if gcd(x, TIME) != 1: continue
    
        # TIME consists of 4 distinct digits
        (T, I, M, E) = nsplit(TIME)
        if not(len(set((T, I, M, E))) == 4): continue
    
        # check the digits in ANDAGAIN
        ds = nsplit(ANDAGAIN)
        if len(ds) != 8: continue
        (A, N, D, A1, G, A2, I1, N1) = ds
        if not(A == A1 == A2 and N == N1 and I == I1 and len(set((T, I, M, E, A, N, D, G))) == 8): continue
        
        printf("AGAIN = {AGAIN} [{x} / {TIME} = 0.({ANDAGAIN})...]", AGAIN=ANDAGAIN % 100000)
    

    Solution: AGAIN = 38354.

    The actual expression is:

    522 / 1507 = 0.(34638354)…

    where the digits in brackets repeat indefinitely.

    Without the extra clue we can consider all three digit values of x from 100 to 999 (900 values), which takes the above program 289ms to consider.

    But without being told anything about the “shape” of x we can solve the puzzle as an alphametic, and find that there is only one solution. (Even when the fraction is allowed to be not in lowest terms).

    This Python program uses the [[ SubstitutedExpression() ]] solver from the enigma.py library and runs in 557ms.

    from enigma import SubstitutedExpression, gcd, printf
    
    # express the puzzle as an alphametic expression
    p = SubstitutedExpression(
      [ "(TIME * ANDAGAIN) % 99999999 = 0" ],
      d2i={ 0: 'T' },
      answer="(TIME, ANDAGAIN)"
    )
    
    # solve the alphametic
    for (s, (TIME, ANDAGAIN)) in p.solve():
      # extract the numerator of the fraction
      x = (TIME * ANDAGAIN) // 99999999
      # check the fraction is in lowest terms
      if gcd(x, TIME) != 1: continue
      # output the solution
      printf("{x} / {TIME} = 0.({ANDAGAIN})...")
    
  2. Brian Gladman 11 December 2017 at 10:15 pm
    from number_theory import divisor_pairs
      
    # Using the extra clue the expression is equivalent
    # to: XYY * (10^8 - 1) = TIME * ANDAGAIN
    
    # try possible numerators of form XYY
    for xy in range(10, 100):
      xxy = 10 * xy + xy % 10
      # split the right hand side into two factors
      for time, andagain in divisor_pairs(xxy * (10 ** 8 - 1)):
        # extract eight different digits and check duplicates
        try:
          T, I, M, E = str(time)
          A, N, D, a1, G, a2, i, n = str(andagain)
          if not (a1 == a2 == A and i == I and n == N
                     and len({A, D, E, G, I, M, N, T}) == 8):
            raise ValueError
        except ValueError:
          continue
        print(' ' * 26 + '_' * 8)
        print(f'AGAIN = {andagain % 100000} ({xxy}/{time}=0.{andagain})')
    
  3. geoffrounce 12 December 2017 at 5:03 pm
    digits = set('1234567890')
     
    from itertools import permutations
    for p1 in permutations(digits, 5):
      a, g, i, n, d = p1
      if a == '0': continue
      again = int(a + g + a + i + n)
      andagain = int(a + n + d + a + g + a + i + n)
      
      p2 = digits.difference(p1)
      for q1 in permutations(p2, 3):
        t, m, e  = q1
        if t == '0': continue
        time = int(t + i + m + e)
        xyy, r = divmod(time * andagain, 10 ** 8 - 1)
        if not r:
          print("AGAIN = ", again)
          
    #AGAIN =  38354
    

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: