Você sabia que o algoritmo euclidiano é capaz de gerar ritmos musicais tradicionais ? Vamos ver como isso funciona, descrevendo um algoritmo semelhante, mas um pouco diferente do algoritmo no artigo.
Escolha um número inteiro positivo n
, o número total de batidas e um número inteiro positivo k
, o número de batidas que são tocadas (notas). Podemos pensar no ritmo como uma sequência de n
bits, k
dos quais são 1s. A idéia do algoritmo é distribuir os 1s da maneira mais uniforme possível entre os 0s.
Por exemplo, com n = 8
e k = 5
, começamos com 5 uns e 3 zeros, cada um em sua própria sequência:
[1] [1] [1] [1] [1] [0] [0] [0]
A qualquer momento, teremos dois tipos de sequências - as que estão no início são as "principais" e as que estão no final são as "restantes". Aqui os núcleos são se [1]
os restantes são [0]
s. Contanto que tenhamos mais de uma sequência restante, as distribuímos entre os núcleos:
[1 0] [1 0] [1 0] [1] [1]
Agora, o núcleo é [1 0]
e o restante é [1]
, e distribuímos novamente:
[1 0 1] [1 0 1] [1 0]
Agora o núcleo é [1 0 1]
e o restante é [1 0]
. Como só temos uma sequência restante, paramos e obtemos a string
10110110
Isso é o que parece, repetidas 4 vezes:
Aqui está outro exemplo, com n = 16
e 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
Observe como terminamos na última etapa com duas seqüências principais e nenhuma sequência restante. Aqui está, repetido duas vezes:
Entrada
Você pode escrever uma função ou um programa completo lendo STDIN, linha de comando ou similar. A entrada terá dois números inteiros positivos n
e k <= n
, o que você pode assumir em qualquer ordem.
Resultado
Sua tarefa é produzir o ritmo gerado como uma n
sequência longa de caracteres. Você pode escolher dois caracteres ASCII imprimíveis distintos (0x20 a 0x7E) para representar notas e pausas.
Casos de teste
Os seguintes casos de teste são usados x
para representar notas .
es para representar restos. A entrada é dada na ordem n
, então 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.
Pontuação
Isso é código-golfe, então o código com o menor número de bytes vence.
q~\,f>
.Haskell, 125 bytes
Exemplo de uso:
42 # 13
->x...x..x..x..x...x..x..x..x...x..x..x..x..
.f
usa dois parâmetros: lista principal e restante. Ele fecha as duas listas (viag
) e chama a si próprio novamente ou para se o restante for muito curto. A função principal#
cria as listas e chamadas iniciaisf
.fonte
Python, 85
A solução recursiva natural. Os parâmetros
(n,k,a,b)
representam um núcleo dek
a
's seguido por um restante den-k
b'
s.Essa solução é ineficiente porque as duas chamadas recursivas
f
são avaliadas, causando um número exponencial de chamadas.Eu tentei comprimir a invocação condicional de
f
likemas nenhum saiu mais curto.
fonte