Con dos nombres de nota, debe escribir un programa que determine si el intervalo formado por estas dos notas es consonante o disonante.
Introducción
En la música occidental, solo hay 12 tonos "diferentes". Sus nombres, ordenados de menor a mayor, son los siguientes: C, C#, D, D#, E, F, F#, G, G#, A, A#, B. La secuencia es cíclica, es decir, continúa con otra Cdespués de la B, infinitamente.
La distancia entre dos tonos se llama intervalo . El intervalo entre dos notas que son adyacentes en la serie anterior (por ejemplo, C — C#o E — F) se llama semitono . El intervalo entre notas más distantes se define como la cantidad de pasos de semitonos necesarios para pasar de la primera a la segunda (mientras se ajusta la secuencia). Algunos ejemplos: D to E= 2 semitonos, C to G= 7 semitonos, B to D#= 4 semitonos (esto envuelve la secuencia). 1
Ahora, estos intervalos se dividen en dos categorías: consonantes (que suena agradablemente si toca las dos notas a la vez) y disonante (no tanto).
Definamos los intervalos de consonantes como: 0, 3, 4, 5, 7, 8 y 9 semitonos.
El resto de ellos es disonante, a saber: 1, 2, 6, 10 y 11 semitonos.
El reto
Escriba un "programa" (en el sentido amplio habitual de la palabra: una función está perfectamente bien) para hacer lo siguiente:
Tome dos nombres de notas (cadenas de la secuencia anterior) como entrada. Puede tomarlos como quiera (desde stdin, como argumentos, separados por lo que quiera, incluso puede tomarlos como una lista de caracteres (por ejemplo
["C","#"]). Sin embargo, no puede asignar ningún otro nombre a las notas (especialmente usted no puede numerarlos del 0 al 11 y usar los números).Para los fanáticos de la música, las notas se especificarán sin la octava. En este caso, tampoco importa en qué orden vienen las notas y cuál es más bajo y cuál es más alto. Finalmente, no necesita manejar ningún nombre que no esté en la lista anterior. No hay otras enarmónicas como
E#, sin pisos, dobles alteraciones, etc.Elija dos valores diferentes. Su programa debe generar uno de ellos siempre que el intervalo formado por las dos notas en la entrada sea consonante, y el otro si no lo son. (Podría ser
TrueyFalse, pero incluso π y e si quieres :))Este es un código de golf. El programa más corto en bytes en cada idioma gana. ¡Que te diviertas!
Ejemplos y casos de prueba
Note 1 Note 2 Output Interval [semitones]
C D Dissonant 2
A# A# Consonant 0
G D Consonant 7 (wraparound)
D# A Dissonant 6
F E Dissonant 11
A C Consonant 3
No agrego más de ellos ya que no hay casos particularmente traicioneros en esto.
Este es un primer desafío mío, por lo que cualquier crítica constructiva es calurosamente bienvenida :—). Si encuentra la explicación de la teoría descuidada, no dude en hacer preguntas. Finalmente, por favor no me digas que esto es un engaño de esto o esto . Me aseguré de que no sea así. (Esto último es bastante similar pero más complejo. Pensé que presentar un desafío un poco más simple facilitaría la participación de las personas).
1 : Traté de simplificar esta explicación lo más que pude. Hay mucha más teoría sobre los intervalos. Por favor, no me critiques por dejarlo fuera.

