Ajude-me com meus polirritmos

17

Sou músico e preciso de mais polirritmos na minha vida!

Um polirritmo ocorre na música (e na natureza) quando dois eventos (palmas, notas, vaga-lumes piscando etc.) ocorrem em dois intervalos regulares diferentes. Os dois tipos de evento acontecem um número diferente de vezes no mesmo intervalo.

Se eu tocar com a mão esquerda duas vezes e com a mão direita três vezes, no mesmo espaço de tempo, ficará um pouco assim:

  ------
R . . .
L .  .  

Os hífens no topo denotam o comprimento do padrão polirrmico, que é o menor múltiplo comum ou 2 e 3. Isso pode ser entendido como o ponto em que o padrão se repete.

Há também um 'metarritmo', que é o padrão produzido quando uma das mãos está tocando:

  ------
R . . .
L .  .  
M . ...

Este é um polirritmo simples e muito comum, com uma proporção de 3: 2.

Digamos apenas que não quero fazer um polirritmo simples que possa resolver na minha cabeça, então preciso de algo para resolver isso para mim. Eu poderia fazer isso de forma longa no papel, ou ...


Regras:

  • Escreva algum código para gerar e exibir um diagrama polirritmático, conforme descrito acima.
  • Qualquer idioma antigo, tente pelo menor número de bytes.
  • Seu código usa dois argumentos:
    • Número de toques com a mão esquerda (número inteiro positivo)
    • Número de toques com a mão direita (número inteiro positivo)
  • Ele calculará o comprimento, que é o múltiplo comum mais baixo para os dois argumentos.
  • A linha superior será composta por dois caracteres de espaço em branco seguidos por hífens exibindo o comprimento (comprimento * '-')
  • A segunda e terceira linhas mostrarão o padrão para as mãos direita e esquerda:
    • Ele começará com um R ou L, indique de que lado ele é, seguido por um espaço.
    • O intervalo para essa mão é o comprimento dividido por seu argumento.
    • Os toques começarão no terceiro caractere, indicado por qualquer caractere que você escolher. A partir de então, ele exibirá o mesmo caractere 'intervalo' caracteres separados.
    • Não será maior que a linha de comprimento.
  • A quarta linha é o metarritmo:
    • Ele começará com M maiúsculo, seguido por um espaço.
    • A partir do terceiro caractere, ele mostrará um personagem (qualquer personagem que você escolher) em todas as posições em que houver um toque na mão direita ou esquerda.
  • O espaço em branco à direita é irrelevante.

Casos de teste:

r = 3, l = 2

  ------
R . . .
L .  .  
M . ...

r = 4, l = 3

  ------------
R .  .  .  .    
L .   .   .    
M .  .. . ..

r = 4, l = 5

  --------------------
R .    .    .    .                     
L .   .   .   .   .      
M .   ..  . . .  ..

r = 4, l = 7

  ----------------------------
R .      .      .      .      
L .   .   .   .   .   .   .   
M .   .  ..   . . .   ..  .

r = 4, l = 8

  --------
R . . . . 
L ........
M ........

Feliz golfe!

AJFaraday
fonte
Seus casos de teste incluem muitos espaços em branco à direita, podemos omiti-los / adicionar mais?
Wastl
Temos que aceitar re lcomo dois valores separados? Poderíamos aceitar uma matriz de dois elementos, por exemplo? Que tal a ordem deles, isso é rseguido estritamente l?
Sok
@Sok Isso é aceitável como uma interpretação de 'dois argumentos'
AJFaraday
Ele realmente precisa imprimir o diagrama ou pode simplesmente devolvê-lo?
Reintegrar Monica - notmaynard
@iamnotmaynard voltar está bem.
AJFaraday

Respostas:

6

JavaScript (ES6), 131 bytes

Saídas 0como o caractere de toque .

r=>l=>`  ${g=n=>n?s.replace(/./g,(_,x)=>[,a=x%(k/r),x%=k/l,a*x][n]&&' '):++k%l|k%r?'-'+g():`-
`,s=g(k=0)}R ${g(1)}L ${g(2)}M `+g(3)

Experimente online!

Quão?

g()

g()0k=lcm(l,r)

g = _ => ++k % l | k % r ? '-' + g() : `-\n`

s

g()1n3xs0

g = n => s.replace(/./g, (_, x) => [, a = x % (k / r), x %= k / l, a * x][n] && ' ')
Arnauld
fonte
4

Java 11, 226 234 233 219 bytes

String h(int r,int l,int m){var s="";for(;m>0;)s+=m%r*(m--%l)<1?'.':32;return s;}

