fundo
Na música ocidental, cada nota musical possui um nome atribuído. Dentro de cada oitava, há doze notas exclusivas na seguinte ordem: "CC # / Db DD # / Eb EFF # / Gb GG # / Ab AA # / Bb B C", onde o C final é uma oitava acima da primeira.
Para saber a diferença entre notas de oitavas diferentes, um número (para esse desafio restrito a um único dígito) é anexado ao final do nome da nota. Assim, C5 é a nota que está uma oitava acima de C4. Bb6 está acima de B5.
Um fato importante é que B5 e C6 são notas próximas umas das outras e que C0 e B9 são as notas mais baixa e mais alta.
Entre duas notas, existe uma distância que é o número de semitons entre elas. Bb4 é um semitom abaixo de B4, que é ele próprio um semitom abaixo de C5. Há doze semitons em uma oitava, então Bb4 está a uma distância de 12 de A # 3, pois está uma oitava acima dela (observe como uma única nota pode ter até dois nomes).
O desafio
Seu desafio é escrever o programa mais curto possível que possa obter uma lista de notas musicais de STDIN e imprimir a lista de alterações de intervalo em STDOUT.
A entrada será uma lista separada por espaços de notas musicais. Cada nota consistirá em uma letra maiúscula AG, um sinal b ou # opcional e um número de um dígito. Você não precisará lidar com E # / Fb ou B # / Cb. Exemplo de entrada:
C4 D4 E4 F4 G4 A4 B4 C5 C4
A saída será uma lista de números inteiros separados por espaço, que representa a distância entre cada nota sucessiva, sempre prefixada com + ou - para mostrar se a nota estava subindo ou descendo em relação à anterior. Sempre haverá um número a menos emitido do que as notas inseridas. Exemplo de saída para a entrada acima:
+2 +2 +1 +2 +2 +2 +1 -12
Mais alguns exemplos de entradas:
E5 D#5 E5 B4 E5 F#5 E5 B4
C0 B0 Bb1 A2 G#3 G4 F#5 F6
G4 Ab4 Gb4 A4 F4 A#4
E suas saídas correspondentes:
-1 +1 -5 +5 +2 -2 -5
+11 +11 +11 +11 +11 +11 +11
+1 -2 +3 -4 +5
Regras e Restrições
O vencedor é determinado pelo número de caracteres no código fonte
Seu programa deve consistir apenas em caracteres ASCII imprimíveis
Você não tem permissão para usar qualquer tipo de função interna relacionada a música ou som
Fora isso, aplicam-se regras de código padrão para golfe
fonte
+0
ou-0
ou0
para duas notas idênticas?Respostas:
GolfScript, 61
fonte
Haskell, 161 caracteres
fonte
Perl, 103
fonte
C, 123 caracteres
Com base na solução da esquerda, com algumas melhorias.
Alguns truques que eu acho que valem a pena mencionar:
1.
argv[0]
(aqui chamadob
) é um ponteiro para o nome do programa, mas usado aqui como um buffer temporário. Nós precisamos apenas de 4 bytes (por exemploC#2\0
), então temos o suficiente.2.
c
é o número de argumentos e, portanto, começa como 1 (quando executado sem argumentos). Nós o usamos para impedir a impressão na primeira rodada.Possível problema -
c+=b[..c+=..]
é meio estranho. Eu não acho que seja um comportamento indefinido, porque?:
é um ponto de sequência, mas talvez eu esteja errado.fonte
c = c + b[..c+=..]
, é um comportamento claramente indefinido. Independentemente do seqüenciamento interno[..]
, você não sabe se o externoc
é buscado antes, durante ou depoisb[..]
.REG=c;REG+=b[..c+=..];c=REG
. No entanto, ficarei surpreso ao ver algo assim na prática. Mas ainda é UB.scanf
sem protótipo, e tudo bem. É apenas bom saber o que é e não é legal na vida real :)C,
241229183fonte
printf("%+d ",c-d)
.F(*b-65)
vez dec-=65;
,b[1]<36&&++c||b[1]>97&&c--?2:1
->b[1]&16?1:(c+=b[1]%2*2-1,2)
, abusammain(e,b,c,d)char*b{
do argumento por: (Use o ponteiro do primeiro argumento como um buffer de trabalho).c=F(*b)%12
pode ser substituído porc=-~*b*1.6;c%=12
. Por quê?sin
no originalF
pode ser substituído por 9.6.c*1.6+9.6
é(c+6)*1.6
,c-=65
e(c+6)
se tornac-59
, e entãoc+1
(60 * 96% 12 == 0).Fator, 303 caracteres
Com comentários,
Para esse script, uma "lista separada por espaços" pode ter 1 ou mais espaços entre elementos e 0 ou mais espaços no início ou no final. Esse script imprime um espaço extra no final da saída, mas também aceita um espaço extra (ou nova linha) no final da entrada.
Se eu adotasse uma definição mais rígida, em que uma "lista separada por espaço" tem exatamente 1 espaço entre os elementos e 0 espaços no início ou no final, então posso abreviá-lo
contents R/ [#-b]+/ all-matching-slices
paracontents " " split
(usingsplitting
, notregexp
). No entanto, eu precisaria adicionar mais código para evitar o espaço extra no final da saída.Se eu usar a palavra descontinuada
dupd
, posso encurtarover [ - "%+d " printf ] dip
paradupd - "%+d " printf
, salvando 8 caracteres. Não estou usando palavras obsoletas porque elas "devem ser removidas em breve".fonte