# Exercise 2: choose a characteristic among neighbours, then identify lights from stopwatch readings. NEIGHBOURS = {"Fl(2) W 10s": ("Fl", 2, 10), "Fl W 8s": ("Fl", 1, 8), "Oc W 6s": ("Oc", 1, 6)} CANDIDATES = {"Fl(3) W 15s": ("Fl", 3, 15), "Fl W 10s": ("Fl", 1, 10), "Fl(2) W 12s": ("Fl", 2, 12), "Oc W 6s": ("Oc", 1, 6), "Fl W 3s": ("Fl", 1, 3), "Iso W 8s": ("Iso", 1, 8)} FLASH_S = 1 def passes_rules(cls, n, period): if cls in ("Iso", "Oc"): return True if n == 1: return 2 <= period <= 15 and period - FLASH_S >= 3 * FLASH_S return period <= (20 if n == 2 else 30) def confusable(a, b): return a[0] == b[0] and a[1] == b[1] and abs(a[2] - b[2]) < 3 # Part 1: test each candidate against the rules and the neighbours. for name, c in CANDIDATES.items(): clashes = [nb for nb, v in NEIGHBOURS.items() if confusable(c, v)] print(name, "| rules:", passes_rules(*c), "| clashes:", clashes or "none", "->", "ok" if passes_rules(*c) and not clashes else "reject") # Part 2: identify a light from flash start times (seconds). def identify(starts): gaps = [round(b - a, 1) for a, b in zip(starts, starts[1:])] if len(set(gaps)) == 1: return 1, gaps[0] long_gap = max(gaps) first = gaps.index(long_gap) second = gaps.index(long_gap, first + 1) return second - first, round(sum(gaps[first:second]), 1) WATCHES = { "A": [1.0, 6.0, 11.0, 16.0, 21.0, 26.0], "B": [2.0, 4.0, 14.0, 16.0, 26.0, 28.0, 38.0], "C": [0.0, 2.0, 4.0, 15.0, 17.0, 19.0, 30.0], } for name, starts in WATCHES.items(): n, period = identify(starts) print("watch", name, "-> flashes per group", n, "| period", period, "s") # Part 3: the shortest watch that can show two full periods of the slowest candidate. slowest = max(c[2] for c in CANDIDATES.values()) print("slowest candidate period:", slowest, "s; two full periods:", 2 * slowest, "s") # Fl(3) W 15s | rules: True | clashes: none -> ok # Fl W 10s | rules: True | clashes: ['Fl W 8s'] -> reject # Fl(2) W 12s | rules: True | clashes: ['Fl(2) W 10s'] -> reject # Oc W 6s | rules: True | clashes: ['Oc W 6s'] -> reject # Fl W 3s | rules: False | clashes: none -> reject # Iso W 8s | rules: True | clashes: none -> ok # watch A -> flashes per group 1 | period 5.0 s # watch B -> flashes per group 2 | period 12.0 s # watch C -> flashes per group 3 | period 15.0 s # slowest candidate period: 15 s; two full periods: 30 s