Tłumacz muzyczny

11

Biorąc pod uwagę partyturę ascii, musisz mieć możliwość wygenerowania nuty i odpowiadającej jej długości. Partytura będzie zawierać od 5 do 15 nut włącznie i jest zapisywana na pięciolinii. Klepka składa się z pięciu poziomych linii składających się z - (minus) znaków oddzielonych liniami spacji. Dolna linia w pięciolinii odpowiada nucie „E”. Linia odstępów bezpośrednio nad dolną linią wskazuje „F” i ma wyższy skok niż „E” poniżej. Trwa to jak poniżej. Zauważ, że nuty idą w górę do „G”, zanim zaczną ponownie od „A”. Patrz poniżej:

F ----------
E           
D ----------
C           
B ----------
A           
G ----------
F           
E ----------

Zauważ, że litery nie są zawarte w danych wejściowych. Nuty nakładają się na pięciolinię za pomocą znaku ao (małe litery ooh), aby wskazać „główkę nuty”. Ta główka nuty wskazuje częstotliwość nuty, a zatem jej alfabetyczną reprezentację, jak powyżej. Na przykład nuta umieszczona na partyturze, jak poniżej, oznacza „A”:

----

----

----
o   
----

----

Nuta, taka jak „A” powyżej, nazywa się „całą nutą” i byłaby odtwarzana przez cały jeden takt. Inne czasy trwania można wskazać, włączając „trzon” powstający z nuty oraz od zera do trzech „flag”. Trzon składa się z trzech | (rura lub pionowy pasek) znaki ułożone bezpośrednio nad głowicą nuty. Trzon bez flag jest uważany za „ćwierćnuta” i gra przez ćwierć uderzenia. Flagi to znaki \ (odwrotny ukośnik) i ręka po prawej stronie rdzenia. Każdy trzon zmniejsza o połowę czas grania nuty. Długość każdej nuty będzie następująca: cała nuta, ćwierćnuta, ósma nuta, szesnasta nuta lub trzydziestosekundowa nuta. Tak wyglądałby każdy typ notatki A:

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

----|---|\--|\--|\--
    |   |   |\  |\
----|---|---|---|\--
o   o   o   o   o
--------------------

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

Połączenie więcej niż jednej nuty daje wynik. Każda nuta może mieć szerokość czterech znaków, przy czym nuta znajduje się w pierwszej kolumnie każdego czteroznakowego bloku. Na przykład :

    |\             
----|\--|\----------
    |\  |       |\  
----o---|---o---|\--
|       o       |   
|---------------o---
|                   
o-------------------

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

Powyższy przykład zawiera następujące nuty w kolejności: ćwierćnuta „G”, trzydziestosekundowa nuta „D”, ósma nuta „C”, cała nuta „D” i szesnasta nuta „B”. Każda nuta na wydruku powinna mieć format litera / długość, gdzie litera to AG, a długość to ułamek długości nuty w porównaniu do całej nuty. Jako wyjątek, długość i / / znak nie powinny być drukowane, jeśli notatka jest całą notatką. Każda nuta w twoich wynikach powinna być oddzielona pojedynczym odstępem. Dlatego dla powyższego wyniku kod powinien wypisać następujące dane:

G/4 D/32 C/8 D B/16
  • Nuty będą miały następujący zakres: EFGABCDE F. Uwaga: należy wydrukować tylko literę, oktawa jest ignorowana.
  • Zauważ, że liczba linii wejściowych waha się od 9 do 12, ponieważ nuty z kwadransami lub mniej w linii D lub wyższej będą wymagały więcej linii do pełnego wyświetlenia.
  • W tym przypadku nie ma półnuty.

Najkrótszy kod wygrywa (białe znaki się nie liczą).

Edycja: Naprawiono błąd w odstępach na jednym wejściu.

Niektóre przykładowe dane wejściowe:

        |\                    
----|\--|-------------------
|\  |   |                   
|---|---o---------------o---
|   o               |\      
o---------------|\--|\------
            |\  |\  |\      
------------|\--|\--o-------
            |\  o           
