# Enigmatic Code

Programming Enigma Puzzles

## Enigma 814: Mixed and matched

I had a day at the health club recently. I planned to have one full session of squash, one full session of badminton and one full session in the sauna (but not necessarily in that order) with at least a one-hour break between each of the sessions. The club’s timetable of sessions is shown above.

By coincidence my colleagues Mark and Jenny also spent the day there with the same idea in mind (although none of us necessarily did any of the activities together).

Our boss (who knew all the above facts) tried to telephone me at one stage but was told I was busy. From this he was able to work out my exact day’s schedule.

An hour later he tried to telephone Mark but was told he was busy and he was told the activity which Mark was engaged in. From this my boss was able to work out Mark’s exact schedule.

Another hour later he tried to telephone Jenny but was told she was busy and he was told the activity which Jenny was engaged in. From this my boss was able to work out Jenny’s exact schedule.

Which is the correct order of the men’s, women’s, and mixed sessions in the sauna?

[enigma814]

### One response to “Enigma 814: Mixed and matched”

1. Jim Randell 13 March 2023 at 11:30 am

This Python program runs in 59ms. (Internal runtime is 1.3ms).

Run: [ @replit ]

```from enigma import (
irange, tuples, subsets, singleton, flatten, peek,
update, join, sprintf, map2str, printf
)

# represent times in minutes
T = lambda h, m: h * 60 + m

sessions = {
# squash sessions: 45m sessions starting at 10:15 - 16:15
'sq': list(tuples(irange(T(10, 15), T(16, 15) + 45, step=45), 2)),
# badminton sessions: 60m sessions, starting at 10:00 - 16:00
'ba': list(tuples(irange(T(10, 00), T(16, 00) + 60, step=60), 2)),
# sauna sessions, 120m sessions
'sa': [ (T(10, 00), T(12, 00)), (T(12, 30), T(14, 30)), (T(15, 00), T(17, 00)) ],
}

# return activities in progress; key -> time
def progress(t):
d = dict()
# select activities in progress at time t
for (k, vs) in sessions.items():
for (a, b) in vs:
if a <= t < b:
d[k] = (a, b)
return d

# complete a schedule that is busy at time t
def schedule(d):
# choose an unrepresented activity
k = peek((k for k in sessions.keys() if k not in d), default=None)
if k is None:
yield d
else:
# look for times that don't interfere with existing activities
for (x, y) in sessions[k]:
if all(a >= y + 60 or x >= b + 60 for (a, b) in d.values()):
yield from schedule(update(d, [(k, (x, y))]))

# format times
time = lambda *ts: join((sprintf("{h:02d}:{m:02d}", h=t // 60, m=t % 60) for t in ts), sep=" - ")

# format a schedule
fmt = lambda ss: map2str(((time(a, b), k) for (k, (a, b)) in ss.items()), arr=" = ", sep="; ")

# consider times the call for josie could be made
for t1 in irange(T(10, 15), T(14, 45), step=15):
# times of subsequent calls
(t2, t3) = (t1 + 60, t1 + 120)
# collect possible activities in progress at time t
d = progress(t1)
# look for a time that gives a unique schedule
ss1 = singleton(flatten((schedule({k: v}) for (k, v) in d.items()), fn=iter))
if ss1 is None: continue

# collect activities in progress for mark's call
d = progress(t2)
# look for an activity that gives a unique schedule
for (k, v) in d.items():
ss2 = singleton(schedule({k: v}))
if ss2 is None: continue

# collect activities in progress for jenny's call
d = progress(t3)
for (k, v) in d.items():
ss3 = singleton(schedule({k: v}))
if ss3 is None: continue
# output schedules
printf("call @ {t} -> josie = {ss}", t=time(t1), ss=fmt(ss1))
printf("call @ {t} -> mark ({k}) = {ss}", t=time(t2), ss=fmt(ss2))
printf("call @ {t} -> jenny ({k}) = {ss}", t=time(t3), ss=fmt(ss3))
# consider Male, Female, miXed sauna sessions
for (M, F, X) in subsets(sessions['sa'], size=3, select='P'):
# no males in the Female session, and no females in the Male session
if ss1['sa'] == M or ss2['sa'] == F or ss3['sa'] == M: continue

printf("male = {M}; female = {F}; mixed = {X}", M=time(*M), F=time(*F), X=time(*X))
printf()
```

Solution: 10:00 – 12:00 = ladies only; 12:30 – 2:30 = men only; 3:00 – 5:00 = mixed.

The setter (Josie, who I assume is female) has a schedule as follows:

10:15 – 11:00 = squash
11:00 – 12:00 = break
13:00 – 15:00 = break
15:00 – 17:00 = sauna

Her phone call came in at 12:00, when she had just started her badminton session.

Mike (male) has the following schedule:

11:00 – 12:30 = break
12:30 – 13:15 = squash
13:15 – 15:00 = break
15:00 – 17:00 = sauna

His phone call came in at 13:00 when he was in the middle of a squash session.

Josie and Mike are in the same sauna session, so it must be the mixed session.

Jenny has two possible schedules:

10:00 – 12:00 = sauna
12:00 – 14:00 = break
14:00 – 14:45 = squash
14:45 – 16:00 = break