Partituras ASCII-art generator

31

Nota : Anders Kaseorg me avisa que isso pode ser uma duplicata de outra pergunta anterior . Parece que sim, e desculpe-me por não ter encontrado essa pergunta antes de postar esta. No entanto, essa pergunta recebeu apenas uma resposta e essa é mais simples, caso você queira tentar dessa vez. No entanto, vou entender se essa pergunta acaba sendo marcada como duplicada.

O desafio

Dada uma entrada como esta:

8g 8Df 4cs 2C 1A

Escreva o programa / função mais curto que produz uma saída como esta:

    /\                                         -o-
   | |
---|-|---------------------------------------------------|-|
   |/                                                    | |
---/|--------|\----b-*-----------------------------------|-|
  / |        | |    |                  o                 | |
-|--|--------|------|-----------------|------------------|-|
 | (| \      |      | |               |                  | |
-|--|--)----*-------|/---------|------|------------------|-|
  \ | /                        |      |                  | |
-----|-------------------------|-------------------------|-|
     |                         |
   *_/                      #-*-

Regras

A saída deve consistir em uma pauta de cinco linhas, começando com o desenho de uma clave G exatamente como mostrado acima, alinhada à esquerda da pauta e deixando uma única coluna após o início da pauta.

    /\  
   | |
---|-|--
   |/   
---/|---
  / |   
-|--|---
 | (| \ 
-|--|--)
  \ | / 
-----|--
     |  
   *_/
^
Single column

As notas devem começar com um *ou um ocaractere, dependendo do seu tipo.

Deve haver exatamente oito colunas de separação cada *ou um opersonagem:

    /\                                         -o-
   | |
---|-|---------------------------------------------------|-|
   |/                                                    | |
---/|--------|\----b-*-----------------------------------|-|
  / |        | |    |                  o                 | |
-|--|--------|------|-----------------|------------------|-|
 | (| \      |      | |               |                  | |
-|--|--)----*-------|/---------|------|------------------|-|
  \ | /                        |      |                  | |
-----|-------------------------|-------------------------|-|
     |                         |
   *_/                      #-*-
   ↑        ↑        ↑        ↑        ↑        ↑        ↑
   8 columns of separation

A equipe deve terminar com o terminador alinhado à direita, como mostra o exemplo. A barra esquerda do terminador deve ser separada 8 colunas da última nota.

A entrada será uma única sequência contendo as notas (pelo menos uma, sem entradas vazias), cada uma separada por um espaço em branco (você pode considerar que todas as notas serão adequadas, portanto, não é necessário verificar se há erros). Você também pode considerar a entrada como uma matriz de cadeias, com uma nota por elemento na matriz. Para cada nota, o primeiro caractere será o denominador do tamanho da nota ( 1para uma nota inteira / semibreve , começa com o; 2para uma meia nota / mínima , começa com o; 4para uma semínima / virilha , começa com *; e 8para uma oitava nota / tremor , começa com*) O segundo caractere será a nota (consulte a tabela a seguir) e o terceiro caractere opcional será fou Fpara notas simples e / sou Spara notas agudas.

    ---    A (ledger line)
           G
--------   F
           E
--------   D
           C
--------   b
           a
--------   g
           f
--------   e
           d
    ---    c (ledger line)

Obviamente, a entrada deve respeitar o caso das notas, mas você pode escolher o caso dos modificadores fe s.

Faça anotações ce Aadicione duas -(linhas de contabilidade), uma de cada lado, pois elas devem estender a equipe. Notas de Gestão fora da equipe, mas não precisa de linhas de livro.

As notas achatadas ou afiadas devem adicionar uma bou #duas posições à esquerda da nota.

As hastes (se houver) devem ser desenhadas com 4 barras verticais. As notas de bcima e de cima devem puxar a haste para baixo e no lado esquerdo da nota. As notas de ae para baixo devem desenhar a haste para cima e no lado direito da nota. Os quavers devem adicionar a bandeira, sempre à direita e exatamente como mostrado, e não precisam ser transferidos se houver várias delas seguidas.

