# Enigmatic Code

Programming Enigma Puzzles

## Enigma 1694: The town clock prank

From New Scientist #2861, 21st April 2012 [link]

Our town clock has a standard 12-hour face, divided into 60 minute marks. The hands do not move smoothly: the minute hand moves sharply on to the next minute mark at the end of each minute, and the hour hand moves at the end of each 12 minutes.

The other day, a prankster swapped the hands (an operation that only took a few seconds between movements of the mechanism). Immediately after the swap, the clock showed the wrong time, but it was a valid time; in other words, the relative positions of the hands made sense. Within the next 10 minutes, the clock had shown the right time for exactly 2 minutes.

What time did the clock show immediately before the hands were swapped?

[enigma1694]

### 4 responses to “Enigma 1694: The town clock prank”

1. Jim Randell 18 April 2012 at 7:24 pm

The following Python code runs in 51ms.

```from enigma import printf

# the clock face has 60 divisions
# make a list of valid times for 12 hours
valid = list((i // 12, i % 60) for i in range(0, 12 * 60))

# convert division hour hand is pointing to to the actual hour
def hour(t):
h = t // 5
return 12 if h == 0 else h

# now find elements which are also a valid time when swapped
swapped = []
for i, p in enumerate(valid):
s = tuple(reversed(p))
if s not in valid: continue
swapped.append(i)

# and find a run of 3 valid swapped elements with 10 minutes of each other
n = len(swapped)
for i in range(n):
s = list(swapped[j % n] for j in range(i, i + 3))
if s[2] - s[0] > 10: continue
# swapped time can only be right if the hands are on top of each other
# but this can't happen at the time of the swap
ts = list(valid[j] for j in s)
if list(t[0] == t[1] for t in ts) != [False, True, True]: continue

# show the actual times and the displayed times
for t in ts:
printf("time = {h0}:{t[1]:02d} -> {h1}:{t[0]:02d}", h0=hour(t[0]), h1=hour(t[1]))
print()
```

Solution: The clock was showing 11:54 when the hands were switched.

• Jim Randell 18 April 2012 at 9:58 pm

And a slightly more efficient variation (although it’s not noticeably faster).

```from enigma import printf

# the clock face has 60 divisions
# make a list of valid times for 12 hours
valid = list((i // 12, i % 60) for i in range(0, 12 * 60))

# convert division hour hand is pointing to to the actual hour
def hour(t):
h = t // 5
return 12 if h == 0 else h

# now find elements which are also a valid time when swapped
swapped = list(i for i, p in enumerate(valid) if tuple(reversed(p)) in valid)

# and elements where the hands are superimposed
same = set(i for i, p in enumerate(valid) if p[0] == p[1])

# and find a run of 3 valid swapped elements with 10 minutes of each other
n = len(swapped)
for i in range(n):
s = list(swapped[j % n] for j in range(i, i + 3))
if s[2] - s[0] > 10: continue
# the swap changes to a different time
if s[0] in same: continue
# and the other two times should be the same
if not(s[1] in same and s[2] in same): continue

# show the actual times and the displayed times
ts = list(valid[j] for j in s)
for t in ts:
printf("time = {h0}:{t[1]:02d} -> {h1}:{t[0]:02d}", h0=hour(t[0]), h1=hour(t[1]))
print()
```
• Jim Randell 18 April 2012 at 11:02 pm

Here’s a version that finds the two times that are correct first, and then goes back to find when the hands were swapped. It runs in 34ms.

```from enigma import irange, sprintf, printf

# the clock face has 60 divisions
# make a list of valid times for 12 hours
valid = list((i // 12, i % 60) for i in range(0, 12 * 60))

# convert divisions to standard times
def time(t):
(h, m) = (t[0] // 5, t[1])
if h == 0: h = 12
return sprintf("{h:02d}:{m:02d}")

# find elements where the hands are superimposed
same = list(i for (i, p) in enumerate(valid) if p[0] == p[1])
n = len(same)

# find two times when the hands are the same that are within 10 (in fact 9) minutes of each other
for (i, s1) in enumerate(same):
s2 = same[(i + 1) % n]
d = (s2 - s1) % 720
if d > 9: continue
# and then look for a time within 10 minutes of the second time
# where the hands are valid when swapped (but not the same)
for j in irange(1, 10 - d):
t0 = valid[s1 - j]
if s1 - j in same: continue
if (t0[1], t0[0]) not in valid: continue

# show the times and the displayed times
for t in (t0, valid[s1], valid[s2]):
printf("time = {t} -> {s}", t=time(t), s=time((t[1], t[0])))
print()
```
2. Brian Gladman 19 April 2012 at 9:05 am

Here is my version:

```
full_day = 12 * 60
# create dictionaries to/from time and hand positions
# (hand positions in 6 degree units)
time_to_clock = dict()
clock_to_time = dict()
for time in range(full_day):
time_to_clock[time] = (time // 12, time % 60)
clock_to_time[(time // 12, time % 60)] = time

for time in range(0, full_day):
# get hour and minute hand positions
h_pos, m_pos = time_to_clock[time]
# check time shown is wrong but valid
if h_pos != m_pos and (m_pos, h_pos) in clock_to_time:
# find times in next 10 minutes when clock is right
times = []
for t in range(time, time + 10):
# get hour and minute hand positions
h_p, m_p = time_to_clock[t % 720]
# get time shown when hands are swapped
try:
clock_time = clock_to_time[(m_p, h_p)]
except KeyError:
continue
# count how many times the clock is correct
if clock_time == t % 720:
times += [(t // 60, t % 60)]
if len(times) == 2:
print('{0:02d}:{1:02d} ('.format(time // 60, time % 60), end='')
print('{0[0]:02d}:{0[1]:02d}, '.format(times[0]), end='')
print('{0[0]:02d}:{0[1]:02d})'.format(times[1]))
```