Teaser 2100: Uncle Hex
From The Sunday Times, 15th December 2002 [link]
The standard hexadecimal notation used in some computations needs 16 “hex-digits”, so it uses 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E and F — e.g. the hex-number DEC15 represents the decimal number: 13×16⁴ + 14×16³ + 12×16² + 1×16 + 5 = 912405.
Of course, only a few dates (like today’s) can look like a hex-number in that way (with some dates having a choice of hex-number, like DEC08/DEC8). My Uncle Hex and I have noticed we both have birthdays that look like hex-numbers. We have each worked out a decimal number that our birthday can represent and, comparing notes, we see that between them those two decimal numbers use each of the digits 0 to 9 at least once. Uncle Hex’s next birthday comes before mine.
When is Uncle Hex’s birthday?
Teaser 2100 – 2105 were originally published in The Sunday Times with the numbers 3000 – 3005.
[teaser2100]
Jim Randell 7:41 am on 30 May 2023 Permalink |
This Python program generates all the dates in a leap year, and finds those that give viable “hex-dates” (obviously it would be more efficient to just consider months that consist entirely of hex digits).
We then look for a pair of hex-dates that have values that between them use all 10 digits when represented in decimal form.
It runs in 75ms. (Internal runtime is 12ms).
Run: [ @replit ]
from datetime import (date, timedelta) from enigma import (repeat, inc, sprintf, base2int, catch, subsets, union, int2base, printf) # generate possible "hex-dates" def generate(): # month names months = "? JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC".split() # consider dates in 2000 (a leap year) for d in repeat(inc(timedelta(days=1)), date(2000, 1, 1)): if d.year > 2000: break (m, d) = (months[d.month], d.day) for fmt in ["{m}{d}", "{m}{d:02d}"]: s = sprintf(fmt) v = catch(base2int, s, base=16) if v is not None: yield (s, v) # collect "hex-dates" d = dict(generate()) # find pairs that use 10 different digits when expressed in decimal for ((k1, v1), (k2, v2)) in subsets(d.items(), size=2): ds = union(int2base(v, base=10) for v in (v1, v2)) if len(ds) != 10: continue # output solution printf("{k1} -> {v1}; {k2} -> {v2}")Solution: Uncle Hex’s birthday is 4th February.
The two dates are:
The puzzle was set on 15th December, so the next of these dates to occur is 4th February.
LikeLike
Frits 6:54 pm on 30 May 2023 Permalink |
@Jim, I don’t see the requirement that each “hex-date” has to use distinct digits.
LikeLike
Jim Randell 7:13 pm on 30 May 2023 Permalink |
I don’t know where that came from. The [[
is_duplicate()]] test can be removed, and you still get the same answer.LikeLike
Frits 8:39 pm on 30 May 2023 Permalink |
Slow but more than three times faster with PyPy.
from enigma import SubstitutedExpression, int2base months = "JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC" days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] # check for valid "hex-date" def check(i): s = int2base(i, base=16) if not (3 < len(s) < 6): return 0 f = months.find(s[:3]) if f < 0: return 0 d = s[3:] if not d.isnumeric(): return 0 d = int(d) f //= 4 # so we have indices 0-11 if not (0 < d <= days[f]): return 0 return 100 * f + d # the alphametic puzzle p = SubstitutedExpression( [ # uncle HEX: UVWXYZ me: SOMERF "UVWXYZ > 43680", # start from AAA1 "check(UVWXYZ)", "len(set([U, V, W, X, Y, Z])) >= 4", "SOMERF > 43681", # start from AAA2 # those numbers use each of the digits 0 to 9 at least once "len(set([U, V, W, X, Y, Z, S, O, M, E, R, F])) == 10", # my number "check(SOMERF)", # uncle Hex's next birthday comes before mine "0 < check(UVWXYZ) < check(SOMERF)", ], answer="int2base(UVWXYZ, base=16)", d2i="", distinct="", env=dict(check=check), #reorder=0, verbose=0, # use 256 to see the generated code ) # print answers for (_, ans) in p.solve(): print(f"Uncle Hex's birthday: {ans}")LikeLike