Enigmatic Code

Programming Enigma Puzzles

Enigma 1771: Squares either way

From New Scientist #2939, 19th October 2013 [link] [link]

Whether you write dates in the order day.month.year or month.day.year (in each case with two digits for each element), 04.04.01 represents 4 April 2001, and it is a square date because 40401 is the square of 201.

In addition to 4 April 2001, there is one other date in this century that is written in exactly the same way in each order and is also a square date.

(1) What is that date?
(2) What is the next date after today that is a square date if written in the order day.month.year?
(3) What is the next date after today that is a square date if written in the order month.day.year?

Give each answer in the form of 4 April 2001.

[enigma1771]

3 responses to “Enigma 1771: Squares either way

  1. Jim Randell 16 October 2013 at 7:22 pm

    This Python program uses the standard Python date library to validate dates, and if you have an English locale it should output the dates in the required format. It runs in 38ms.

    from datetime import date
    from enigma import irange, printf
    
    # today's date
    today = date(2013, 10, 16)
    
    # convert y, m, d to a valid date, or None if invalid
    def to_date(y, m, d):
      try:
        return date(2000 + y, m, d)
      except ValueError:
        return None
    
    # format a date
    def fmt(t):
      return t.strftime("%d %B %Y").lstrip('0')
    
    # record dmy and mdy square dates
    (d1, d2) = ([], [])
    
    # consider 5- and 6-digit squares
    for i in irange(101, 557):
      s = "{:06d}".format(i * i)
      (x, y, z) = (int(t) for t in (s[0:2], s[2:4], s[4:6]))
      dmy = to_date(z, y, x)
      mdy = to_date(z, x, y)
      if dmy: d1.append(dmy)
      if mdy: d2.append(mdy)
      
    # (1) dates that represent the same way
    for t in d1:
      if t.day == t.month and t in d2:
        printf("(1) {t}", t=fmt(t))
    
    # (2) first dmy date after today
    for t in sorted(d1):
      if t > today:
        printf("(2) {t}", t=fmt(t))
        break
    
    # (3) first mdy date after today
    for t in sorted(d2):
      if t > today:
        printf("(3) {t}", t=fmt(t))
        break
    

    Solution: (1) 7 July 2056. (2) 6 May 2016. (3) 8 January 2016.

  2. Brian Gladman 16 October 2013 at 8:44 pm

    I didn’t like this one much.

    from itertools import product
    from datetime import date
    
    # question one
    for y, dm in product(range(100), range(1, 13)):
      x = 10100 * dm + y  
      if round(x ** 0.5) ** 2 == x:
        print('1)', date(2000 + y, dm, dm).strftime('%d %B %Y').lstrip('0'))
    
    # question two
    for y, m, d in product(range(13, 100), range(1, 32), range(1, 13)):
      x = 100 * (100 * d + m) + y
      if round(x ** 0.5) ** 2 == x:
        print('2)', date(2000 + y, m, d).strftime('%d %B %Y').lstrip('0'))
        break
    
    # question three
    for y, m, d in product(range(13, 100), range(1, 32), range(1, 13)):
      x = 100 * (100 * m + d) + y
      if round(x ** 0.5) ** 2 == x:
        print('3)', date(2000 + y, m, d).strftime('%d %B %Y').lstrip('0'))
        break
    
    • Brian Gladman 17 October 2013 at 8:08 am

      A correction of a stupid error and a small speed up.

      from itertools import product
      from datetime import date
      
      # quadratic residues mod 100 for years
      q = sorted(set((x * x) % 100 for x in range(100)))
      
      # question one
      for y, dm in product(q, range(1, 13)):
        x = 10100 * dm + y  
        if round(x ** 0.5) ** 2 == x:
          print('1)', date(2000 + y, dm, dm).strftime('%d %B %Y').lstrip('0'))
      
      # question two
      for y, m, d in product(q, range(1, 13), range(1, 32)):
        if y > 12:
          x = 100 * (100 * d + m) + y
          if round(x ** 0.5) ** 2 == x:
            print('2)', date(2000 + y, m, d).strftime('%d %B %Y').lstrip('0'))
            break
      
      # question three
      for y, m, d in product(q, range(1, 13), range(1, 32)):
        if y > 12:
          x = 100 * (100 * m + d) + y
          if round(x ** 0.5) ** 2 == x:
            print('3)', date(2000 + y, m, d).strftime('%d %B %Y').lstrip('0'))
            break
      

Leave a Comment

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