------------o---------------

Wyjście: B / 8 C / 8 D / 8 E / 32 F / 32 G / 32 D.


----------------o-------------------
                                o   
------------o-----------------------
                            o       
--------o---------------------------
                        o           
----o-------------------------------
                    o               
o-----------------------------------

Wyjście: EGBDFFACE


            |\                  
            |\                  
            |\                  
------------o-------|-----------
|               o   |   |\      
|---|\--------------|---|\------
|   |               o   |\      
o---|---|\--------------o---|\--
    o   |\                  |\  
--------|\------------------|---
        o                   o   
--------------------------------

Wyjście: B / 4 A / 8 F / 32 F / 32 EC / 4 B / 32 F / 16

Neil
źródło
Dlaczego białe znaki się nie liczą?
JB
@J: Aby ludzie nie mieli ochoty przesyłać programów o długości jednego wiersza bez spacji.
Neil
1
Konwencjonalne jest liczenie białych znaków, ale nie liczenie nowych linii, które są tylko po to, aby utrzymać wpis na rozsądnej szerokości. Skrypt użytkownika George'a robi to w przypadku niektórych języków (w tym c).
dmckee --- były moderator kociak
2
@ No cóż, w tej chwili wszystko, co mam ochotę przesłać, to program Whitespace.
JB
@Neil, tak, ale potem dostajesz inteligentnych, którzy piszą naprawdę pełne rozwiązania, pakują je w ciąg białych znaków i golf dekodują i wykonują
stoisko

Odpowiedzi:

6

JavaScript, 284,279,278,225,221 , 220 znaków (w tym niezbędne spacje)

One-liner ( skrzypce testowe ):

function a(c){b='',d=c.split('\n');for(e=0;d[0][e++];){f=0;for(i=0;g=d[i++];){h=g[e-1];if(h=='o')b+=(b?' ':'')+String.fromCharCode((d.length+4-i)%7+65);if(h=='|')f=f||4;if(g[e]&&g[e]=='\\')f*=2;}if(f)b+='/'+f;}return b;}

Czytelne ( skrzypce testowe ):

function getNotes(input){
    out='',lines=input.split('\n');

    for(col=0;lines[0][col++];){
        time=0;
        for(i=0;line=lines[i++];){
            char=line[col-1];
            if(char=='o')out+=(out?' ':'')+String.fromCharCode((lines.length+4-i)%7+65);
            if(char=='|')time=time||4;
            if(line[col]&&line[col]=='\\')time*=2;
        }
        if(time)out+='/'+time;
    }
    return out;
}
Briguy37
źródło
1
Usuwając niepotrzebne elementy ;i wykonując kilka sztuczek, możesz uczynić to jeszcze krótszym. function a(c){b='',d=c.split('\n');for(e=0;d[0][e++];){for(i=f=0;g=d[i++];){h=g[e-1];if(h=='o')b+=(b?' ':'')+String.fromCharCode((d.length+4-i)%7+65);if(h=='|')f=f||4;f*=1+(g[e]=='\\');}if(f)b+='/'+f}return b}(209 znaków)
JiminP
4

Perl, 103 znaki

(108 jeśli policzy się niezbędne znaki odstępu)