r->l->{int a=r,b=l,m;for(;b>0;b=a%b,a=m)m=b;m=r*l/a;return"  "+repeat("-",m)+"\nR "+h(m/r,m+1,m)+"\nL "+h(m/l,m+1,m)+"\nM "+h(m/r,m/l,m);}

Tipo de longo; muito ruim Java não tem uma lcm()função. Experimente online aqui (o TIO ainda não possui o Java 11, portanto, ele usa um método auxiliar em vez de String.repeat()).

Minha versão inicial levou o intervalo entre toques em vez do número de toques. Corrigido agora. Agradecimentos a Kevin Cruijssen pelo golfe de 1 byte.

Ungolfed:

String h(int r, int l, int m) { // helper function returning a line of metarhythm; parameters are: tap interval (right hand), tap interval (left hand), length
    var s = ""; // start with an empty String
    for(; m > 0; ) // repeat until the length is reached
        s += m % r * (m-- % l) < 1 ? '.' : 32; // if at least one of the hands taps, add a dot, otherwise add a space (ASCII code 32 is ' ')
    return s; // return the constructed line
}

r -> l -> { // lambda taking two integers in currying syntax and returning a String
    int a = r, b = l, m; // duplicate the inputs
    for(; b > 0; b = a % b, a = m) // calculate the GCD of r,l using Euclid's algorithm:
        m=b; // swap and replace one of the inputs by the remainder of their division; stop once it hits zero
    m = r * l / a; // calculate the length: LCM of r,l using a=GCD(r,l)
    return // build and return the output:
    "  " + "-".repeat(m) // first line, m dashes preceded by two spaces
    + "\nR " + h(m / r, m + 1, m) // second line, create the right-hand rhythm; by setting l = m + 1 for a metarhythm, we ensure there will be no left-hand taps
    + "\nL " + h(m / l, m + 1, m) // third line, create the left-hand rhythm the same way; also note that we pass the tap interval instead of the number of taps
    + "\nM " + h(m / r, m / l, m); // fourth line, create  the actual metarhythm
}
OOBalance
fonte
Não é muito, mas -1 byte mudando ?".":" "para ?'.':32.
Kevin Cruijssen
@KevinCruijssen Cada byte conta :-) Obrigado!
OOBalance
4

Python 2 , 187 185 183 174 166 156 148 147 145 bytes

Usa -como caractere de toque

a,b=r,l=input()
while b:a,b=b,a%b
w=r*l/a
for x,y,z in zip(' RLM',(w,r,l,r),(w,r,l,l)):print x,''.join('- '[i%(w/y)!=0<i%(w/z)]for i in range(w))

Experimente online!


Salvou:

  • -2 bytes, graças a Jonathan Frech
TFeld
fonte
[i%(w/y)and i%(w/z)>0]poderia ser [i%(w/y)!=0<i%(w/z)].
Jonathan Frech
@JonathanFrech Thanks :)
TFeld
3

Perl 6 , 85 80 78 bytes

-2 bytes graças a Jo King.

'  'R L M»Z~'-'x($!=[lcm] @_),|(@_.=map:{' '~(0~' 'x$!/$_-1)x$_}),[~|] @_}

Experimente online!

Retorna uma lista de quatro linhas.

Nwellnhof
fonte
3

Python 2 , 185 228 223 234 249 bytes

def f(r,l):
     c='.';d=' ';M,R,L=[r*l*[d]for _ in d*3]
     for i in range(r*l):
      if i%r<1:L[i]=M[i]=c
      if i%l<1:R[i]=M[i]=c
      if r<R.count(c)and l<L.count(c):R[i]=L[i]=M[i]=d;break
     print d,i*'-','\nR',''.join(R),'\nL',''.join(L),'\nM',''.join(M)

Experimente online!

sonrad10
fonte
Acabei de copiar isso no TIO e peguei o formato gerado a partir daí. Acontece que ele é feito em menos bytes do que você pensou;)
AJFaraday
@Tfeld r=4, l=8funciona bem para mim
sonrad10
O comprimento deve ser o menor múltiplo comum. Com r = 4, l = 8, deve ser 8, mas parece que sua saída é muito maior (8 * 4?).
OOBalance
1
Isso ainda não dá o LCM; por exemplo 15,25, para , dá 375, mas deveria ser 75.
OOBalance
1
Acredito que a última verificação possa ser substituída por i%r+i%l+0**i<1. Além disso, você pode remover versões anteriores do código, como eles serão preservados em seu histórico de edição de alguém quiser vê-los
Jo rei
2

Gelatina , 32 bytes

æl/Ḷ%Ɱµa/ṭ=0ị⁾. Z”-;ⱮZ“ RLM”żK€Y

Experimente online!

Leva a entrada como uma lista [L,R].

