Generador de partituras ASCII-art

31

Nota : Anders Kaseorg me advierte que esto podría ser un duplicado de otra pregunta anterior . Parece que sí, y lo siento, no encontré esa pregunta antes de publicar esta. Sin embargo, esa pregunta solo recibió una respuesta y esta es más simple, en caso de que todos quieran intentarlo esta vez. Sin embargo, entenderé si esta pregunta termina siendo marcada como duplicada.

El reto

Dada una entrada como esta:

8g 8Df 4cs 2C 1A

Escriba el programa / función más corto que produce una salida como esta:

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

Reglas

El resultado debe consistir en un pentagrama de cinco líneas que comience con el dibujo de una clave de sol exactamente como se muestra arriba, alineado a la izquierda del pentagrama y dejando una sola columna después del inicio del pentagrama.

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

Las notas deben comenzar con un *o un ocarácter dependiendo de su tipo.

Debe haber exactamente ocho columnas de separación cada uno *o un opersonaje:

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

El personal debe terminar con el terminador alineado a la derecha como se muestra en el ejemplo. La barra izquierda del terminador debe estar separada 8 columnas de la última nota.

La entrada será una sola cadena que contiene las notas (al menos una, sin entradas vacías), cada una separada por un espacio en blanco (puede considerar que cada nota será la adecuada, por lo que no es necesario verificar si hay errores). También puede tomar la entrada como una matriz de cadenas, con una nota por elemento en la matriz. Para cada nota, el primer carácter será el denominador de la duración de la nota ( 1para una nota entera / semibreve , comienza con o; 2para una media nota / mínima , comienza con o; 4para un cuarto de nota / entrepierna , comienza con *; y 8para un octavo nota / temblor , comienza con*) El segundo carácter será la nota (ver tabla siguiente), y el tercer carácter opcional será fo Fpara notas planas y / so Spara notas agudas.

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

Obviamente, la entrada debe respetar el caso de las notas, pero puede elegir el caso de la fy smodificadores.

Notas cy Adebe agregar dos -(líneas contables), una a cada lado, ya que deben extender el pentagrama. Notas dy Gestán fuera del personal, pero no necesitan líneas contables.

Las notas planas o afiladas deben agregar bo #dos posiciones a la izquierda de la nota.

Los tallos (si los hay) deben dibujarse con 4 barras verticales. Las notas de barriba deben dibujar el tallo hacia abajo y al lado izquierdo de la nota. Las notas desde ay hacia abajo deben dibujar el tallo hacia arriba y en el lado derecho de la nota. Los quavers deben agregar la bandera, siempre hacia la derecha y exactamente como se muestra, y no necesitan ser emitidos si hay varios de ellos en una fila.

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

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

Como de costumbre, su programa / función puede dibujar directamente la salida o devolver una cadena, una matriz de cadenas, una matriz de caracteres o cualquier otro formato razonable.

Enlaces útiles

Este es el , ¡así que puede ganar el programa / función más corto para cada idioma!

Bonificación: ¡intenta escribir ejemplos con melodías famosas y deja que todos intenten adivinar qué melodía es!

Charlie
fuente
Caja de arena .
Charlie
¿Duplicar?
Anders Kaseorg
... así que ni siquiera podemos usar el caso de la letra para saber de qué manera dibujar el tallo?
Neil
1
@Neil lo siento, me temo que no puedes. No inventé esa regla, verifiqué que : "los tallos generalmente apuntan hacia abajo para las notas en la línea media o más alta, y hacia arriba para las de abajo".
Charlie
1
¿Podemos tomar una serie de cadenas, con cada cadena como una sola nota, como entrada?
Shaggy

Respuestas:

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

Pruébalo aquí! (θ agregado para facilitar su uso; para ejecutarse como 171 bytes, espera que la entrada esté en la pila)

Por lo que puedo decir, esto funciona, pero si encuentras algún problema, dímelo.

Explicación:

primera parte: creación del lienzo

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: bucle, colocación de cabeza de 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

tercera parte: banderas y tallos

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
fuente
Tu código es casi perfecto. El único inconveniente es que la nota 2bsen su ejemplo debe tener el tallo apuntando hacia abajo.
Charlie
@CarlosAlejo arreglado
dzaima
¡Excelente! Y gracias por la explicación!
Charlie
10

JavaScript (ES6), 616 527 bytes

Gracias @shaggy por eliminar casi 90 bytes

No tenía idea de las notas ... hasta ahora, espero haberlo hecho bien.

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; }

explicación

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
fuente
Yo creo que se puede ahorrar algunos bytes por el ahorro t[0]y t[2], a continuación, sólo lo hacenq=t.length*9
Stephen
2
Bienvenido a PPCG. Muy buena primera respuesta :) Sin embargo, hay un poco más de golf que se puede hacer. Tomé un pase rápido sobre si y lo reduje a 520 bytes , lo que debería darle un buen comienzo.
Shaggy
Sin duda alguna la sustitución + atob / btoa ahorraría algunos bytes
Downgoat
1
@ Shaggy muchas gracias. Tengo mucho que aprender.
arcos el
De nada :) Tiene un espacio perdido después del s>6&&(cual puede ahorrarle un byte. También puede guardar otro byte reemplazando (w=q+12)con w, repeat(q=i.length*9)con repeat(w=i.length*9)y repeat(q)con repeat(w,w+=12).
Shaggy
9

De carbón , 180 171 168 163 bytes

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

Pruébalo en línea! El enlace es a la versión detallada del código. Explicación:

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

Imprime el bastón.

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

Imprime la clave.

F⪪θ «

Recorre cada nota.

A⌕AGFEDCbagfedc§ι¹λ

Encuentra la coordenada Y de la nota.

JχλA⁺⁹χχ

Esto es realmente astuto: χes una variable que está predefinida a 10, que es exactamente la coordenada X de la primera nota accidental, si tiene una. Después de saltar a esa posición, se agrega 9, que representa la siguiente posición de nota.

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

Imprima el accidental, si hay uno.

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

Imprima las líneas del libro mayor si es necesario y la nota. De hecho, la línea se imprime en cualquier coordenada y uniforme, aunque imprimirla sobre el pentagrama no tiene ningún efecto, por supuesto.

¿›ι2

Nada más que hacer para semibreves.

¿›λ⁶«

Para notas debajo del punto medio,

↗↑⁴

dibuja el tallo hacia arriba,

¿›ι8«↘↘¹↓¹

y la bandera de los temblores.

»»«

Para notas por encima del punto medio,

↙↓⁴

dibuja el tallo hacia abajo,

¿›ι8«↗↗¹↑¹

y la bandera de los temblores.

Neil
fuente
¡Has vencido a SOGL! :-)
Charlie
@CarlosAlejo esperaba que sucediera. Pero esperaba que me ganara como un 20% también.
dzaima
@dzaima tal vez si fuera un desafío de arte ASCII puro, pero este también tiene una parte lógica que hace que la salida dependa de la entrada. Sin embargo, todavía me estoy acostumbrando a lo que cada idioma puede hacer mejor.
Charlie