Teaser 3135: Rhythmic gymnastics
From The Sunday Times, 23rd October 2022 [link] [link]
Skaredahora used three rhythmic patterns of quaver beats in a short, purely percussive, composition. His “Dotykam” rhythm has accents on beats 1, 4, 6, 7, 8, 10 & 11; “Kluc” has accents on beats 1, 8 and one particular beat in between; and “Omacka” has accents on beats 1, 2, 5, 6 & 10. Several percussion instruments are involved, each playing one of the three rhythms, but starting at different times. Overall the patterns overlap, with every beat in the composition being filled by an accent from exactly one of the instruments, and all the patterns finishing by the end of the composition.
What is the other beat of Kluc, and what is the order of appearance of the rhythmic patterns (e.g. DOOKD)?
[teaser3135]
Jim Randell 4:51 pm on 21 October 2022 Permalink |
This Python program considers possible additional accent positions for pattern K, and then fills out patterns with an accent on every beat, but no overlaps, until there is a continuous sequence of accents.
It runs in 54ms. (Internal runtime is 372µs).
Run: [ @replit ]
from enigma import (irange, inf, update, peek, printf) # the rhythm patterns D = [1, 4, 6, 7, 8, 10, 11] K = [1, None, 8] # a beat in the range [2, 7] is missing O = [1, 2, 5, 6, 10] # disjoint union of two sets (or None) def disjoint_union(ss, xs): ss = set(ss) for x in xs: if x in ss: return ss.add(x) return ss # fill out patterns from <ps> with an accent on every beat # starting from <s> def solve(ps, s=1, vs=[], bs=set()): # we are done if there are no missing beats if bs and len(bs) == max(bs): yield vs else: # find the first missing beat b = peek(k for k in irange(s, inf) if k not in bs) # and choose a pattern to start here for (k, pattern) in ps.items(): bs_ = disjoint_union(bs, (x + b - 1 for x in pattern)) if bs_ is not None: yield from solve(ps, s + 1, vs + [(k, b)], bs_) # consider the missing beat in pattern K for k in irange(2, 7): for vs in solve(dict(D=D, K=update(K, [1], [k]), O=O)): printf("k={k} vs={vs}")Solution: Kluc has an additional accent on beat 5. The order of the patterns as: OOKKDDK.
The composition lasts for 33 beats (or a multiple of 33 beats). The patterns being:
Which covers all beats from 1 – 33.
In order for the composition to end after 33 beats with each beat being accented by exactly one of the instruments, we need pattern K to end after the last accented beat. Pattern D can have 0 or 1 non-accented beats after the last accented beat. And pattern O could have up to 21 non-accented beats after the last accented beat.
LikeLike
NigelR 10:47 am on 25 October 2022 Permalink |
Less elegant than Jim’s solution, but gets the job done!
rhy = [[1, 4, 6, 7, 8, 10, 11],[1, 2, 8],[1, 2, 5, 6,10]] patts=('DO','KL','OM') ntotxt = lambda k : [[patts[j[0]],j[1]] for j in k] #makes print out more intelligible using labels score = lambda k : sorted([y+x[1]-1 for x in k for y in rhy[x[0]]]) # creates list of beat numbers filled gap = lambda k : sorted([x for x in range(1,len(k)+1) if x not in k]) # identifies gaps in beat sequence for n in range(2,8): # iterate for missing value in KL rhy[1][1] = n seq=[[0,1]] #Initialise seq. Entries in seq are in format:[pattern no.,starting beat] while seq: beats=score(seq) if dup:=len(beats)-len(set(beats)): #if overlap of beats found, go back in sequence while seq and seq[-1][0]==2: seq.pop() if not seq:break seq[-1][0]+=1 #try next pattern in exisiting sequence else: #no overlaps in current sequence if g:=gap(beats): # start next pattern at first gap in sequence seq.append([0,g[0]]) else: # if no gap and no overlaps, solution has been found print('solution found: ',ntotxt(seq), ' n=',n) exit() print('options exhausted for n=' ,n)LikeLike