æl/       Get LCM of this list.
   Ḷ      Range [0..LCM-1]
    %Ɱ    Modulo by-each-right (implicitly the input, [L,R]):
           [[0%L ... (LCM-1)%L], [0%R ... (LCM-1)%R]]
µ         Take this pair of lists, and:
 a/ṭ      Append their pairwise AND to the pair.
    =0    Is zero? Now we have a result like:
              [[1 0 0 1 0 0 1 0 0 1 0 0 1 0 0]
               [1 0 0 0 0 1 0 0 0 0 1 0 0 0 0]
               [1 0 0 1 0 1 1 0 0 1 1 0 1 0 0]]

ị⁾.       Convert this into dots and spaces.
Z”-;ⱮZ    Transpose, prepend a dash to each, transpose. Now we have
              ['---------------'
               '.  .  .  .  .  '
               '.    .    .    '
               '.  . ..  .. .  ']

“ RLM”ż       zip(' RLM', this)
       K€     Join each by spaces.
         Y    Join the whole thing by newlines.
Lynn
fonte
1

C (gcc), 204 bytes

p(s){printf(s);}
g(a,b){a=b?g(b,a%b):a;}
h(r,l,m){for(;m;)p(m%r*(m--%l)?" ":".");}
f(r,l,m,i){m=r*l/g(r,l);p("  ");for(i=m;i-->0;)p("-");p("\nR ");h(m/r,m+1,m);p("\nL ");h(m/l,m+1,m);p("\nM ");h(m/r,m/l,m);}

Porta da minha resposta Java . Ligue com f(number_of_right_hand_taps, number_of_left_hand_taps). Experimente online aqui .

OOBalance
fonte
200 bytes
ceilingcat
1

Pitão, 53 bytes