$i=0,s/\|\\/h /g,map$b[$i++].=$_,/./g for<>;/o/&&print chr 65+(4+length$')%7,/[h|]/&&"/".4*2**y/h//," "for@b

Z białymi miejscami do prezentacji:

$i=0,
    s/\|\\/h /g,
    map $b[$i++]. = $_, /./g
  for <>;
/o/ && print chr 65 + (4 + length $') % 7,
             /[h|]/ && "/" . 4*2**y/h//,
             " "
  for @b

Zauważ, że zakładam, że wszystkie linie mają tę samą długość (jak w poprawionej wersji pytania).

Zmieniona wersja z objaśnieniami:

#!/usr/bin/env perl
# First transpose the list of lines into a list of columns.
my @b = ();               # @b[$i] will contain the characters in column $i
while (<>) {              # for each input line, do
    my $i = 0;            # start in column 0
    s/\|\\/h /g;          # replace '\|' by 'h ', to keep track of part notes in the first column
    foreach (/./g) {      # for each character, do
        $b[$i++] .= $_;   # append the character to the transposed matrix
    }
}
# Now process each column.
foreach (@b) {            # for each column, do
    if (/o/) {            # if it contains a note, then
        print chr(65 + (4 + length $') % 7);    # print the note pitch
        if (/[h|]/) {                           # if this is a part note (had |\ or just |)
            print "/", 4*2**y/h//;              # print /n where n = 2^(subdivision)
        }
        print " ";
    }
}

(stare, dłuższe rozwiązanie, zachowane, ponieważ może być interesujące, nawet jeśli jest trochę dłuższe)

Perl, 147126 znaków

( 149 131, jeśli policzysz niezbędne białe znaki)

$c=0,map{/o/?$h[$c]=E:/\\/?$d[$c-1]*=2:/\|/?$d[$c]||=4:++$h[$c];++$c}/./g for<>;print grep{s~$~/$d[$i++] ~;s~/ ~ ~;y/E-M/EFGA-F/}@h

Z białymi miejscami do prezentacji:

$c = 0,
map { /o/ ? $h[$c]=E :
      /\\/ ? $d[$c-1]*=2 :
      /\|/ ? $d[$c]||=4 :
      ++$h[$c];
      ++$c
    } /./g for <>;
print grep {s~$~/$d[$i++] ~; s~/ ~ ~; y/E-M/EFGA-F/} @h

Zmieniono trochę, aby nie nadużywać języka tak bardzo:

#!/usr/bin/perl
my @h;          # $h[$c] will contain the note in column $c, if any
my @d;          # $d[$c] will contain the note length (e.g. 4), if any
while (<>) {    # for each input line, do
    my $c = 0;  # column number
    foreach (split //) {   # for each character, do
        if (/o/) { $h[$c] = "E"; }      # o => it's a note; if this is the last line, it's E
        elsif (/\\/) { $d[$c-1] *= 2; } # \ => halve the duration of the note in the previous column
        elsif (/\|/) { $d[$c] ||= 4; }  # | => if this is the first | in the column, we have a quarter note
        else { ++$h[$c]; }              # anything else => bump the note by 1
        ++$c;
     }
}
for (my $i = 0; $i < @h; $i++) { # for each column, do
    $_ = $h[$i];                   # look up the potential note (or garbage if there is no note in this column)
    s~$~/$d[$i++] ~;               # append the duration and a space (or "/ " if there is no duration)
    s~/ ~ ~;                       # remove the spurious "/" if there is no duration
    if (y/E-M/EFGA-F/) {           # if it's a note (i.e. if it contains a letter E-M), then
                                   # fix the letter wraparound and then
        print $_;                    # print the note
    }
}

Zauważ, że zakładam, że wszystkie linie mają tę samą długość. Jeśli chcesz zezwolić na krótsze wiersze, oczywistą poprawką jest dodanie $_.=1x$c,na początku programu, kosztem 9 znaków.

Pomyślałem o innym podejściu, aby uniknąć długich słów, takich jak spliti, mapi pozwolić spacjom wykonać więcej pracy, ale płyta kotłowa i znaki interpunkcyjne zemściły się i mogę sprowadzić ją do okropnej 130 (144 z niezbędną spacją).

sub p{$-[0]}
%a=qw(o $h[p]=E \ $d[&p-1]*=2 | $d[p]||=4 - ++$h[p]);
y/ /-/,s~.~$a{$&}~gee for<>;
print grep{s~$~/$d[$i++] ~;s~/ ~ ~;y/E-M/EFGA-F/}@h

Tym razem łatka do radzenia sobie z niedokończonymi liniami jest nieco dziwniejsza (co, myślałeś, że nie może być dziwniejsza?). 139 znaków, 155 z niezbędnymi odstępami.

sub p{$-[0]}
%a=qw(o $h[p]=E \ $d[&p-1]*=2 | $d[p]||=4 - ++$h[p]);
$_.=" "x p,y/
 /-/,s~.~$a{$&}~gee for<>;
print grep{s~$~/$d[$i++] ~;s~/ ~ ~;y/E-M/EFGA-F/}@h
Gilles „SO- przestań być zły”
źródło
2

Scala (2,9), 352 313 291 294 290 277 274 273 znaków

Jeśli potrzebna jest tylko funkcja:

def m(s:String){var(x,y,z,l)=(0,1,s.count(_=='\n'),Array.fill(99)(0))
var n=l.clone
for(c<-s){if(c=='\n'){x=0;y+=1}
if(c=='\\')l(x-1)+=1
if(c=='|')l(x)+=1
if(c=='o')n(x)="EFGABCDEF"(z-y)
x+=1}
(n,l).zipped.map((x,y)=>if(x>0)print(x.toChar+(if(y>0)"/"+(4<<y-3)else"")+" "))}

Jeśli wymagany jest pełny program:

object M extends App{def m(s:String){var(x,y,z,l)=(0,1,s.count(_=='\n'),Array.fill(99)(0))
var n=l.clone
for(c<-s){if(c=='\n'){x=0;y+=1}
if(c=='\\')l(x-1)+=1
if(c=='|')l(x)+=1
if(c=='o')n(x)="EFGABCDEF"(z-y)
x+=1}
(n,l).zipped.map((x,y)=>if(x>0)print(x.toChar+(if(y>0)"/"+(4<<y-3)else"")+" "))}
m(io.Source.stdin.mkString)}
Gareth
źródło
Pomiędzy słupkami puste spacje do końca wyniku, chociaż nie wspomniałem o tym, więc program powinien działać niezależnie. Jeśli linia z pustymi spacjami kończy się nagle, oznacza to, że i tak nie ma już więcej danych do rozważenia dla tej linii. Po prostu musi się nie zawieść .. :)
Neil
2

J - 108 znaków

exit echo}.,>,&.>/_4<@((a.{~32,65+7|4+i.&'o'),(>&0#('/',0":2^]))@((+/@(=&'\'))+2*'|'&e.))@;\|:|.[;._2]stdin''

Nie golfowany:

str =: stdin''
lines =: [;._2] str                          NB. split on the last character, the newline
rotated =: |: |. lines                       NB. lines reversed, then transposed
pitch =: 65 + 7 | 4 + i.&'o'                 NB. ord('A') + ( line.index('o') + 4 ) % 7
has_stem =: '|' & e.                         NB. '|' in line?
backslash_count =: (+/ @ (=&'\') )           NB. sum(char = '\\' for char in line)
denom_exp =: backslash_count + 2 * has_stem
fraction =: (>&0 # ('/', 0": 2 ^ ]))         NB. slash + 2^denom_exp, if denom_exp > 0
suffix =: fraction @ denom_exp
note_string =: (a. {~ 32,pitch) , suffix     NB. map(chr, (ord(' '), pitch)) + suffix
boxed_note_string =: < @ note_string @ ;     NB. box the string so it doesn't get padded
each_note_of_the =: boxed_note_string        NB. compute the note for a block of 4 lines
join_to_one_box =: , &. >
exit echo }. , > join_to_one_box / _4 each_note_of_the \ rotated
DCharness
źródło
2

Python golf, 207 znaków.

import sys
a=[x[:-1]+' '*99 for x in sys.stdin]
for x in range(0,99,4):
 b=''.join((y[x:x+4] for y in a))+'o'
 c=2**(b.count('\\')+('|'in b)*2)
 print'FEDCBAGFE '[b.index('o')/4-len(a)+9]+('','/'+`c`)[c>1],

Mam zacząć grać w golfa z kodu Pythona przez 2 dni i uważam, że takie rzeczy jak import sys, sys.stdin.read, sys.stdout.writesą wyraziste.

Promień
źródło
Jeśli dopiero zaczynasz grać w golfa w Pythonie, może ci się przydać pytanie o wskazówki dotyczące gry w python .
Gareth,