Generatore di spartiti ASCII-art


31

Nota : Anders Kaseorg mi avverte che questo potrebbe essere un duplicato di un'altra domanda precedente . Sembra di sì, e mi dispiace di non aver trovato quella domanda prima di pubblicarla. Tuttavia, quella domanda ha ricevuto solo una risposta e questa è più semplice, nel caso in cui tutti voi vogliate provare questa volta. Capirò se questa domanda finirà per essere contrassegnata come duplicata, però.

La sfida

Dato un input come questo:

8g 8Df 4cs 2C 1A

Scrivi il programma / funzione più breve che produce un output come questo:

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

Regole

L'output deve essere composto da un rigo a cinque righe che inizia con il disegno di una G-clef esattamente come mostrato sopra, allineato a sinistra del rigo e che lascia una singola colonna dopo l'avvio del rigo.

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

Le note devono iniziare con un *o un ocarattere a seconda del tipo.

Ci devono essere esattamente otto colonne di separazione ogni *o un opersonaggio:

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

Il personale deve terminare con la terminazione allineata a destra, come mostrato nell'esempio. La barra di sinistra del terminatore deve essere separata da 8 colonne dall'ultima nota.

L'input sarà una singola stringa contenente le note (almeno una, nessun input vuoto), ognuna separata da uno spazio bianco (puoi considerare che ogni nota sarà una corretta, quindi non c'è bisogno di verificare la presenza di errori). Puoi anche prendere l'input come un array di stringhe, con una nota per elemento nell'array. Per ogni nota, il primo carattere sarà il denominatore della lunghezza della nota ( 1per un'intera nota / semibreve , inizia con o; 2per una mezza nota / minimo , inizia con o; 4per una nota / un quarto , inizia con *; e 8per un ottavo note / quaver , inizia con*). Il secondo carattere sarà la nota (vedere la tabella successiva) e il terzo carattere facoltativo sarà fo Fper le note piatte e so Sper le note acute.

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

Ovviamente, l'input deve rispettare il caso delle note, ma è possibile scegliere il caso dei modificatori fe s.

Note ce Adevono aggiungere due -(righe di libro mastro), una per lato, in quanto devono estendere il personale. Note de Gsono fuori dallo staff ma non hanno bisogno di righe di contabilità generale.

Le note appiattite o affilate devono aggiungere bo #due posizioni a sinistra della nota.

Gli steli (se presenti) devono essere disegnati con 4 barre verticali. Le note da be sopra devono disegnare il gambo verso il basso e sul lato sinistro della nota. Le note da ae sotto devono disegnare il gambo verso l'alto e sul lato destro della nota. I quavers devono aggiungere la bandiera, sempre a destra ed esattamente come mostrato, e non devono essere irradiati se ce ne sono diversi di fila.

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

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

Come al solito, il tuo programma / funzione può disegnare direttamente l'output o restituire una stringa, una matrice di stringhe, una matrice di caratteri o qualsiasi altro formato ragionevole.

Link utili

Questo è , quindi può vincere il programma / funzione più breve per ogni lingua!

Bonus: prova a scrivere esempi con melodie famose e lascia che tutti provino a indovinare quale melodia sia!




... quindi non possiamo nemmeno usare il caso della lettera per dire in che modo disegnare il gambo?
Neil,

1
@Neil scusa, temo che non puoi. Non ho inventato questa regola, ho verificato che : "gli steli di solito puntano verso il basso per le note sulla linea di mezzo o più in alto, e per quelle sotto".
Charlie,

1
Possiamo prendere una matrice di stringhe, con ogni stringa che è una singola nota, come input?
Shaggy,

Risposte:


13

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

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

Provalo qui! (θ aggiunto per facilità d'uso; per funzionare come 171 byte si aspetta che l'input sia nello stack)

Per quanto ne so, funziona, ma se riscontri problemi, dimmelo.

Spiegazione:

prima parte: creazione della tela

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

seconda parte: anello, posizionamento della testa della 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

terza parte: bandiere e steli

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

Il tuo codice è quasi perfetto. L'unico nitpick è che la nota 2bsnel tuo esempio deve avere lo stelo rivolto verso il basso.
Charlie,

@CarlosAlejo fixed
dzaima

Grande! E grazie per la spiegazione!
Charlie,

10

JavaScript (ES6), 616 527 byte

Grazie @shaggy per la rimozione di quasi 90 byte

Non avevo idea delle note ... fino ad ora, spero di aver capito bene.

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

spiegazione

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``

Io penso che è possibile salvare alcuni byte salvando t[0]e t[2], e poi basta fareq=t.length*9
Stephen

2
Benvenuti in PPCG. Molto bella la prima risposta :) Tuttavia, c'è un po 'più di golf che si può fare. Ho preso un passaggio veloce se e l'ho portato a 520 byte , il che dovrebbe darti un buon inizio.
Shaggy,

Sicuramente un po 'di sostituzione di + atob / btoa salverebbe alcuni byte
Downgoat,

1
@ Shaggy grazie mille. Ho molto da imparare.
archi,

Prego :) Hai uno spazio randagio dopo il s>6&&(quale puoi risparmiare un byte. È inoltre possibile salvare un altro byte con sostituendolo (w=q+12)con w, repeat(q=i.length*9)con repeat(w=i.length*9)e repeat(q)con repeat(w,w+=12).
Shaggy,

9

Carbone , 180 171 168 163 byte

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

Provalo online! Il collegamento è alla versione dettagliata del codice. Spiegazione:

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

Stampa il pentagramma.

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

Stampa la chiave.

F⪪θ «

Passa attraverso ogni nota.

A⌕AGFEDCbagfedc§ι¹λ

Trova la coordinata Y della nota.

JχλA⁺⁹χχ

Questo è davvero subdolo: χè una variabile predefinita a 10, che è esattamente la coordinata X dell'accidentale della prima nota, se ne ha una. Dopo aver saltato in quella posizione, viene aggiunto 9, che rappresenta la posizione della nota successiva.

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

Stampa l'accidentale, se presente.

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

Stampa le righe del libro mastro se necessario e la nota. In effetti la linea viene stampata su qualsiasi coordinata y anche se la stampa sopra il pentagramma non ha ovviamente alcun effetto.

¿›ι2

Nient'altro da fare per i semibrevi.

¿›λ⁶«

Per le note sotto il punto medio,

↗↑⁴

disegna lo stelo verso l'alto,

¿›ι8«↘↘¹↓¹

e la bandiera per i quavers.

»»«

Per le note sopra il punto medio,

↙↓⁴

disegna lo stelo verso il basso,

¿›ι8«↗↗¹↑¹

e la bandiera per i quavers.


Hai battuto SOGL! :-)
Charlie

@CarlosAlejo Mi aspettavo che succedesse. Ma mi aspettavo che mi avrebbe battuto anche del 20%.
dzaima,

@dzaima forse se fosse una pura sfida di arte ASCII, ma questa ha anche una parte logica che rende l'output dipendente dall'input. Tuttavia mi sto ancora abituando a ciò che ogni lingua può fare meglio.
Charlie,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.