Fazendo caixas de música

23

Sua tarefa é pegar uma sequência de caracteres (a música) como entrada (em uma função ou programa) e imprimir (ou retornar) a música como seria em uma caixa de música.

Você receberá apenas os caracteres ABCDEFG.()como entrada, e a entrada nunca estará vazia. Você também pode receber as letras em minúsculas, se desejar.

Esta é uma caixa de música vazia, de tamanho 3:

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

Como você pode ver, as linhas têm 7 caracteres e, como o comprimento da caixa de música é 3, temos 3 linhas. Existem apenas .s aqui, pois a caixa de música está vazia. Vamos colocar música nele!

Primeiro, criamos a caixa de música. Neste exemplo, a entrada será CDAG.DAG.

O comprimento de CDAG.DAGé 8, por isso precisamos de uma caixa de música com o comprimento 8:

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

Em seguida, lemos a entrada, um caractere de cada vez, e colocamos um Oem sua respectiva posição.

O primeiro caractere é Ce a localização de cada nota é equivalente a isso (adicionei espaços para maior clareza):

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

Se o caractere de entrada for a ., basta imprimir uma linha vazia.......

Então, o Cseria o terceiro personagem junto. Vamos colocá-lo em nossa caixa de música no topo:

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

Repetiremos esse processo para todos os outros caracteres (o texto entre parênteses é apenas para mostrar a nota, você não deve produzir isso):

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

Por causa de como as caixas de música funcionam, se usarmos um caractere diferente de O, .e <insert newline here>, como um espaço, em nossa saída, ele não tocará a música correta!

Este é um acorde:

(ACE)

Esse acorde está nos instruindo a tocar as notas A, Ce E, ao mesmo tempo. Nunca haverá uma pausa (ou seja, a .) em um acorde.

É assim que seria escrito:

O.O.O...

E é assim que pode aparecer na música: B(ACE)D

Você nunca receberá um acorde em um acorde, ou seja, isso não será válido: (AB(CD)EF)ou isso A(B()):, e o acorde não estará vazio, ou seja, isso não será válido:A()B

Você nunca receberá uma entrada inválida.

Exemplos:

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.

Espaço em branco à esquerda / à direita na saída é permitido.

Como se trata de , o código mais curto vence!

Okx
fonte
uma string de música pode conter ()duas vezes (por exemplo AB(CD)E(FG):) ??
Sr. Xcoder 10/03
@ Mr.Xcoder Sim, pode.
Okx, 10/03/17
A saída pode ser uma lista / matriz de caracteres?
Rod
@Rod certeza, como por padrões PPCG
Okx
Temos a garantia de não receber duas da mesma nota no mesmo acorde?
Business Cat

Respostas:

0

Pip , 29 bytes

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

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

Recebe entrada em minúsculas como um argumento da linha de comandos. Experimente online!

Explicação

                              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)

Aqui está uma amostra de como uma entrada é transformada:

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

Python 2 , 95 94 bytes

-1 byte graças ao 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

Experimente online! ou Experimente todos os casos de teste

Explicação

'@'<ié verificar se ihá uma letra, substituindo o .por Ona posição correta.
'*'>ié verificar se ié um parêntese, se for x=i>'('vai colocar 0em xevitar a impressão / compensação de o, quando i==')', ele vai colocar 1na xre-permitindo a impressão / compensação de o.
Quando i=='.'nada será alterado e '.......'será impresso.
A ordem do caractere é dada pelo código ASCII, onde'('<')'<'*'<'.'<'@'<'A'

Cajado
fonte
oh, eu perdi esse comentário. NVM.
quintopia
Vala a vírgula: ['.']*7. Talvez seja uma suspensão de quando você estava usando uma tupla, o que exigiria a vírgula. Além disso, posso estar errado, mas isso parece gerar uma matriz ['O', '.', '.', '.', '.', '.', '.']por linha e não tenho certeza se isso é permitido.
Value Ink
@ValueInk sim, OP permitido
Rod
Você mencionou a mudança byte e mudou seu link TIO mas o código listado no seu post ainda é o mesmo: V
Valor 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 e emitindo a linha se o último símbolo visto não for a (.

Neil
fonte
4

Röda , 97 78 76 bytes

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

Experimente online!

É uma função anônima que lê a entrada do fluxo. Usá-lo como este: main { f={...}; push("ABCD") | f() }. Ele usa o regex da resposta da ETHproductions.

Ungolfed:

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

Resposta anterior:

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

Experimente online!

Ele funciona dividindo a sequência especificada em locais onde a sequência a seguir contém apenas parênteses correspondentes. Em seguida, para cada acorde, ele percorre as notas possíveis e imprime Ose a nota é um membro do acorde ou .não.

fergusq
fonte
4

JavaScript (ES6), 86 85 76 bytes

Guardado 9 bytes graças 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>

Explicação

Primeiro, combinamos o que formará cada linha da saída: acordes e caracteres que não fazem parte de um acorde. Então, para cada linha, pegamos a string ABCDEFG\ne substituímos cada caractere que não seja de nova linha por um Ose a linha o contiver e por .outro.

ETHproductions
fonte
Se uma nova linha à direita for aceitável, você poderá salvar 8 bytes usando s=>s.replace(r=/\(\w+\)|./g,x=>`ABCDEFG\n`.replace(r,c=>x.match(c)?"O":".")).
Neil
@Neil Wow, isso é incrível :-)
ETHproductions
Huh, agora que eu medi-lo novamente, ele deve ser uma economia de 10 byte ...
Neil
Pode \)ser .?
L4m2 23/07/19
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 teste

