Музыкальный переводчик


11

При наличии партитуры ascii у вас должна быть возможность вывести ноту и соответствующую ей длину. Партитура будет содержать от 5 до 15 нот включительно и будет записана на нотном стане. Посох состоит из пяти горизонтальных линий, состоящих из - (минус) символов, разделенных линиями пробелов. Нижняя строка в нотном стане эквивалентна ноте 'E'. Линия пробелов непосредственно над нижней строкой обозначает «F» и имеет более высокую высоту, чем «E» под ней. Это продолжается, как показано ниже. Обратите внимание, что ноты доходят только до «G», а затем снова начинаются с «A». См. ниже:

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

Обратите внимание, что буквы не включены во входные данные. Ноты накладываются на верхнюю часть нотного станка, используя символ ao (нижний регистр ooh) для обозначения «заголовка ноты». Этот заголовок примечания указывает частоту примечания и, следовательно, его буквенное представление, как указано выше. Например, примечание, помещенное в партитуру, как показано ниже, обозначает «A»:

----

----

----
o   
----

----

Нота, как и вышеприведенная буква «А», называется «целой нотой» и будет воспроизводиться за один полный удар. Другие длительности могут быть указаны включением «стебля», поднимающегося из ноты, и между нолем и тремя «флагами». Стебель состоит из трех | (труба или вертикальная черта) символы располагаются непосредственно над заголовком заметки. Стебель без флагов считается четвертной нотой и играет четверть удара. Флаги являются символами \ (обратная косая черта) и находятся на правой стороне ствола. Каждый ствол делится пополам на время, за которое играется нота. Длина каждой ноты будет одной из следующих: целая нота, четвертная нота, восьмая нота, шестнадцатая нота или тридцать вторая нота. Вот как каждый тип заметки будет выглядеть для A:

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

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

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

Соединение более чем одной записки дает вам оценку. Каждую заметку можно считать шириной в четыре символа, причем заметка находится в первом столбце каждого четырехсимвольного блока. Например :

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

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

Приведенный выше пример содержит следующие примечания по порядку: четвертная нота «G», тридцать вторая нота «D», восьмая нота «C», целая нота «D» и шестнадцатая нота «B». Каждая заметка в выходных данных должна быть в формате буква / длина, где буква - это AG, а длина - это доля длины заметки по сравнению с целой заметкой. Как исключение, длина и / символ не должны быть напечатаны, если заметка является целой заметкой. Каждая нота в вашем выводе должна быть отделена одним пробелом. Следовательно, для оценки выше ваш код должен вывести следующее:

G/4 D/32 C/8 D B/16
  • Примечания будут в следующем диапазоне: EFGABCDE F. Обратите внимание, что только буква должна быть напечатана, октава игнорируется.
  • Обратите внимание, что количество строк ввода варьируется от 9 до 12, поскольку примечания с четвертным или меньшим временем в строке D или выше потребуют больше строк для полного отображения.
  • В этом случае нет полулоты.

Самый короткий код выигрывает (пробел не считается).

Редактировать: Исправлена ​​ошибка в интервале в одном входе.

Некоторые примеры входных данных:

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

Выход: B / 8 C / 8 D / 8 E / 32 F / 32 G / 32 D


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

Выход: EGBDFFACE


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

Выход: B / 4 A / 8 F / 32 F / 32 EC / 4 B / 32 F / 16


Почему пробелы не учитываются?
JB

@J: чтобы люди не чувствовали склонности представлять программы в одну строку без пробелов.
Нил

1
Обычно считается пустое пространство, но не учитываются новые строки, которые находятся там только для того, чтобы сохранить запись на разумной ширине. Пользовательский скрипт Джорджа делает это с некоторыми языками (включая с).
dmckee --- котенок экс-модератора

2
@ Нейл, хорошо, сейчас все, что я склонен представить, - это программа Whitespace.
JB

@Neil, да, но тогда у вас есть умники, которые пишут по-настоящему многословные решения, упаковывают их в строку пробелов и играют в декодер и исполняют
Boothby

Ответы:


6

Javascript, 284 279 278 225 221 , 220 символов (включая необходимые пробелы)

Однострочник ( тестовая скрипка ):

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

Читаемый ( тестовая скрипка ):

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

1
Удаляя ненужные ;s и делая некоторые трюки, вы можете сделать это еще короче. 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 символов)
JiminP

4

Perl, 103 символа

(108, если вы считаете необходимые пробельные символы)

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

С пробелами для презентации:

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

Обратите внимание, что я предполагаю, что все строки имеют одинаковую длину (согласно пересмотренной версии вопроса).

Переставленная версия с пояснениями:

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

(старое, более длинное решение, сохранено, потому что оно может быть интересным, даже если оно немного дольше)

Perl, 147 126 символов

( 149 131, если вы считаете необходимые пробелы)

$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

С пробелами для презентации:

$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

Переставил немного, чтобы не злоупотреблять языком так сильно

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

Обратите внимание, что я предполагаю, что все строки имеют одинаковую длину. Если вы хотите разрешить более короткие строки, очевидным решением будет добавить $_.=1x$c,в начале программы, стоимостью 9 символов.

Я подумал о другом подходе, чтобы избежать длинных слов, таких как splitи, mapи позволить пробелам делать больше работы, но шаблон и пунктуация отомстили, и я могу довести его до колоссальных 130 (144 с необходимыми пробелами).

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

На этот раз патч, чтобы справиться с незаконченными строками, немного страннее (что, вы думали, он не может стать более странным?). 139 символов, 155 с необходимыми пробелами.

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

2

Scala (2,9), 352 313 291 294 290 277 274 273 символов

Если функция - это все, что нужно:

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

Если требуется полная программа:

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

До конца партитуры между пробелами есть пробелы, хотя я не упоминал об этом, поэтому программа должна работать независимо. Если строка с пробелами внезапно заканчивается, это означает, что в любом случае больше нет ввода для этой строки. Он просто не должен разбиться .. :)
Нил

2

J - 108 символов

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

2

Питон гольф, 207 символов.

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

Я запустить код игры в гольф с Python в течение 2 дней , и я обнаружил , что вещи , как import sys, sys.stdin.read, sys.stdout.writeобширны.


Если вы новичок в гольфе в Python, вам может пригодиться этот вопрос .
Гарет
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.