Partiturinterpreter

11

Bei einer ASCII-Partitur müssen Sie in der Lage sein, die Note und ihre entsprechende Länge auszugeben. Die Partitur enthält zwischen 5 und 15 Noten einschließlich und ist auf einer Daube transkribiert. Eine Daube besteht aus fünf horizontalen Linien, die aus - (Minus-) Zeichen bestehen, die durch Leerzeichen voneinander getrennt sind. Die unterste Zeile in der Daube entspricht der Note 'E'. Die Leerzeichenzeile unmittelbar über der unteren Zeile zeigt ein 'F' an und hat eine höhere Tonhöhe als das 'E' darunter. Dies wird wie folgt fortgesetzt. Beachten Sie, dass Noten nur bis zu 'G' reichen, bevor Sie erneut bei 'A' beginnen. Siehe unten:

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

Beachten Sie, dass die Buchstaben nicht in der Eingabe enthalten sind. Die Noten werden mit ao (Kleinbuchstaben ooh) über die Daube gelegt, um den 'Notenkopf' anzuzeigen. Dieser Notenkopf gibt die Häufigkeit der Note und damit die alphabetische Darstellung wie oben an. Zum Beispiel zeigt eine Notiz, die wie folgt in der Partitur platziert ist, ein 'A' an:

----

----

----
o   
----

----

Eine Note, wie das 'A' oben, wird als 'ganze Note' bezeichnet und für einen ganzen Schlag gespielt. Andere Dauern können angezeigt werden, indem ein 'Stiel' aus der Note und zwischen null und drei 'Flaggen' eingefügt wird. Ein Stiel besteht aus drei | Zeichen (Pipe oder vertikaler Balken), die unmittelbar über dem Notenkopf gestapelt sind. Ein Stiel ohne Flaggen wird als "Viertelnote" betrachtet und spielt einen Viertelschlag. Flags sind \ (Backslash-) Zeichen und befinden sich auf der rechten Seite des Stiels. Jeder Stiel halbiert die Zeit, für die die Note gespielt wird. Die Länge jeder Note ist eine der folgenden: eine ganze Note, eine Viertelnote, eine Achtelnote, eine Sechzehntelnote oder eine Zweiunddreißigste Note. So würde jede Art von Notiz nach A aussehen:

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

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

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

Wenn Sie mehr als eine Note zusammenfügen, erhalten Sie eine Punktzahl. Jede Note kann als vier Zeichen breit angesehen werden, wobei sich eine Note in der ersten Spalte jedes vierstelligen Blocks befindet. Zum Beispiel :

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

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

Das obige Beispiel enthält die folgenden Noten in der Reihenfolge: eine Viertelnote 'G', eine zweiunddreißigste Note 'D', eine Achtelnote 'C', eine ganze Note 'D' und eine Sechzehntelnote 'B'. Jede Note in Ihrer Ausgabe sollte das Format Buchstabe / Länge haben, wobei Buchstabe AG ist und Länge der Bruchteil der Länge der Note im Vergleich zu einer ganzen Note ist. In Ausnahmefällen sollten Länge und / oder Zeichen nicht gedruckt werden, wenn die Notiz eine ganze Notiz ist. Jede Note in Ihrer Ausgabe sollte durch ein einzelnes Leerzeichen getrennt werden. Daher sollte Ihr Code für die obige Punktzahl Folgendes ausgeben:

G/4 D/32 C/8 D B/16
  • Die Noten liegen im folgenden Bereich: EFGABCDE F. Beachten Sie, dass nur der Buchstabe gedruckt werden muss, die Oktave wird ignoriert.
  • Beachten Sie, dass die Anzahl der Eingabezeilen zwischen 9 und 12 variiert, da Noten mit einer Viertelzeit oder weniger in Zeile D oder höher mehr Zeilen erfordern, um vollständig angezeigt zu werden.
  • In diesem Fall gibt es keine halbe Note.

Der kürzeste Code gewinnt (Leerzeichen zählen nicht).

Bearbeiten: Fehler im Abstand in einem Eingang behoben.

Einige Beispieleingaben:

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

Ausgang: B / 8 C / 8 D / 8 E / 32 F / 32 G / 32 D.


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

Ausgabe: EGBDFFACE


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