--------------------------

-----|\----b-*------------
     | |    |             
-----|------|-------------
     |      | |           
----*-------|/---------|--
    ↑↑                 |  
----||------↑↑---------|--
    ||      ||         |
    ||      ||      #-*-
    |\      |\        ↑↑
    | Stem  | Note    | Stem
    Note    Stem      Note

Como sempre, seu programa / função pode desenhar diretamente a saída ou retornar uma string, matriz de strings, matriz de caracteres ou qualquer outro formato razoável.

Links Úteis

Isso é , portanto, pode ganhar o programa / função mais curto para cada idioma!

Bônus: tente escrever exemplos com melodias famosas e deixe todos tentarem adivinhar qual é a melodia!

Charlie
fonte
Sandbox .
6777 Charlie
Duplicado?
Anders Kaseorg
... então não podemos nem usar o caso da carta para dizer qual caminho desenhar o caule?
611 Neil
1
@ Neil desculpe, eu tenho medo que você não pode. Não criei essa regra, verifiquei que : "as hastes geralmente apontam para notas na linha do meio ou mais altas e para as que estão abaixo".
6777 Charlie
1
Podemos pegar uma matriz de strings, com cada string como uma única nota, como entrada?
Shaggy

Respostas:

13

SOGL V0.12 , 178 175 174 173 172 171 bytes

l9*6«+@*@¶¹┐∑:@┌ŗ4Ο"γ;]∑«;‽ΗmzΖH+īN D‼,ΨU‛y‚_○¤└yΨšI‘7n2∆╬5;{" -o-”;l3=?Jζ2%Ƨ#bWGk+;}Jz7m««:U+;W7«κArBb3>?Ζo*ŗ}a2\?┌@ŗ}ē9*LI+a╬5b1>?4┐∙b8=?"■QD³‘┼}e9*5+a4-8a>?5+;2-;G↕№}╬5

Experimente aqui! (θ adicionado para facilitar o uso; para executar com 171 bytes, espera que a entrada esteja na pilha)

Tanto quanto eu posso dizer, isso funciona, mas se você encontrar algum problema, diga-me.

Explicação:

primeira parte: criação de telas

l                                get the length of that array
 9*                              multiply by 9
   6«+                           add 12
      @*                         get that many spaces
        @¶                       push a space and a newline
          ¹                      put all the strings on the stack in an array
           ┐∑                    join with vertical bars
             :                   duplicate that string (which is a line with the ending barline but no staff)
              @┌ŗ                replace spaces with dashes (to make it a line with staff)
                 4Ο              encase 4 copies of the space lines in lines with the dashes
                   "...‘         push the G-clef without newlines
                        7n       split into an array of items of length 7
                          2∆╬5   at 1-indexed coordinates [2; -1] place the G-clef in the staff lines, extending the arrays size 
                              ;  get the input split on spaces back on top of the stack

segunda parte: loop, posicionamento da cabeça da nota

{                        loop over the input split on spaces
" -o-”                    push a template for a note head and leger lines
      ;                   get the input optop
       l3=?            }  if the length of the input is 3, then
           J                pop the last letter off from the input
            ζ               get its unicode point
             2%             modulo 2
               Ƨ#bW         get its index in "#b"
                   G        get the template ontop
                    k       remove its 1st letter
                     +      join the replaced input and the template
                      ;     get the input back ontop to be consisntent with how the if started

sidequest: parse the rest of the inputs
J                  pop the last letter off of the remaining input string (the note), leaving the note length as string on the stack below
 z                 push the lowercase alphabet
  7m               get its first 7 letters
    ««             put the first 2 at the end
      :            duplicate it
       U+          append it uppercased to the original
         ;W        get the notes letter ontop and get its 1-indexed index in that just created string
           7«κ     subtract it from 14
              A    save on variable A
               r   convert the note length to a number
                B  save on variable B