j.b+NYc"  L R M "2++*\-J/*FQiFQKm*d+N*\ t/JdQsmeSd.TK

Definitivamente espaço para golfe. Farei isso quando tiver tempo.
Experimente aqui

Explicação

j.b+NYc"  L R M "2++*\-J/*FQiFQKm*d+N*\ t/JdQsmeSd.TK
                       J/*FQiFQ                        Get the LCM.
                    *\-                                Take that many '-'s.
                               Km*d+N*\ t/dJQ          Fill in the taps.
                                             smeSd.TK  Get the metarhythm.
                  ++                                   Append them all.
      c"  L R M "2                                     Get the prefixes.
 .b+NY                                                 Prepend the prefixes.
j                                                      Join with newlines.

fonte
1

C # (compilador interativo do Visual C #) , 254 bytes


Golfe Experimente online!

(r,l)=>{int s=l>r?l:r,S=s;while(S%l>0|S%r>0)S+=s;string q(int a){return"".PadRight(S/a,'.').Replace(".",".".PadRight(a,' '));}string R=q(S/r),L=q(S/l),M="";s=S;while(S-->0)M=(R[S]+L[S]>64?".":" ")+M;return"  ".PadRight(s+2,'-')+$"\nR {R}\nL {L}\nM {M}";}

Ungolfed

( r, l ) => {
    int
        s = l > r ? l : r,
        S = s;

    while( S % l > 0 | S % r > 0 )
        S += s;

    string q( int a ) {
        return "".PadRight( S / a, '.' ).Replace( ".", ".".PadRight( a, ' ' ) );
    }

    string
        R = q( S / r ),
        L = q( S / l ),
        M = "";

    s = S;

    while( S-- > 0 )
        M = ( R[ S ] + L[ S ] > 64 ? "." : " " ) + M;

    return "  ".PadRight( s + 2, '-') + $"\nR {R}\nL {L}\nM {M}";
}

Código completo

Func<Int32, Int32, String> f = ( r, l ) => {
    int
        s = l > r ? l : r,
        S = s;

    while( S % l > 0 | S % r > 0 )
        S += s;

    string q( int a ) {
        return "".PadRight( S / a, '.' ).Replace( ".", ".".PadRight( a, ' ' ) );
    }

    string
        R = q( S / r ),
        L = q( S / l ),
        M = "";

    s = S;

    while( S-- > 0 )
        M = ( R[ S ] + L[ S ] > 64 ? "." : " " ) + M;

    return "  ".PadRight( s + 2, '-') + $"\nR {R}\nL {L}\nM {M}";
};

Int32[][]
    testCases = new Int32[][] {
        new []{ 3, 2 },
        new []{ 4, 3 },
        new []{ 4, 5 },
        new []{ 4, 7 },
        new []{ 4, 8 },
    };

foreach( Int32[] testCase in testCases ) {
    Console.Write( $" Input: R: {testCase[0]}, L: {testCase[1]}\nOutput:\n{f(testCase[0], testCase[1])}" );
    Console.WriteLine("\n");
}

Console.ReadLine();

Lançamentos

  • v1.0 - 254 bytes- Solução inicial.

Notas

  • Nenhum
auhmaan
fonte
1

Carvão , 52 bytes

≔θζW﹪ζη≧⁺θζζ↙≔⮌Eζ⟦¬﹪×ιθζ¬﹪×ιηζ⟧ζFζ⊞ι⌈ι↓Eζ⭆ι§ .λ←↓RLM

Experimente online! Link é a versão detalhada do código. Explicação:

≔θζW﹪ζη≧⁺θζ

Calcule o LCM das entradas, tomando o primeiro múltiplo do Rque é divisível por L.

ζ↙

Imprima o LCM, que gera automaticamente a linha necessária de -s. Em seguida, mova para imprimir o ritmo da direita para a esquerda.

≔⮌Eζ⟦¬﹪×ιθζ¬﹪×ιηζ⟧ζ

Faça um loop sobre os números do LCM até 0 e crie uma matriz de listas representando as batidas das mãos direita e esquerda.

Fζ⊞ι⌈ι

Faça um loop sobre as batidas e adicione o metarritmo.

↓Eζ⭆ι§ .λ

Imprima as batidas invertidas para baixo, mas como essa é uma matriz, elas terminam para a esquerda.

←↓RLM

Imprima o cabeçalho.

Neil
fonte
1

Ruby , 130 126 bytes

->*a{puts"  "+?-*s=a[0].lcm(a[1])
r,l=a.map!{|e|(?.+' '*(s/e-1))*e}
[?R,?L,?M].zip(a<<r.gsub(/ /){l[$`.size]}){|e|puts e*" "}}

Experimente online!

Restabelecer Monica - notmaynard
fonte
1

Python 2 , 117 bytes

a,b=input();n=a
while n%b:n+=a
for i in-1,1,2,3:print'_RLM '[i],''.join(' -'[i%2>>m*a%n|i/2>>m*b%n]for m in range(n))

Experimente online!

xnor
fonte
1

Pitão, 49 bytes

J/*FQiFQjC+c2" RLM    "ms@L" -"!M++0d*Fdm%Ld/LJQJ

Espera entrada no formulário [r,l]. Usa -para exibir toques. Experimente on-line aqui ou verifique todos os casos de teste de uma vez aqui .

J/*FQiFQjC+c2" RLM    "ms@L" -"!M++0d*Fdm%Ld/LJQJ   Implicit: Q=eval(input())
 /*FQiFQ                                            Compute LCM: (a*b)/(GCD(a,b))
J                                                   Store in J
                                        m       J   Map d in [0-LCM) using:
                                            /LJQ      Get number of beats between taps for each hand
                                         %Ld          Take d mod each of the above
                                                    This gives a pair for each beat, with 0 indicating a tap
                       m                            Map d in the above using:
                                     *Fd              Multiply each pair (effecively an AND)
                                 ++0d                 Prepend 0 and the original pair
                               !M                     NOT each element
                        s@L" -"                       Map [false, true] to [' ', '-'], concatenate strings
                                                    This gives each column of the output
           c2" RLM    "                             [' RLM','    ']
          +                                         Prepend the above to the rest of the output
         C                                          Transpose
        j                                           Join on newlines, implicit print
Sok
fonte
1

R , 161 149 146 bytes

function(a,b){l=numbers::LCM(a,b)
d=c(0,' ')
cat('  ',strrep('-',l),'\nR ',d[(x<-l:1%%a>0)+1],'\nL ',d[(y<-l:1%%b>0)+1],'\nM ',d[(x&y)+1],sep='')}

Experimente online!

Definitivamente, sinto que há espaço para melhorias aqui, mas tentei algumas abordagens diferentes e essa é a única que ficou presa. Livrar-me da definição da função interna me deixaria muito feliz e tentei várias reestruturações do cat () para que isso acontecesse. Deixa pra lá, assim que postei, percebi o que podia fazer. Definitivamente, ainda existem algumas economias de eficiência.

Existem outras funções LCM em bibliotecas com nomes mais curtos, mas o TIO possui números e eu considero isso mais valioso neste momento.

CriminallyVulgar
fonte
1

C ++ (gcc) , 197 bytes

int f(int a,int b){std::string t="  ",l="\nL ",r="\nR ",m="\nM ";int c=-1,o,p=0;for(;++p%a||p%b;);for(;o=++c<p;t+="-")l+=a*c%p&&++o?" ":".",r+=b*c%p&&++o?" ":".",m+=o-3?".":" ";std::cout<<t+l+r+m;}

Experimente online!

Annyo
fonte
Sugerir em ++p%a+p%bvez de++p%a||p%b
tetocat 22/09