Euklidische Rhythmen erzeugen

8

Wussten Sie, dass der euklidische Algorithmus traditionelle musikalische Rhythmen erzeugen kann ? Wir werden sehen, wie dies funktioniert, indem wir einen ähnlichen, aber etwas anderen Algorithmus als den in diesem Artikel beschriebenen beschreiben.

Wählen Sie eine positive Ganzzahl n, die Gesamtzahl der Schläge, und eine positive Ganzzahl k, die Anzahl der Schläge, die erklingen (Noten). Wir können uns den Rhythmus als eine Folge von nBits vorstellen, kvon denen 1s sind. Die Idee des Algorithmus ist es, die Einsen so gleichmäßig wie möglich unter den Nullen zu verteilen.

Zum Beispiel beginnen wir mit n = 8und k = 5mit 5 Einsen und 3 Nullen, jede in ihrer eigenen Reihenfolge:

[1] [1] [1] [1] [1] [0] [0] [0]

Zu jedem Zeitpunkt werden wir zwei Arten von Sequenzen haben - die am Anfang sind die "Kern" -Sequenzen und die am Ende sind die "Rest" -Sequenzen. Hier sind die Kerne [1]s und die Reste sind [0]s. Solange wir mehr als eine Restsequenz haben, verteilen wir sie auf die Kerne:

[1 0] [1 0] [1 0] [1] [1]

Jetzt ist der Kern [1 0]und der Rest ist [1], und wir verteilen wieder:

[1 0 1] [1 0 1] [1 0]

Jetzt ist der Kern [1 0 1]und der Rest ist [1 0]. Da wir nur eine Restsequenz haben, halten wir an und holen den String

10110110

So klingt es, 4 Mal wiederholt:

Hier ist ein weiteres Beispiel mit n = 16und k = 6:

[1] [1] [1] [1] [1] [1] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0]
[1 0] [1 0] [1 0] [1 0] [1 0] [1 0] [0] [0] [0] [0]
[1 0 0] [1 0 0] [1 0 0] [1 0 0] [1 0] [1 0]
[1 0 0 1 0] [1 0 0 1 0] [1 0 0] [1 0 0]
[1 0 0 1 0 1 0 0] [1 0 0 1 0 1 0 0]
1001010010010100

Beachten Sie, wie wir den letzten Schritt mit zwei Kernsequenzen und keinen Restsequenzen beendet haben. Hier wird es zweimal wiederholt:

Eingang

Sie können eine Funktion oder ein vollständiges Programm schreiben, das von STDIN, der Befehlszeile oder ähnlichem gelesen wird. Die Eingabe besteht aus zwei positiven Ganzzahlen nund k <= nist vermutlich in beliebiger Reihenfolge.

Ausgabe

Ihre Aufgabe ist es, den generierten Rhythmus als nzeichenlange Zeichenfolge auszugeben . Sie können zwei verschiedene druckbare ASCII-Zeichen (0x20 bis 0x7E) auswählen, um Noten und Pausen darzustellen.

Testfälle

Die folgenden Testfälle werden xzur Darstellung von Notizen und .s zur Darstellung von Pausen verwendet. Die Eingabe wird in der angegebenen Reihenfolge n, dann k.

1 1    ->  x
3 2    ->  xx.
5 5    ->  xxxxx
8 2    ->  x...x...
8 5    ->  x.xx.xx.
8 7    ->  xxxxxxx.
10 1   ->  x.........
11 5   ->  x.x.x.x.x..
12 7   ->  x.xx.x.xx.x.
16 6   ->  x..x.x..x..x.x..
34 21  ->  x.xx.x.xx.xx.x.xx.x.xx.xx.x.xx.x.x
42 13  ->  x...x..x..x..x...x..x..x..x...x..x..x..x..
42 18  ->  x..x.x.x..x.x.x..x.x.x..x.x.x..x.x.x..x.x.

Wertung

Dies ist Code-Golf, also gewinnt der Code in den wenigsten Bytes.

Sp3000
quelle

Antworten:

5

