Hacer cajas de música

23

Su tarea es tomar una secuencia de caracteres (la música) como entrada (en una función o programa) e imprimir (o devolver) la música como se vería en una caja de música.

Solo recibirá los caracteres ABCDEFG.()como entrada, y la entrada nunca estará vacía. También puede recibir las letras en minúsculas, si lo desea.

Esta es una caja de música vacía, de longitud 3:

.......
.......
.......

Como puede ver, las líneas tienen 7 caracteres de longitud, y dado que la longitud de la caja de música es 3, tenemos 3 líneas. Solo hay .s aquí, ya que la caja de música está vacía. ¡Pongamos algo de música!

Primero, creamos la caja de música. En este ejemplo, la entrada será CDAG.DAG.

La longitud de CDAG.DAGes 8, por lo que necesitamos una caja de música de longitud 8:

.......
.......
.......
.......
.......
.......
.......
.......

Luego, leemos la entrada, un carácter a la vez, y colocamos un Oen su respectiva posición.

El primer carácter es C, y la ubicación de cada nota es equivalente a esto (agregué espacios para mayor claridad):

 A B C D E F G
 . . . . . . .
 . . . . . . .
 (and so on)

Si el carácter de entrada es un ., entonces solo imprimimos una línea vacía.......

Entonces, el Csería el tercer personaje a lo largo. Pongámoslo en nuestra caja de música en la parte superior:

..O....
.......
.......
.......
.......
.......
.......
.......

Repetiremos este proceso para todos los demás caracteres (el texto entre paréntesis es solo para mostrarle la nota, no debe mostrar eso):

..O.... (C)
...O... (D)
O...... (A)
......O (G)
....... (.)
...O... (D)
O...... (A)
......O (G)

Debido a cómo funcionan las cajas de música, si usamos un carácter distinto de O, .y <insert newline here>, como un espacio, en nuestra salida, ¡entonces no reproducirá la música correcta!

Este es un acorde:

(ACE)

Este acorde nos está instruyendo a tocar las notas A, Cy Eal mismo tiempo. Nunca habrá una pausa (es decir, a .) en un acorde.

Así es como se escribiría:

O.O.O...

Y así es como podría aparecer en la música: B(ACE)D

Nunca recibirá un acorde en un acorde, es decir, esto no será válido: (AB(CD)EF)o esto: A(B())y el acorde no estará vacío, es decir, esto no será válido:A()B

Nunca recibirá una entrada no válida.

Ejemplos:

B(ACE)D

.O.....
O.O.O..
...O...

B

.O.....

GGABC

......O
......O
O......
.O.....
..O....

...

.......
.......
.......

A..F.C(DA).

O......
.......
.......
.....O.
.......
..O....
O..O...
.......

.(ABCDEF)

.......
OOOOOO.

Se permite el espacio en blanco final / inicial en la salida.

Como se trata de , ¡el código más corto gana!

Okx
fuente
¿Puede una cadena de música contener ()dos veces (por ejemplo AB(CD)E(FG):)?
Sr. Xcoder
@ Mr.Xcoder Sí, puede.
Okx
¿Puede la salida ser una lista / matriz de caracteres?
Rod
@ Rod seguro, según los estándares
PPCG
¿Estamos garantizados de no obtener dos de la misma nota en el mismo acorde?
Business Cat

Respuestas:

0

Pip , 29 bytes

28 bytes de código, +1 para -lbandera.

'.X7RA_'OMz@?a@`\(\w+.|.`@XL

Toma la entrada en minúsculas como argumento de línea de comando. Pruébalo en línea!