Ausgang: B / 4 A / 8 F / 32 F / 32 EC / 4 B / 32 F / 16

Neil
quelle
Warum zählt kein Leerzeichen?
JB
@J: Damit die Leute nicht geneigt sind, Programme eine Zeile lang ohne Leerzeichen einzureichen.
Neil
1
Es ist üblich, Leerzeichen zu zählen, aber keine neuen Zeilen zu zählen, die nur dazu da sind, den Eintrag unter einer angemessenen Breite zu halten. Georges Userscript macht dies mit einigen Sprachen (einschließlich c).
dmckee --- Ex-Moderator Kätzchen
2
@Neil Nun, alles, was ich einreichen möchte, ist ein Whitespace-Programm.
JB
@Neil, ja, aber dann bekommst du Smartasses, die wirklich ausführliche Lösungen schreiben, sie in eine Reihe von Leerzeichen packen und ein Decode-and-Exec spielen: codegolf.stackexchange.com/questions/3203/meta-golf-challenge/…
Standby

Antworten:

6

Javascript, 284,279,278,225,221 , 220 Zeichen (einschließlich des erforderlichen Leerzeichens)

Einzeiler ( Testgeige ):

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

Lesbar ( Testgeige ):

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
quelle
1
Indem Sie unnötige ;s entfernen und einige Tricks ausführen, können Sie dies noch kürzer machen. 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 Zeichen)
JiminP
4

Perl, 103 Zeichen

(108, wenn Sie die erforderlichen Leerzeichen zählen)

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

Mit Leerzeichen für die Präsentation:

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

Beachten Sie, dass ich davon ausgehe, dass alle Zeilen die gleiche Länge haben (gemäß der überarbeiteten Version der Frage).

Neu arrangierte Version mit Erklärungen:

#!/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 " ";
    }
}

(alte, längere Lösung, aufbewahrt, weil sie interessant sein kann, auch wenn sie etwas länger ist)

Perl, 147 126 Zeichen

( 149 131, wenn Sie das erforderliche Leerzeichen zählen)

$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

Mit Leerzeichen für die Präsentation:

$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

Ein wenig neu arrangiert, um die Sprache nicht so sehr zu missbrauchen:

#!/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
    }
}

Beachten Sie, dass ich davon ausgehe, dass alle Zeilen die gleiche Länge haben. Wenn Sie kürzere Zeilen zulassen möchten, ist es naheliegend, $_.=1x$c,zu Beginn des Programms 9 Zeichen hinzuzufügen .

Ich dachte an einen anderen Ansatz, um lange Wörter wie splitund zu vermeiden mapund Leerzeichen mehr von der Arbeit machen zu lassen, aber das Boilerplate und die Interpunktion rächten sich, und ich kann es nur auf einen Keuchhusten 130 (144 mit dem erforderlichen Leerzeichen) bringen.

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

Der Patch, um mit unfertigen Linien fertig zu werden, ist diesmal etwas seltsamer (was, Sie dachten, es könnte nicht seltsamer werden?). 139 Zeichen, 155 mit dem erforderlichen Leerzeichen.

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 - hör auf böse zu sein'
quelle
2

Scala (2,9), 352 313 291 294 290 277 274 273 Zeichen

Wenn nur eine Funktion benötigt wird:

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"")+" "))}

Wenn ein vollständiges Programm erforderlich ist:

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
quelle
Es sind Leerzeichen dazwischen Bars bis zum Ende der Partitur, obwohl ich es nicht erwähnt , so sollte das Programm unabhängig arbeiten. Wenn die Zeile mit Leerzeichen abrupt endet, bedeutet dies, dass für diese Zeile ohnehin keine weiteren Eingaben mehr zu berücksichtigen sind. Es muss einfach nicht abstürzen .. :)
Neil
2

J - 108 Zeichen

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

Ungolfed:

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
quelle
2

Python Golf, 207 Zeichen.

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],

Ich habe für 2 Tage Code Golf mit Python beginnen , und ich fand , dass Dinge wie import sys, sys.stdin.read, sys.stdout.writesind expansiv.

Strahl
quelle
Wenn Sie mit dem Golfen in Python noch nicht vertraut sind, ist diese Frage mit Python-Gofling-Tipps möglicherweise hilfreich.
Gareth