APL (Dyalog),
6239 bytesUses
⎕IO←0; 0 is consonant, 1 is dissonant. Takes list of base note chars as left argument and list of sharps as right argument.Try it online!
{…}anonymous function where⍺is the left argument and⍵is the right argument⎕A[…]∊'BCGKL'is the Alphabet, indexed by the following, a member of the string?⍕#format the root namespace (yields the sharp character)⍵=are the right argument chars (the sharps) equal to that?(…)+add the following:'C D EF G A '⍳⍺indices of the left argument chars in the string-/difference between those|absolute valuefuente
MATL,
302726 bytesInputs the two notes in different lines. Outputs
0for consonant,1for dissonant.Try it online! Or verify all test cases.
Explanation
The 11-character string
encodes both the notes and the dissonant intervals, as follows.
The program first finds the 1-based indices of the input characters in the above string. A non-sharp input like
Dwill give1,Ewill give3, ...,Cwill give11. These numbers can also be considered 1×1 numeric arrays. A sharp input likeC#will give the 1×2 array[11 0], meaning thatCwas found at position11and#was not found.Observe that letters
JPILwill never be present in the input. For now they are only used as placeholders, so that for example noteEis two semitones aboveD. But they will also be useful to define dissonant intervals.The numbers in the first entry of the 1×1 or 1×2 array correspond to note pitch in semitones, not counting sharp symbols (yet). Observe that the scale defined by these numbers doesn't start at
C; but that doesn't matter because we only want intervals, that is, differences between notes. Subtracting the obtained numbers would give either the interval or 12 minus the interval. But first we need to consider the sharp symbol.To consider sharp notes, a golfy way (in MATL) is to add
1to each entry of the 1×1 or 1×2 array obtained previously and then sum the array (2 bytes). Thus non-sharp notes are increased by1and sharp notes by2. This makes sharp notes 1 semitone higher than non-sharp notes, as required. We are also adding an extra semitone to all notes, but that doesn't change the intervals between them. So now noteDwill give pitch number2,D#will give3, ...,Cwill give12,C#will give13.Dissonant intervals are
1,2,6,10, or11. These have a modulo-12 symmetry: an interval between two notes is dissonant if and only if the interval with the notes in reverse order, modulo 12, is dissonant.If we compute the consecutive differences of the string
'DJEFPGIALBC'we get the numeric vectorwhich contains precisely the dissonant intervals, in addition to some negative values, which will be neither useful nor harmful. Observe that it is the choice of additional letters
JPILin the string'DJEFPGIALBC'that defines (via consecutive differences) the dissonant intervals.To see if the two input notes are dissonant we take the absolute difference of their pitch numbers. For example,
CandD#will give numbers12and3respectively, and the absolute difference is9. The actual difference would be-9, and the actual interval would be3(obtained as-9modulo 12). But thanks to the symmetry referred to above, we can consider9instead of3. Since9is not present in the vector of consecutive differences, the notes are consonant.fuente
JavaScript (ES6),
6864 bytesTakes the notes as two strings in currying syntax
(a)(b). Returns0for dissonant or1for consonant.Test cases
Show code snippet
Formatted and commented
fuente
Jelly, 26 bytes
A monadic link taking a list of the two notes (as lists of characters) and returning
0for consonant and1for dissonant.Try it online! or see all inputs in the test-suite.
How?
fuente
Jelly, 31 bytes
Try it online!
wheeeeee 32 bytes too long
Explanation
fuente
"G#", "A"(dissonant) yields a difference of11which is not in[1,2,6].Mathematica, 55 bytes
Map the internal built-in
Sound`PitchToNumberon the input (list of two strings), take the absolute difference, then pattern match for dissonant interval numbers.Just for fun (non-competing)
Here are some shorter functions that violate the restriction “you may not assign any other names to the notes.” The rudimentary
Music`package has predefined note constants (likeA4 = 440.) and the functionHertzToCents(which can be golfed). Instead of strings, we will use the note constants as arguments, but given in a different format for each function.The package import
<<Music`;takes 9 bytes.This function converts a string (like
"F#") into a note constant (likeFsharp3):To accept intervals larger than an octave, replace
Abs[…]withMod[…,12].Why are some intervals considered dissonant? An interval is a ratio of two frequencies. If the ratio has a “simple” numerator and denominator, it tends to be more consonant. In 5-limit tuning, ratios can be factored into integer powers of only prime numbers less than or equal to 5. No interval in equal temperament, besides the octave, is a just interval; they are merely close approximations using powers of the 12th root of 2.
Instead of hard-coding which interval numbers are dissonant, we can find a rational approximation of the interval and then determine if its numerator and denominator are “simple” (meaning that the denominator is less than 5 and the ratio does not divide 7).
This table shows each of the steps in that process.
The rational approximation lies within
1/17of the interval because that is the largest threshold that distinguishes between all 12 equal tempered intervals. We match rational numbers with the patternRational[a_,b_](or justa_~_~b_) first, and then match integers with only_.This culminates in the following rather short function that determines if an arbitrary frequency ratio (greater than 1) is consonant or dissonant.
fuente
Mathematica, 118 bytes
Input form
Outputs
thanks @JonathanFrech -16 bytes
fuente
ConsonantandDissonant. You may output any two values instead of them (0/1,... whatever). That could save some bytes.If[...,0,1]and defineTrue->Consonant; False->Dissonant?StringCases["CC#DD#EFF#GG#AA#B",_~~"#"...]– 42 Bytes{1,2,6,10,11}with1|2|6|10|11Charcoal, 30 bytes
Try it online! Link is to verbose version of code. Outputs 1 for consonant, 0 for dissonant. Explanation:
fuente
⌕ζis used for "find index"?ζis the variable assigned to earlier.J, 68 bytes
explanation
A straightforward, not super golfed implementation in J:
Input is given as boxed itemized notes (produced using cut), in order.
Find their indexes in the range of notes:
(<;._1',C,C#,D,D#,E,F,F#,G,G#,A,A#,B')i.]Subtract the first from the second:
-~/Take the remainder when divided by 12:
12|Check if it's one of the dissonant notes:
e.&1 2 6 10 11Try it online!
fuente
///,
9088 bytesTry it online! (all test cases at once)
,B#in each test case.,for consonant,,#for dissonant.##) orE#in some particular cases. Otherwise the output is,for consonant,#,for dissonant (thanks to modulo 12 symmetry)fuente
C (gcc), 91 bytes
call:
f("A#", "D")Return value:
Bonus: The function is case insensitive.
Try it online!
fuente
return (s?g(char*s){s=(s[1]&1|2**s&15)*4/5;}f(char*x,char*y){x=1952220<<g(x)>>g(y)&2048;}and nice solution!Python 2,
125 117 83 7877 bytesWhere the
""at the end actually contains the characters"\x02\x04\x0c\x14\x16"Try it Online!
(+3 because I forgot 11 or 22 in the list to begin with)
-8 bytes from Jonathan Frech and switching to Python 2.
-34 bytes with suggestions from Jonathan Frech and using
str's index instead oflist's.-4 bytes from inlining
iand Neil's reversing the string suggestion (only -2 really, as i forgot()around a generator)-5 bytes from un-inlining
i& changing the input format-1 bytes from Jonathan Frech with
map()and unprintables.Takes input in one line of stdin in the format:
Trueis dissonant,Falseis consonant.Old Explanation:
Python
str.indexreturns the lowest (positive) starting index of a matching substring, so"ABACABA".index("A") == 0and"ABACABA".index("BA") == 1. Because of this, we can put the note names evenly spaced in a string, and as long as (for example)Acomes beforeA#, the sharedAwon't be a problem.iis now a function that returns the index in'C C#D D#E F F#G G#A A#B'its argument (a note name) is, which is 2 * (the number of semitones that note is up fromC)Python 2's
input()is (mostly) equivalent toeval(input())in Python3, so with a valid input of the format'C#','F'(for example),a='C#'andb='F'If the disttance between the first note and the second note in the string is not 2, 4, 12, or 20 (since the note names are represented in 2 characters), then the interval is dissonant, print True, else it is consonant, print False.
fuente
eval(input())(13 bytes) instead ofinput().split()(15 bytes).) instead of an emtpy string.C (gcc), 115
117120bytesTry it online!
Return 1/0 for consonat and dissonat. It is always interesting to do string manipulation with pure C. Take input as
f("A#", "C")fuente
PowerShell, 107 bytes
Try it online!
Outputs
Truefor dissonant andFalsefor consonant.Takes input
$aand$b, the two notes, as strings. Performs a-splitoperation on the scale, which splits on whitespace, to create an array of the notes, stores that into$x. Finds the.indexof$bin that array, subtracts the index of$a, and then takes theabsolute value thereof. Checks whether that number is-inthe dissonant ranges.fuente
Python 2, 68 bytes
Try it online!
Outputs:
1is dissonant,0is consonant.fuente
SQL, 582 bytes
SQL Fiddle
I still have some golfing to do on it, but I wanted to get it down here before I end up breaking it completely.
If the input is in a letter format, then putting those letters in a table with values is okay, right?
fuente
Perl 5, 106 bytes
Try it online!
Returns false for dissonant, true for consonant.
fuente