CJam, 37 34 30 27 24 Bytes

3 Bytes von user23013 gespeichert.

q~,f>{_(a-W<}{e`:a:e~z}w

Dies nimmt die Eingabe als kerste, nzweite. Es verwendet 1und 0, um Noten bzw. Pausen anzuzeigen.

Probieren Sie es hier aus. Alternativ finden Sie hier ein Testkabel, das alle angegebenen Testfälle ausführt (Austausch der Eingabereihenfolge) und die Ausgabe neu formatiert, um sie zu verwenden xund den .Vergleich mit den Referenzlösungen zu erleichtern. (Die Ergebnisse, die in der Eingabe des Testkabels angezeigt werden, werden vor dem Ausführen des Codes verworfen. Sie können sicher entfernt werden, ohne das Programm zu beeinträchtigen.)

Erläuterung

q~                       e# Read and eval the input, dumping k and n on the stack.
  ,                      e# Create a range [0 .. n-1]
   f>                    e# For each of them, check if it's less than k.
                         e# This gives k 1s and n-k 0s.
     {      }{        }w e# While the first block yields a truthy result, execute
                         e# the second block.
      _                  e# Duplicate the array.
       (a-               e# Remove all instances of core sequences.
          W<             e# Remove one remainder sequence if there is one. This
                         e# gives an empty array (falsy) whenever there are less
                         e# than two remainder sequences.
              e`         e# Run-length encode. I.e. this turns an array into a list
                         e# of pairs of run-length and element.
                :a:e~    e# Wrap each RLE pair in an array and RLD it. This
                         e# partitions the array into cores and remainders.
                     z   e# Zip the two parts, interleaving cores and remainders.

Dieser Prozess verschachtelt sehr tief Arrays, aber der wichtige Teil ist, dass alle Kerne (und alle verbleibenden) immer die gleiche verschachtelte Struktur haben, so dass sie immer noch gleich sind. CJam druckt den Stapelinhalt automatisch am Ende des Programms und lässt Array-Trennzeichen vollständig weg, daher wirkt sich diese Struktur auch nicht auf die Ausgabe aus.

Martin Ender
quelle
2 oder 3 Bytes kürzer : q~\,f>.
Jimmy23013
@ user23013 Oh, das ist ordentlich! Vielen Dank. :)
Martin Ender
Für 3 Bytes meinte ich, dass die Eingabe in beliebiger Reihenfolge erfolgen kann.
Jimmy23013
@ user23013 Oh richtig, das habe ich vergessen.
Martin Ender
1

Haskell, 125 Bytes

r=replicate
g z(a:b)(c:d)=g((a++c):z)b d
g z x y=(z,x++y)
f(x,y)|length y>1=f$g[]x y|1<2=concat$x++y
n#k=f(r k "x",r(n-k)".")

Anwendungsbeispiel: 42 # 13-> x...x..x..x..x...x..x..x..x...x..x..x..x...

fnimmt zwei Parameter: Kern- und Restliste. Entweder komprimiert es beide Listen (via g) und ruft sich erneut auf oder stoppt, wenn der Rest zu kurz ist. Die Hauptfunktion #erstellt die Startlisten und Aufrufef .

Nimi
quelle
1

Python, 85

f=lambda n,k,a='1',b='0':n-k<2and a*k+b*(n-k)or[f(n-k,k,a+b,b),f(k,n-k,a+b,a)][2*k>n]

Die natürliche rekursive Lösung. Die Parameter (n,k,a,b)stellen einen Kern von k a's dar, gefolgt von einem Rest vonn-k b' s.

Diese Lösung ist ineffizient, da beide rekursive Aufrufe an f ausgewertet werden und eine exponentielle Anzahl von Aufrufen verursachen.

Ich habe versucht, den bedingten Aufruf von flike zu komprimieren

f(max(n-k,k),min(n-k,k),a+b,[a,b][2*k<n])
f(*[n-k,k,k,n-k,b,a][2*k>n::2]+[a+b])

aber keiner fiel kürzer aus.

xnor
quelle