b3>?    }          if b>3 (aka if note length is either 4 or 8)
    Ζo*ŗ             replace "o" with "*"
         a2\?   }  if a divides by 2 (aka there isn't staff nor leger lines required)
             ┌@ŗ     replace "-" with " "

ē          push the value of variable E and after that increase it (default is user input number, which errors and defaults to 0)
 9*        multiply by 9
   LI+     increase by 11
      a    push variable a
       ╬5  at those positions (e*9+11, a) insert the note head template in the canvas

terceira parte: bandeiras e hastes

b1>?                      if b (note length)>1 (aka if the stem is needed at all)
    4┐∙                   get an array of 4 vertical bars
       b8=?       }       if b==8 (aka if the flag is needed)
           "■QD³‘           push "\    |"
                 ┼          add verically-down-then-horizontally-right

e9*                       push e*9 (now e starts with 1 as it's been increased) (the X coordinate for the flag)
   5+                     add 5 to it
     a4-                  push a-4 (the Y coordinate, 4 less than the note head as arrays get inserted from the top-left corner)
        8a>?         }    if 8>a (aka if the flag needs to be rotated)
            5+              add 5 to the Y coordinate
              ;2-;          subtract 2 from the X coordinate
                  G         get the stem&flag or stem ontop
                   ↕№       reverse it vertically and mirror characters
                      ╬5  insert the array of the stem and maybe flag at those coordinates
dzaima
fonte
Seu código é quase perfeito. O único detalhe é que a nota 2bsno seu exemplo deve ter a haste apontando para baixo.
6777 Charlie
@CarlosAlejo fixed
dzaima
Ótimo! E obrigado pela explicação!
Charlie #
10

JavaScript (ES6), 616 527 bytes

Obrigado @shaggy por remover quase 90 bytes

Eu não tinha idéia sobre anotações ... até agora, espero que eu acertei.

f=i=>i.map((v,p)=>(k[e=(w=q+12)*(l="AGFEDCbagfedc".search(v[1]))+p*9+12]="o*"[(s=v[0])>3|0],l<1|l>11&&(k[e-1]=k[e+1]="-"),(t=v[2])&&(k[e-2]="b#"[t>"f"|0]),--s&&[1,2,3,4].map(i=>(k[(b=l<8)?e+w*i-1:e-w*i+1]="|",s>6&&( b?k[e+w*4]="/":k[e-w*4+2]="\\",k[b?e+w*3+1:e-w*3+3]='|')))),k=[...`    /\\  ${s=" ".repeat(q=i.length*9)}  
   | |  ${s}    
---|-|--${l="-".repeat(q)+"|-|"}
   |/   ${t=s+"| |"}
---/|---${l}
  / |   ${t}
-|--|---${l}
 | (| \\ ${t}
-|--|--)${l}
  \\ | / ${t}
-----|--${l}
     |  ${s}   
   *_/  ${s}`])&&k.join``

console.log(f(["8g","8Df","4cs","2C","1A"]))
.as-console-wrapper { max-height: 100% !important; top: 0 }
.as-console-row:after { display: none !important; }

explicação

f=i=>i.map((v,p)=>( // for each note

  k[e=(w=q+12)*(l="AGFEDCbagfedc".search(v[1]))+p*9+12]= // position in 1D array to set the note to
  "o*"[(s=v[0])>3|0], // note value (either o or *)

  l<1|l>11&&(k[e-1]=k[e+1]="-"), // add leger line

  (t=v[2])&&(k[e-2]="b#"[t>"f"|0]), // add sharp or flat

  --s&&[1,2,3,4].map(i=> // add the 4 stem lines
                     (k[(b=l<8)?e+w*i-1:e-w*i+1]="|", // durration over eigth note => add stem

                      s>6&&( // if to add a flag
                        b?k[e+w*4]="/":k[e-w*4+2]="\\", // add flag either on left or the right side

                        k[b?e+w*3+1:e-w*3+3]='|') // add the line after the flag
                     )
                    )
),
// template, extended to the final length with lines
k=[...`    /\\  ${s=" ".repeat(q=i.length*9)}  
   | |  ${s}   
---|-|--${l="-".repeat(q)+"|-|"}
   |/   ${t=s+"| |"}
---/|---${l}
  / |   ${t}
-|--|---${l}
 | (| \\ ${t}
-|--|--)${l}
  \\ | / ${t}
-----|--${l}
     |  ${s}   
   *_/  ${s}`])&&k.join``