Explicación

                              a is 1st cmdline arg; XL is `[a-z]`; z is lowercase alphabet
             a@`\(\w+.|.`     List of all matches in a of this regex:
                               Either a ( followed by letters followed by another
                               character (i.e. the closing paren), or any one character
                         @XL  For each of those matches, a list of all matches of this
                               regex (effectively, split the match into a list of
                               characters and keep only the lowercase letters)
          z@?                 Find index of each letter in the lowercase alphabet
         M                    To that list of lists of indices, map this function:
'.X7                           Take a string of 7 periods
    RA_                        and replace the characters at all indices in the argument
       'O                      with O
                              Finally, autoprint the resulting list, with each item on
                              its own line (-l flag)

Aquí hay una muestra de cómo se transforma una entrada:

"b.(ceg)"
["b" "." "(ceg)"]
[["b"] [] ["c" "e" "g"]]
[[1] [] [2 4 6]]
[".O....." "......." "..O.O.O"]
DLosc
fuente
6

Python 2 , 95 94 bytes

-1 byte gracias a Value Ink

x=1
for i in input():
 if x:o=['.']*7
 if'@'<i:o[ord(i)-65]='O'
 if'*'>i:x=i>'('
 if x:print o

Pruébalo en línea! o Pruebe todos los casos de prueba

Explicación

'@'<ies verificar si ies una letra, reemplazando el .by Oen la posición correcta.
'*'>ies comprobar si ies un paréntesis, si se trata x=i>'('pondrá 0en ximpedir la impresión / limpieza de o, cuando i==')', pondrá 1en xvolver a habilitar la impresión / limpieza de o.
Cuando i=='.'nada se cambiará y '.......'se imprimirá.
El orden de caracteres está dado por su código ASCII, donde'('<')'<'*'<'.'<'@'<'A'

Barra
fuente
Oh, me perdí ese comentario. nvm.
quintopia
Pasa de la coma: ['.']*7. Tal vez sea un remanente de cuando usabas una tupla, lo que requeriría una coma. Además, podría estar equivocado, pero esto parece generar una matriz ['O', '.', '.', '.', '.', '.', '.']por línea, y no estoy seguro de si eso está permitido.
Value Ink
@ValueInk sí, OP permitido
Rod
Mencionó el cambio de byte y cambió su enlace TIO, pero el código que figura en su publicación sigue siendo el mismo: V
Value Ink
1
@ValueInk ¯ \ _ (ツ) _ / ¯
Rod
4

Lote, 209 bytes

@set s=%1
@set p=)
@for %%n in (a b c d e f g)do @set %%n=.
:g
@if %s:~,1% lss @ (set "p=%s:~,1%")else set %s:~,1%=O
@set s=%s:~1%
@if %p%==( goto g
@echo %a%%b%%c%%d%%e%%f%%g%
@if not "%s%"=="" %0 %s%

Funciona acumulando letras y generando la línea si el último símbolo visto no era a (.

Neil
fuente
4

Röda , 97 78 76 bytes

{search`\(\w+\)|.`|{|c|seq 65,71|{|l|["O"]if[chr(l)in c]else["."]}_;["
"]}_}

Pruébalo en línea!

Es una función anónima que lee la entrada de la secuencia. Utilizar de esta manera: main { f={...}; push("ABCD") | f() }. Utiliza la expresión regular de la respuesta de ETHproductions.

Sin golf:

{
    search(`\(\w+\)|.`) | for chord do
        seq(ord("A"), ord("G")) | for note do
            if [ chr(note) in chord ] do
                push("O")
            else
                push(".")
            done
        done
        push("\n")
    done
}

Respuesta anterior:

f s{(s/"(?=([^()]*(\\([^()]*\\))?)*$)")|{|c|seq 65,71|{|l|["O"]if[chr(l)in c]else["."]}_;["
"]}_}

Pruébalo en línea!

Funciona dividiendo la cadena dada en lugares donde la cadena siguiente solo contiene paréntesis coincidentes. Luego, para cada acorde, itera a través de posibles notas e imprime Osi la nota es un miembro del acorde y de lo .contrario.

fergusq
fuente
4

JavaScript (ES6), 86 85 76 bytes

Guardado 9 bytes gracias a @Neil

let f =
s=>s.replace(r=/\(\w+\)|./g,x=>`ABCDEFG
`.replace(r,c=>x.match(c)?"O":"."))
<input oninput="if(/^([A-G.]|\([A-G]+\))+$/.test(value))O.textContent=f(value)"><br>
<pre id=O></pre>

Explicación

Primero, hacemos coincidir lo que formará cada línea de la salida: acordes y caracteres que no son parte de un acorde. Luego, para cada línea, tomamos la cadena ABCDEFG\ny reemplazamos cada carácter que no sea de nueva línea con un Osi la línea lo contiene, y .otro.

ETHproducciones
fuente
Si una nueva línea final es aceptable, puede guardar 8 bytes usando s=>s.replace(r=/\(\w+\)|./g,x=>`ABCDEFG\n`.replace(r,c=>x.match(c)?"O":".")).
Neil
@Neil Wow, eso es increíble :-)
ETHproductions
Huh, ahora que lo mido de nuevo, debería ser un ahorro de 10 bytes ...
Neil
Puede \)ser .?
l4m2
2

JavaScript (ES6), 118 116 114 bytes

f=([c,...t],s)=>c?((s?0:x=[...'.......'],c='ABCDEFG)('.indexOf(c))>6?c-7:(x[c]='O',s))?f(t,1):x.join``+`
`+f(t):''

Casos de prueba

Arnauld
fuente
2

Ruby, 78 75 71 bytes

->x{x.scan(/\(\w+\)|./).map{|x|l=?.*7
x.bytes{|x|x>47?l[x-65]=?O:1};l}}

Devuelve una matriz de cadenas.

Ungolfed + explicación

def boxes string
  string.scan(/\(\w+\)|./)    # Split the string into an array of chords.
  .map do |chord|             # Replace each chord with...
    line = '.' * 7            # a line, where by default each character is a '.',
    chord.bytes do |note|     # but for each note in the chord...
      if note > '.'.ord       # (if it is in fact a note and not a dot or paren)
        line[note-65] = 'O'   # replace the corresponding dot with an 'O'.
      end
    end
    line               
  end
end
m-chrzan
fuente
Tratar x.gsub(...){l=?.*7;$&.bytes{...};l+$/}(de intercambio scancon gsub, quitar map, y pasa la primera |x|ya que se puede utilizar $&para acceder al último partido de expresiones regulares) para guardar 3 bytes y devolver una cadena de múltiples líneas en su lugar. (También se $/asigna a una nueva línea de forma predeterminada.)
Value Ink
1

PHP, 171 bytes

preg_match_all('#[A-G\.]|\([A-G]+\)#',$argv[1],$m);foreach($m[0]as$l){if($l=='.')echo".......";else foreach([A,B,C,D,E,F,G]as$a)echo strpos($l,$a)!==false?O:'.';echo"\n";}

Descompostura :

preg_match_all('#[A-G\.]|\([A-G]+\)#',$argv[1],$m); // Matches either one character in the range [A-G.] OR multiple [A-G] characters between parentheses
foreach($m[0]as$l)                                  // For each match :
    if($l=='.')                                     //   If no note is played
        echo".......";                              //     Echo empty music line
    else                                            //   Else
        foreach([A,B,C,D,E,F,G]as$a)                //     For each note in the [A-G] range
            echo strpos($l,$a)!==false?O:'.';       //       Echo O i the note is played, . if not
    echo"\n";                                       //  Echo new line
}

Pruébalo aquí!

roberto06
fuente
1

Retina , 120 bytes

O`(?<=\([^)]*)[^)]
T`L.`d
(?<=\([^)]*)\d
$*x 
\)
m¶
+`\b(x+) \1(x+) m
$1 m$2 
 m?x

T`x m(`.\O_
\d
$*.O¶
¶
6$*.¶
%7>`.

Estoy seguro de que hay espacio para jugar al golf, pero funciona ahora, así que intentaré jugarlo más tarde.

Pruébalo en línea!

Cómo funciona

Básicamente, el programa funciona cambiando cada carácter a un número y luego asignando Oa esa posición en una línea. Se asigna ABCDEFG.a 01234569.

Para generar las líneas de nota única, todo lo que debe hacerse es poner un Odespués del número correspondiente de .s, luego rellenar la línea con 7 caracteres de longitud.

Sin embargo, los acordes son un poco más difíciles de hacer. Se utiliza un proceso similar, pero los números tienen que traducirse a incrementos, es decir, la primera nota en el acorde es (lo que sea), el segundo son las posiciones X después del primero, el tercero es las posiciones Y después de eso, etc.

Código

O`(?<=\([^)]*)[^)]

Comience ordenando todos los caracteres dentro de los acordes.

T`L.`d

Realice la transliteración (mapeo) de letras a números.

(?<=\([^)]*)\d
$*x 

Reemplace todos los dígitos entre paréntesis con una representación unaria (usando xs), seguida de un espacio.

\)
m¶

Reemplace todos los corchetes de cierre con mseguido de una nueva línea. Se mutilizará como un marcador de tipo para el próximo ciclo:

+`\b(x+) \1(x+) m
$1 m$2 

Esta es una etapa de reemplazo que se repite hasta que ya no se puede reemplazar. Toma las dos últimas secuencias de xs antes de an m, y resta la primera de la segunda, moviendo la parte mposterior. El marcador mes necesario porque tiene que realizar esta operación de derecha a izquierda.

 m?x

Elimina el primero xde cada secuencia excepto el primero.

T`x m(`.\O_

Transliterate reemplazando xcon ., espacio con O, y eliminando my (.

En este punto, se han creado todas las líneas para los acordes. Ahora se deben crear las líneas de nota única.

\d
$*.O¶

Reemplace cada dígito con esa .s, seguido de una Oy una nueva línea.

¶
6$*.¶
%7>`.

Rellene cada línea a la longitud 7 agregando .s a la derecha. Esto funciona agregando 6 .s al final de cada línea (cada línea tendrá al menos 1 otro carácter), y luego reemplaza cada carácter después de los primeros 7 en cada línea con nada. (Desde los .mapas hasta el 9, Ose cortarán en esas líneas)

Gato de negocios
fuente
1

Perl, 87 71 45 + 2 ( -nlbandera) = 47 bytes

#!/usr/bin/env perl -nl
use v5.10;
say map$&=~/$_/i?O:".",a..g while/\(\w+\)|./g

Utilizando:

perl -nlE 'say map$&=~/$_/i?O:".",a..g while/\(\w+\)|./g' <<< "A..F.C(DA)."

Pruébalo en Ideone.

Denis Ibaev
fuente
0

Perl 5 - 78 + 1 (bandera) + 2 (Cotizaciones de entrada) = 81 Bytes

for(;/(\([a-g]+\)|[a-g\.])/g;){$i=$1;print$i=~/$_/?'o':'.'for(a..g);print"\n"}

Se puede ejecutar así:

perl -n <name of file holding script> <<< <input in quotations>
CraigR8806
fuente
¿No crees que la entrada entre comillas contaría como 2 bytes adicionales? Puedo estar equivocado, ya que puede haber un meta consenso sobre esto diciendo lo contrario.
Okx
@Okx actualizó mi bytecount. No estaba seguro de si se agregaba, todavía era algo nuevo aquí :)
CraigR8806
0

Ruby, 68 bytes

->s{w=?.*m=7
s.bytes{|i|i>64?w[i-65]=?O:m=i!=40;m&&(puts w;w=?.*7)}}

La idea es modificar la cadena .......cada vez que encontramos una letra, luego generarla y restablecerla, pero solo cuando estamos fuera de los corchetes. (apaga la salida. )y. ambos activan / dejan la salida activada, pero este último es intrascendente ya que nunca se encontrará dentro de un soporte.

Sin golf en el programa de prueba

f=->s{w=?.*m=7              #set m to a truthy value (7) and w to seven .'s
  s.bytes{|i|               #for each byte in the string
    i>64?w[i-65]=?O:m=i!=40 #if a letter, modify the appropriate character of w ELSE set m to false if inside brackets, true otherwise.
    m&&(puts w;w=?.*7)      #if m is true, output the contents of w and reset to seven .'s
  }
}

p 1
f["B(ACE)D"]
p 2
f["B"]
p 3
f["GGABC"]
p 4
f["A..F.C(DA)."]
p 5
f[".(ABCDEF)"]
Level River St
fuente
0

Python 3, 94 bytes

Una función anónima

import re
lambda s:[''.join('.O'[c in x]for c in'ABCDEFG')for x in re.findall(r'\(\w+\)|.',s)]
RootTwo
fuente
0

Haskell , 101 bytes

c#s|elem c s=c|1<3='.'
s?r=map(#s)"ABCDEFG":p r
p('(':r)|(x,_:t)<-span(')'<)r=x?t
p(x:r)=[x]?r
p e=[]

Pruébalo en línea! Uso: p "AB.(CA)D". Devuelve una lista de cadenas.

Explicación:

La función se prepite sobre la cadena. Si encuentra un corchete de apertura '(', (x,_:t)<-span(')'<)rdivide la cadena de descanso ren las cadenas xantes de que ocurra el corchete de cierre ')'y tdespués. De lo contrario, el carácter actual xse convierte en una cadena [x]. En ambos casos, la función ?se llama con la cadena de notas actual y la cadena de resto. ?asigna la función #sobre la cadena "ABCDEFG", donde #reemplaza todos los caracteres que no están en la cadena actual de notas con '.'. La línea de cuadro de música resultante se antepone a la llamada recursiva de pla lista de descanso r.

Laikoni
fuente
0

Retina 0.8.2 , 52 bytes

\(\w+\)|.
abcdefg$&¶
+`([a-g])(.*)\1
O$2
T`().l`___.

Pruébalo en línea! Toma entrada en minúsculas. Explicación:

\(\w+\)|.
abcdefg$&¶

Divida la música en acordes o notas, y comience a construir la salida agregando la lista de equivalentes de notas.

+`([a-g])(.*)\1
O$2

Para cada nota en cada acorde, cambie la salida a an Oy elimine la nota del acorde.

T`().l`___.

Elimina toda la música ahora extraña, y cambia todas las notas no coincidentes para vaciarlas.

Neil
fuente
0

PHP, 93 bytes

for($s=$t="
.......";$c=ord($argn[$i++]);$d||$s=$t.!print$s)$c<65?$c-46&&$d=~$c&1:$s[$c&7]=O;

Ejecutar como tubería -nRo probarlo en línea .

Descompostura

for($s=$t="\n.......";      // init
    $c=ord($argn[$i++]);    // loop through characters
    $d||                        // 2. if chord flag is unset
        $s=$t.!print$s)             // then print and reset chord
    $c<65                       // 1. if not note
        ?$c-46                      // and not dot
            &&$d=~$c&1              // then set or clear chord flag
        :$s[$c&7]=O             // else set note in chord
    ;
Titus
fuente