Arnauld
fonte
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}}

Retorna uma matriz de seqüências de caracteres.

Ungolfed + explicação

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
fonte
Tente x.gsub(...){l=?.*7;$&.bytes{...};l+$/}(swap scancom gsub, remover map, e pular a primeira |x|vez que você pode usar $&para acessar o último jogo regex) para salvar 3 bytes e retornar uma seqüência de multi-linha em vez. (Também $/mapeia para uma nova linha por padrão).
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";}

Demolir :

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
}

Experimente aqui!

roberto06
fonte
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>`.

Tenho certeza de que há espaço para jogar golfe, mas agora funciona, então tentarei jogar mais tarde.

Experimente online!

Como funciona

Basicamente, o programa funciona alterando cada caractere para um número e atribuindo um Oa essa posição em uma linha. Ele mapeia ABCDEFG.para 01234569.

Para gerar as linhas de nota simples, basta colocar um Oapós o número correspondente de .s e preencher a linha com 7 caracteres.

No entanto, os acordes são um pouco mais difíceis de fazer. Um processo semelhante é usado, mas os números devem ser convertidos em incrementos, ou seja, a primeira nota no acorde é (o que for), a segunda é a posição X depois da primeira, a terceira é a posição Y depois disso, etc.

Código

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

Comece ordenando todos os caracteres dentro dos acordes.

T`L.`d

Realize a transliteração (mapeamento) de letras para números.

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

Substitua todos os dígitos entre colchetes por uma representação unária (usando xs), seguida por um espaço.

\)
m¶

Substitua todos os colchetes de fechamento por mseguidos por uma nova linha. O mserá usado como um tipo de marcador para o próximo loop:

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

Esse é um estágio de substituição que fica em loop até que não possa mais ser substituído. Ele pega as duas últimas seqüências de xs antes de um me subtrai a primeira da segunda, movendo as mcostas. O marcador mé necessário porque ele deve executar esta operação da direita para a esquerda.

 m?x

Remova o primeiro xde cada sequência, exceto o primeiro.

T`x m(`.\O_

Transliterar substituindo xpor ., espaço por Oe excluindo me (.

Nesse ponto, todas as linhas dos acordes foram criadas. Agora, as linhas de nota única precisam ser criadas.

\d
$*.O¶

Substitua cada dígito por tantos .s, seguidos por uma Oe uma nova linha.

¶
6$*.¶
%7>`.

Coloque cada linha no comprimento 7 adicionando .s à direita. Isso funciona adicionando 6 .s ao final de cada linha (cada linha terá pelo menos 1 outro caractere) e substituindo cada caractere após os 7 primeiros em cada linha por nada. (Como o .mapa é 9, Oserá cortado nessas linhas)

Gato de negócios
fonte
1

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

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

Usando:

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

Experimente em Ideone.

Denis Ibaev
fonte
0

Perl 5 - 78 + 1 (sinalizador) + 2 (aspas de entrada) = 81 bytes

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

Pode ser executado assim:

perl -n <name of file holding script> <<< <input in quotations>
CraigR8806
fonte
Você não acha que a entrada entre aspas contaria como 2 bytes extras? Eu posso estar errado, pois pode haver um meta consenso sobre isso afirmando o contrário.
Okx
@Okx atualizou meu bytecount. Não tinha certeza se acrescentar, ainda meio novo aqui :)
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)}}

A idéia é modificar a string .......toda vez que encontrarmos uma letra, depois a enviar e redefinir, mas somente quando estiver entre colchetes.(desliga a saída. )e. ambos alternam / deixam a saída ligada, mas a última é irrelevante, pois nunca será encontrada dentro de um suporte.

Ungolfed in program program

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
fonte
0

Python 3, 94 bytes

Uma função anônima

import re
lambda s:[''.join('.O'[c in x]for c in'ABCDEFG')for x in re.findall(r'\(\w+\)|.',s)]
RootTwo
fonte
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=[]

Experimente online! Uso:p "AB.(CA)D" . Retorna uma lista de strings.

Explicação:

A função se prepete sobre a sequência. Se encontrar um colchete de abertura '(', (x,_:t)<-span(')'<)rparticione a sequência restante rnas cadeias xantes da ocorrência do colchete de fechamento ')'e tdepois dela. Caso contrário, o caractere atual xserá transformado em uma string [x]. Nos dois casos, a função ?é chamada com a sequência atual de notas e a sequência restante. ?mapeia a função #sobre a sequência "ABCDEFG", onde #substitui todos os caracteres que não estão na sequência atual de notas por '.'. A linha da caixa de música resultante é anexada à chamada recursiva da plista restante r.

Laikoni
fonte
0

Retina 0.8.2 , 52 bytes

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

Experimente online! Recebe entrada em minúsculas. Explicação:

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

Divida a música em acordes ou notas e comece a criar a saída adicionando a lista de equivalentes de notas.

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

Para cada nota em cada acorde, altere a saída para a Oe exclua a nota do acorde.

T`().l`___.

Exclua todas as músicas estranhas agora e altere todas as notas incomparáveis ​​para vazias.

Neil
fonte
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;

Execute como pipe -nRou experimente on-line .

demolir

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
fonte