arcos
fonte
Eu acho que você pode economizar alguns bytes, salvando t[0]e t[2], em seguida, basta fazêq=t.length*9
Stephen
2
Bem-vindo ao PPCG. Muito boa primeira resposta :) Mas há um pouco mais de golfe que pode ser feito. Fiz uma rápida revisão do if e o reduzi para 520 bytes , o que deve lhe dar um bom começo.
Shaggy
Certamente alguns substituindo + atob / btoa iria salvar alguns bytes
Downgoat
1
@ Shagy muito obrigado. Eu tenho muito o que aprender.
arcs
De nada :) Você tem um espaço disperso após o s>6&&(qual pode economizar um byte. Você também pode salvar outro byte substituindo (w=q+12)por w, repeat(q=i.length*9)with repeat(w=i.length*9)e repeat(q)with repeat(w,w+=12).
Shaggy
9

Carvão , 180 171 168 163 bytes

F⁵⁺⸿⸿×-⁺²⁷×⁸№θ ↑⁹←↙↓⁹J⁴¦⁹↑⁶↗¹↑²↖¹↓↙¹↓³↙²↓³ \M²↑(| ↘¹↙)↙¹↓²↙¹↑←_*F⪪θ «A⌕AGFEDCbagfedc§ι¹λJχλA⁺⁹χχ¿⁼³Lι§b#⁼§ι²s→P׳¬﹪λ²→P§o*›ι4¿›ι2¿›λ⁶«↗↑⁴¿›ι8«↘↘¹↓¹»»«↙↓⁴¿›ι8«↗↗¹↑¹

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

F⁵⁺⸿⸿×-⁺²⁷×⁸№θ ↑⁹←↙↓⁹

Imprima a pauta.

J⁴¦⁹↑⁶↗¹↑²↖¹↓↙¹↓³↙²↓³ \M²↑(| ↘¹↙)↙¹↓²↙¹↑←_*

Imprima a clave.

F⪪θ «

Passe por cada nota.

A⌕AGFEDCbagfedc§ι¹λ

Encontre a coordenada Y da nota.

JχλA⁺⁹χχ

Isso é realmente sorrateiro: χé uma variável predefinida para 10, que é exatamente a coordenada X do acidental da primeira nota, se houver uma. Depois de pular para essa posição, 9 é adicionado a ela, representando a próxima posição da nota.

¿⁼³Lι§b#⁼§ι²s→

Imprima o acidental, se houver um.

P׳¬﹪λ²→P§o*›ι4

Imprima as linhas do razão, se necessário, e a nota. De fato, a linha é impressa em qualquer coordenada y, embora imprimi-la sobre a pauta não tenha efeito, é claro.

¿›ι2

Nada mais a fazer para semibreves.

¿›λ⁶«

Para notas abaixo do ponto médio,

↗↑⁴

puxe a haste para cima,

¿›ι8«↘↘¹↓¹

e a bandeira dos trêmulos.

»»«

Para notas acima do ponto médio,

↙↓⁴

desenhe a haste para baixo,

¿›ι8«↗↗¹↑¹

e a bandeira dos trêmulos.

Neil
fonte
Você venceu o SOGL! :-)
Charlie
@CarlosAlejo Eu esperava que isso acontecesse. Mas eu esperava que ele me vencesse em 20% também.
Dzaima 6/07
@dzaima talvez se fosse um desafio puro da arte ASCII, mas este também tem uma parte lógica que faz com que a saída dependa da entrada. No entanto, ainda estou me acostumando com o que cada idioma pode fazer melhor.
6777 Charlie