Akordy fortepianu na białych klawiszach

9

Historia [co nie jest prawdą]

Fortepian jest skonfigurowany w następujący sposób:

! [http://www.piano-lessons-made-simple.com/images/2-Octave-Labled.gif

Jednak na moim pianinie wszystkie czarne klawisze są zepsute!

Nadal chcę jednak móc grać akordy na moim złamanym pianinie.

W muzyce akord to grupa nut granych razem. Aby umożliwić wprowadzanie akordów, najpierw zdefiniuję, czym jest półton.

Co to jest półton?

Półton to najmniejsza odległość w muzyce zachodniej. Jeśli spojrzysz na górną część fortepianu, zobaczysz, że zazwyczaj możesz przejść z czarnego klawisza na biały klawisz lub odwrotnie; Jednak między Bi Ca Ei Fnie ma czarny klucz.

Co to jest akord?

Na potrzeby tego wyzwania definiujemy akord jako wiązkę nut z pewną liczbą półtonów między nimi. Na przykład weźmy 4-3-3akord od początku C(dla muzyków jest to akord V 7 F-dur). Zaczynamy o C. Liczymy się 4 półtony: C#, D, D#, E. Kolejna uwaga to Ei liczymy 3 półtony w górę po tym: F, F#, G. Kolejna uwaga to Gi liczymy 3 półtony w górę po tym: G#, A, Bb. Więc rozumiemy C-E-G-Bb. Tak! Ale czekaj ... Bbto czarny klucz, a te są zepsute ... Jednak jeśli zaczniemy G, dostaniemy G-B-D-F! Tak!

Wejście

Dane wejściowe podano jako listę liczb całkowitych w dowolnym rozsądnym formacie. To reprezentuje akord, jak opisano powyżej.

Wynik

Wyjście powinno być listą notatek, na których mogę zacząć używać tylko białych klawiszy. Może to być również ciąg wszystkich maksymalnie 7 nut, ponieważ wszystkie nazwy kluczy będą jednym znakiem. Musisz być w stanie poradzić sobie z pustym wyjściem.

Przypadki testowe

input -> output // comments
4 3 -> C F G // this is a major triad
3 4 -> D E A // this is a minor triad
4 3 3 -> G // this is the major-minor seventh chord
3 3 3 -> [empty output] // this is the diminished-diminished seventh chord. All of them use black keys
4 4 -> [empty output] // this is an augmented triad
3 3 -> B // this is a diminished triad
1 -> B E // this is just a minor second
11 -> C F // this is just a major seventh

Inne specyfikacje

  • Standardowe luki zabronione
  • Możesz założyć, że wejście ma co najmniej jedną liczbę całkowitą
  • Możesz założyć, że wszystkie liczby całkowite są nieujemne i mniejsze niż 12 (ponieważ fortepian powtarza się co 12 nut)
  • Dane wyjściowe mogą być w dowolnej kolejności

Zwycięskie kryteria

Najkrótsze ważne zgłoszenie do 15 kwietnia zostanie zaakceptowane.

HyperNeutrino
źródło
Możemy założyć „nieujemne i mniejsze niż 12” - czy nie powinno to być „dodatnie i mniejsze niż lub równe 12”?
Jonathan Allan
@JonathanAllan Zasadniczo nie ma różnicy; moja metoda pozwala na Perfect Unison, ale nie na Perfect Octave; twoja odwrotnie. Teoretycznie twoje ograniczenie może mieć więcej sensu, ale myślę, że prawdopodobnie nie powinienem go zmieniać, ponieważ są już odpowiedzi i nie zmienia to zasadniczo wyzwania.
HyperNeutrino

Odpowiedzi:

3

Galaretka , 25 bajtów

236ḃ2ṙЀ7+\€Ṭ
+\ịþ¢Ạ€TịØA

Wypróbuj online! lub zobacz pakiet testowy

W jaki sposób?

236ḃ2ṙЀ7+\€Ṭ - Link 1, white-note-offsets: no arguments
236ḃ2         - 236 in bijective base 2 [2, 2, 1, 2, 2, 1, 2] - semitones G->A, A->B ...
     ṙЀ7     - rotate left by, mapped over [1,2,3,4,5,6,7] - i.e. as above for each
                    starting white key (1st one A->B,B->C,...; 2nd B->C,C->D,...; etc)
         +\€  - reduce €ach with addition - i.e. absolute number of semitones: [[2,3,5,7,8,10,12],[1,3,5,6,8,10,12],[2,4,5,7,9,11,12],[2,3,5,7,9,10,12],[1,3,5,7,8,10,12],[2,4,6,7,9,11,12],[2,4,5,7,9,10,12]]
            Ṭ - untruth (vectorises) - make lists with 1s at those indexes: [[0,1,1,0,1,0,1,1,0,1,0,1],[1,0,1,0,1,1,0,1,0,1,0,1],[0,1,0,1,1,0,1,0,1,0,1,1],[0,1,1,0,1,0,1,0,1,1,0,1],[1,0,1,0,1,0,1,1,0,1,0,1],[0,1,0,1,0,1,1,0,1,0,1,1],[0,1,0,1,1,0,1,0,1,1,0,1]]

+\ịþ¢Ạ€TịØA - Main link: list of semitone gap integers (even negatives will work)
+\          - reduce by addition - gets the absolute semitone offsets needed
    ¢       - last link (1) as a nilad
   þ        - outer product with:
  ị         -     index into - 7 lists, each with 1s for white and 0s for black keys hit
                      note that indexing is modular and all the lists are length 12
                      so any integer is a valid absolute offset, not just 0-11 inclusive
     Ạ€     - all truthy for €ach - for each get a 1 if all keys are white ones, else 0
       T    - truthy indexes - get the valid starting white keys as numbers from 1 to 7
        ị   - index into:
         ØA -     the uppercase alphabet
Jonathan Allan
źródło
6

MATL , 31 bajtów

Dzięki Jonathanowi Allanowi za korektę.

'BAGFEDC'"GYs12X\110BQX@YSYsm?@

Wypróbuj online! Lub sprawdź wszystkie przypadki testowe .

Wyjaśnienie

Wzór 2 2 1 2 2 2 1określa odstępy między kolejnymi białymi klawiszami. Program wykorzystuje pętlę, która stosuje wszystkie cykliczne przesunięcia do tego podstawowego wzorca, w celu przetestowania każdego klawisza jako potencjalnie najniższej nuty akordu wejściowego. Dla każdej zmiany uzyskiwana jest skumulowana suma wzoru. Na przykład dla Bpotencjalnie najniższej nuty wzorzec został przesunięty do, 1 2 2 1 2 2 2a jego łączna suma to 1 3 5 6 8 10 12.

Teraz, aby sprawdzić, czy może to obsługiwać 4 3 3akord, obliczamy skumulowaną sumę interwałów akordu, która jest 4 7 10; zredukuj to za pomocą modulo 12 opartego na 1 (interwał 14dałby 2); i sprawdź, czy wszystkie te liczby są członkami dozwolonych wartości 1 3 5 6 8 10 12. W tym przykładzie tak nie jest. Gdyby tak było, wysłalibyśmy list B.

Zależność między przesunięciami cyklicznymi a literami wyjściowymi jest zdefiniowana przez ciąg 'BAGFEDC'. Oznacza to, że 'B'(pierwszy znak) odpowiada cyklicznemu przesunięciu o 1; 'A'(drugi znak) odpowiada cyklicznemu przesunięciu przez 2itp.

'BAGFEDC'  % Push this string
"          % For each character from the string
  G        %   Push input array
  Ys       %   Cumulative sum
  12X\     %   1-based modulo 12, element-wise (1,12,13,14 respectively give 1,12,1,2)
  110BQ    %   Push 110, convert to binary, add 1 element-wise: gives [2 2 1 2 2 2 1]
  X@       %   Push current iteration index, starting at 1
  YS       %   Cyclic shift to the right by that amount
  Ys       %   Cumulative sum
  m        %   Ismember. Gives an array of true of false entries
  ?        %   If all true
    @      %     Push current character
           %   End (implicit)
           % End (implicit)
           % Display (implicit)
Luis Mendo
źródło
5

Mathematica, 110 bajtów (kodowanie ISO 8859-1)

±i_:=#&@@@Select["A#BC#D#EF#G#"~StringTake~{Mod[#,12,1]}&/@#&/@(Accumulate[i~Prepend~#]&/@Range@12),FreeQ@"#"]

Definiuje jednoargumentową funkcję, ±przyjmującą listę liczb całkowitych jako dane wejściowe (w rzeczywistości nie ma ograniczeń co do rozmiaru lub znaków liczb całkowitych) i zwraca listę ciągów jednoznakowych. Na przykład ±{3,4}zwraca {"A","D","E"}.

"A#BC#D#EF#G#"~StringTake~{Mod[#,12,1]}&/@#to funkcja, która zamienia listę liczb całkowitych w odpowiadające im nazwy nut, z wyjątkiem tego, że #oznacza dowolny czarny klawisz. Odnosi się to do każdego elementu Accumulate[i~Prepend~#]&/@Range@12, który tworzy listę wartości nut z listy wejściowej listy przedziałów notatek, zaczynając od każdej możliwej nuty od 1 do 12. Odfiltrowujemy wszystkie takie listy nazw notatek, które zawierają "#"użycie Select[...,FreeQ@"#"], a następnie zwróć pierwszą notatkę z każdej pozostałej listy za pomocą #&@@@.

Greg Martin
źródło
Niezłe zgłoszenie!
HyperNeutrino
Pytanie: Czy Mathematica używa własnego systemu bajtów? Ma 110 znaków, ale w UTF-8 ma 111 bajtów z powodu +/-symbolu.
HyperNeutrino
Możesz całkowicie usunąć przypisanie i po prostu „domyślnie zwrócić” funkcję.
wizzwizz4,
@ wizzwizz4: Odkryłem, że muszę nazwać zmienną, Accumulate[i~Prepend~#]&ponieważ w przeciwnym razie doszłoby do starcia curry. Znajdź jednak obejście!
Greg Martin
@HyperNeutrino: masz rację, że UTF-8 jest standardowym kodowaniem, ale Mathematica może (zwykle) również działać w kodowaniu ISO 8859-1. Zauważyłem to w poście.
Greg Martin
3

Python 2, 159 155 bajtów

(Opublikowanie tego po upewnieniu się, że istnieje poprawne zgłoszenie, które jest krótsze od tego)

import numpy
s='C.D.EF.G.A.B'
def k(y):return lambda x:s[(x+y)%12]
for i in range(12):
    if s[i]!='.'and'.'not in map(k(i),numpy.cumsum(input())):print s[i]

Prawie tylko trywialne rozwiązanie. Wejścia jako lista liczb całkowitych i wyjścia z każdym znakiem w osobnym wierszu.

-4 bajty przez usunięcie niepotrzebnej zmiennej

HyperNeutrino
źródło
3

JavaScript (ES6), 72 71 68 bajtów

a=>[..."C1D1EF1G1A1B"].filter((c,i,b)=>!+c>a.some(e=>+b[i+=e,i%12]))

Pętle przechodzą przez każdy klawisz, pomijając czarne klawisze, a następnie sprawdzają, czy skumulowana suma półtonów nigdy nie wyląduje na czarnym klawiszu.

Edycja: Zapisano 3 bajty dzięki @Arnauld.

Neil
źródło
4
Czytelność?! Czy na pewno jesteś na właściwej stronie? :-)
wizzwizz4