Создание гитарных вкладок?

24

Напишите самую короткую программу, которая генерирует гитарные вкладки для аккордов, указанных в качестве входных данных.

Чтобы у вас среди гитаристов не было преимущества, и чтобы сделать его детерминированным (и, вероятно, более простым для кодирования), вот единственные разрешенные формы аккордов:

Major chords:

  E   F   F#  G   G#  A   A#  B   C   C#  D   D#
e 0---1---2---3---4---0---1---2---3---4---5---6---
B 0---1---2---3---4---2---3---4---5---6---7---8---
G 1---2---3---4---5---2---3---4---5---6---7---8---
D 2---3---4---5---6---2---3---4---5---6---7---8---
A 2---3---4---5---6---0---1---2---3---4---5---6---
E 0---1---2---3---4---0---1---2---3---4---5---6---

Minor chords:

  Em  Fm  F#m Gm  G#m Am  A#m Bm  Cm  C#m Dm  D#m
e 0---1---2---3---4---0---1---2---3---4---5---6---
B 0---1---2---3---4---1---2---3---4---5---6---7---
G 0---1---2---3---4---2---3---4---5---6---7---8---
D 2---3---4---5---6---2---3---4---5---6---7---8---
A 2---3---4---5---6---0---1---2---3---4---5---6---
E 0---1---2---3---4---0---1---2---3---4---5---6---

Обратите внимание, что 5 первых аккордов и 7 последних аккордов каждой серии имеют разные формы.

Все аккорды являются простыми мажорными или минорными аккордами (без 7-й или других вариаций).

Вы должны заботиться о квартирах тоже. Напоминание:

A# = Bb
C# = Db
D# = Eb
F# = Gb
G# = Ab

B#, Cb, E# and Fb are not used

Выходные данные должны содержать первый столбец с именами кабелей, как показано выше. Он не должен включать название аккорда на вершине. Аккорды должны быть разделены на 3, -как показано выше. Финальные 3 -являются необязательными.

Ввод - это строка, состоящая из имен аккордов, разделенных пробелами.

Пример ввода:

Bm Gb A E G D Em F#

и соответствующий вывод:

e 2---2---0---0---3---5---0---2---
B 3---2---2---0---3---7---0---2---
G 4---3---2---1---4---7---0---3---
D 4---4---2---2---5---7---2---4---
A 2---4---0---2---5---5---2---4---
E 2---2---0---0---3---5---0---2---
Жюль Оллеон
источник
... и дополнительный вопрос: какая песня в качестве примера? :)
Жюль Оллеон
5
Отель Калифорния: P
Мэтью Рид
Да, ты выиграл! :)
Жюль Оллеон
Классная идея Жаль, что я не успел поиграть!
Игби Большой человек

Ответы:

9

JavaScript, 297 277 262 235 223 символа

Никакие возвраты каретки в версии для гольфа не имеют значения; они существуют только для того, чтобы сделать ответ читабельным. Точки с запятой значимы.

Редактировать: заменен внешний mapцикл while и другие правки. Наконец внутри 2 × размер версии Golfscript (пока)!

Изменить: Заменены indexOfс математикой, сломали таблицу поиска, другие небольшие улучшения.

Edit: Еще mapдо forи положить в окончательном \nя был излишне еды. Наконец в версии Python Жюля.

i=prompt(o='').split(' ');for(r=6;o+=' EADGBe'[r]+' ',r--;o+='\n')
for(j=0;n=i[j++];o+=(([84,13,52,5][2*/m/.test(n)+x]*8>>2*r&3)+y-7*x)+'---')
y=n.charCodeAt(0),y=(2*y-(y>66)-(y>69)+(n[1]<'$')-(n[1]=='b')+2)%12,x=y>6;alert(o)

Выход больше не использует преимущество трейлинга ---как:

e 2---2---0---0---3---5---0---2---
B 3---2---2---0---3---7---0---2---
G 4---3---2---1---4---7---0---3---
D 4---4---2---2---5---7---2---4---
A 2---4---0---2---5---5---2---4---
E 2---2---0---0---3---5---0---2---
DocMax
источник
Черт, я думаю, что у меня есть зависть в javascript. Красиво сделано.
Кекекела
7

Golfscript, 136 символов

[["eBGDAE"{[]+" "+}/]]\" "/{.-2\{"bm#A B C D E F G"?.)!!*(+}/14%.3>-.8>-.7/@109?0>2*+[963 780 882 753]{3base(;}%=\7%{+'---'+}+%}%+zip n*

23 символа (17,5%) имеют дело с этими двумя символами в начале каждой строки вывода.

Пример вывода, тестирование крайних случаев:

$ golfscript.rb tabs.gs <<<"E G# Ab A Db D# Em G#m Abm Am D#m"
e 0---4---4---0---4---6---0---4---4---0---5---
B 0---4---4---2---6---8---0---4---4---1---6---
G 1---5---5---2---6---8---0---4---4---2---7---
D 2---6---6---2---6---8---2---6---6---2---7---
A 2---6---6---0---4---6---2---6---6---0---5---
E 0---4---4---0---4---6---0---4---4---0---5---

Я потратил на это всего около часа, так что, вероятно, его можно уменьшить как минимум на 5-10 символов. Концептуально это оказывается очень похоже на решение DocMax: ищите таблицу для четырех случаев, затем увеличивайте смещение и соединяйте строки в правильном порядке.

Питер Тейлор
источник
+1: Человек я люблю Golfscript! Сегодня несколько раз я находил места для обрезки своего кода, но не на 50%! У меня нет удобного переводчика: он возвращает D # для Eb?
DocMax
Кстати, последняя нота в вашем примере соответствует C # m, хотя в командной строке отображается D # m. Опечатка или ошибка?
DocMax
@DocMax, ошибка. Я не понимаю, почему это влияет только на D # m, а не на D # - это будет интересно отлаживать. Я переупорядочиваю вещи, потому что сначала удобно иметь блок 7, так что Eb на самом деле не исключительный случай.
Питер Тейлор
Оказывается, что к последнему добавлялось \ n, а отсутствие в таблице поиска приводило к уменьшению значения на эквивалент буквы.
Питер Тейлор
4

После этого я понял, что мог бы сделать это намного умнее ... возможно, я сделаю еще одну запись. Надеюсь, я просто получу очки за то, что был самым быстрым!

Во всяком случае, есть 962 символов Perl.

%c =(B=>{E=>0,F=>1,Gb=>2,G=>3,Ab=>4,A=>2,Bb=>3,B=>4,C=>5,Db=>6,D=>7,Eb=>8,Em=>0,Fm=>1,Gbm=>2,Gm=>3,Abm=>0,Am=>1,Bbm=>2,Bm=>3,Cm=>4,Dbm=>5,Dm=>6,Ebm=>7},G=>{E=>1,F=>2,Gb=>3,G=>4,Ab=>5,A=>2,Bb=>3,B=>4,C=>5,Db=>6,D=>7,Eb=>8,Em=>0,Fm=>1,Gbm=>2,Gm=>3,Abm=>4,Am=>2,Bbm=>3,Bm=>4,Cm=>5,Dbm=>6,Dm=>7,Ebm=>8},D=>{E=>2,F=>3,Gb=>4,G=>5,Ab=>6,A=>2,Bb=>3,B=>4,C=>5,Db=>6,D=>7,Eb=>8,Em=>2,Fm=>3,Gbm=>4,Gm=>5,Abm=>6,Am=>2,Bbm=>3,Bm=>4,Cm=>5,Dbm=>6,Dm=>7,Ebm=>8},A=>{E=>2,F=>3,Gb=>4,G=>5,Ab=>6,A=>0,Bb=>1,B=>2,C=>3,Db=>4,D=>5,Eb=>6,Em=>2,Fm=>3,Gbm=>4,Gm=>5,Abm=>6,Am=>0,Bbm=>1,Bm=>2,Cm=>3,Dbm=>4,Dm=>5,Ebm=>6},E=>{E=>0,F=>1,Gb=>2,G=>3,Ab=>4,A=>0,Bb=>1,B=>2,C=>3,Db=>4,D=>5,Eb=>6,Em=>0,Fm=>1,Gbm=>2,Gm=>3,Abm=>4,Am=>0,Bbm=>1,Bm=>2,Cm=>3,Dbm=>4,Dm=>5,Ebm=>6});
%b=('A#'=>'Bb','C#'=>'Db','D#'=>'Eb','F#'=>'Gb','G#'=>'Ab');
foreach(qw(e B G D A E)){p($_,@ARGV)}
sub p{$s = shift;print "$s ";$s = uc($s);foreach(@_){while(($h,$f)=each(%b)){s/$h/$f/}print "$c{$s}->{$_}---"}print "\n"}

Вот соответствующий вывод.

dhrasmus:Desktop standage$ perl guitar Bm Gb A E G D Em F#
e 2---2---0---0---3---5---0---2---
B 3---2---2---0---3---7---0---2---
G 4---3---2---1---4---7---0---3---
D 4---4---2---2---5---7---2---4---
A 2---4---0---2---5---5---2---4---
E 2---2---0---0---3---5---0---2---
Дэниэл Стендж
источник
4

Поскольку более короткие решения уже были даны (черт возьми, GolfScript!), Вот мое:

Питон, 229 символов

s=[("E EmF FmF#GbG GmG#AbA AmA#BbB BmC CmC#DbD DmD#Eb".find("%-02s"%s[:2])/4,s[-1]!='m')for s in raw_input().split()]
for c in range(6):
 l='eBGDAE'[c]+' '
 for(i,M)in s:x=i>4;l+=`i-5*x+2*(2<c+x<5)+(M+x)*(c==2-x)`+"---"
 print l

Выход:

> echo "Bm Gb A E G D Em F#" | python guitar.py
e 2---2---0---0---3---5---0---2---
B 3---2---2---0---3---7---0---2---
G 4---3---2---1---4---7---0---3---
D 4---4---2---2---5---7---2---4---
A 2---4---0---2---5---5---2---4---
E 2---2---0---0---3---5---0---2---
Жюль Оллеон
источник
3

Python, 449 символов

z=int
f=str
r=range
j=''.join
n='E F F# G G# A A# B C C# D D#'.split()
n+=[x+'m'for x in n]
c=[j([f(z(x)+i)for x in'001220'])for i in r(5)]+[j([f(z(x)+i)for x in'022200'])for i in r(7)]
c+=[x[:2]+f(z(x[2])-1)+x[3:]for x in c[:5]]+[x[0]+f(z(x[1])-1)+x[2:]for x in c[5:]]
a=[c[n.index((chr(ord(i[0])-1)+'#'+i[2:]).replace('@','G')if len(i)-1 and i[1]=='b'else i)]for i in raw_input().split()] 
for i in r(6):print'eBGDAE'[i],j([x[i]+'-'*3 for x in a])
Фернандо Мартин
источник
3

C99 - 231 символов

Аккорды задаются в командной строке, по одному аргументу в аккорде, и, конечно, нет никакой проверки входных данных.

#include<stdio.h>
int main(int c,char**v){for(char*o="e0)B2)G2*D2+A0+E0)",i,m;*o;o+=3,v-=c,puts(""))for(printf("%c ",*o);*++v;printf("%c---",i-(i>2)-i/9+o[1+i/8]-(*o-66-i/8*5?0:m?m+2[*v]>99:0)))m=1[*v],i=(**v*2-4+m/35-m/98*3)%14;}

Образец прогона:

$ ./a.out Bm Gb A E G D Em F#
e 2---2---0---0---3---5---0---2---
B 3---2---2---0---3---7---0---2---
G 4---3---2---1---4---7---0---3---
D 4---4---2---2---5---7---2---4---
A 2---4---0---2---5---5---2---4---
E 2---2---0---0---3---5---0---2---

Un-golfed

#include<stdio.h>
int main(int c,char**v){
     // o points to three characters per output line:
     //   string name, number for A, adjusted number for E (ASCII code minus 7)
     char* o="e0)B2)G2*D2+A0+E0)",
          i, // chord: A=0, A#=1, ..., G#=13, allowing also 3="E#" and 9="B#"
          m; // second character in chord name
     for (; *o; o+=3) {
          printf("%c ", *o);
          for (; *++v; ) {
               m = 1[*v],
               i = (**v*2-4+m/35-m/98*3)%14; // parse & adjust for sharp, flat
               printf("%c---",
                      i-(i>2)-i/9 // eliminate "E#", "B#"
                      +o[1+i/8] // get the number for a major chord
                      // adjust for minor...
                      -(*o-66-i/8*5
                        ? 0
                        : m ? m+2[*v]>99 : 0));
          }
          v -= c; // rewind argument pointer
          puts("");
     }
}

Нестандартный C - 206 знаков

Если нам не нужны языковые спецификации, GCC может скомпилировать следующую однострочную строку в функциональный двоичный файл, даже если он смешивает объявления переменных C99 с объявлением аргументов в стиле K & R (и неявным объявлением printf).

main(c,v)char**v;{for(char*o="e0)B2)G2*D2+A0+E0)",i,m;*o;o+=3,v-=c,puts(""))for(printf("%c ",*o);*++v;printf("%c---",i-(i>2)-i/9+o[1+i/8]-(*o-66-i/8*5?0:m?m+2[*v]>99:0)))m=1[*v],i=(**v*2-4+m/35-m/98*3)%14;}
хань
источник
2

C ++, 432

#include <cmath>
#include <iostream>
F(int c){c-=65;return c*1.6+sin(c/5.+.3);}
T(int a,int s){if(s)return(a=(T(a,s-1)+2)%3)-=(a==1&s>2);return(a<7)*2;}
#define c(a,b) while(*(++j)==a)b;--j; 
#define O std::cout<<
main(int a,char*p[]){
int P=2;for(int i=-1;++i<6;P=2){O p[1][i];O" ";while(P<a){char*j=p[P++];
int f=F(*j);c('#',++f)c('b',--f)
int t=T(f,i)*3.5;if(*(++j)!='m'){--j;t+=(t==3);}
O(f-F(p[1][i])+t+24)%12;O"---";
}O'\n';}}

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

Для отеля Калифорния вы можете сделать $./a.out EBGDAE Cbm Gb Bbb Fb G D Em F# Bm F# G## D## F## C## D##m E##. Результат:

E 2---2---0---0---3---5---0---2---2---2---5---0---3---5---0---2---
B 3---2---2---0---3---7---0---2---3---2---5---0---3---7---0---2---
G 4---3---2---1---4---7---0---3---4---3---6---1---4---7---0---3---
D 4---4---2---2---5---7---2---4---4---4---7---2---5---7---2---4---
A 2---4---0---2---5---5---2---4---2---4---7---2---5---5---2---4---
E 2---2---0---0---3---5---0---2---2---2---5---0---3---5---0---2---
перестал поворачиваться против часовой стрелки
источник
Настройка верхних четырех струн на второстепенные трети позволяет очень легко сыграть трех- и четырехструнные аккорды во многих инверсиях, без открытых струн и без необходимости помещать палец «поверх» струны, не касаясь ее. Используя струны DFG # B, последовательность аккордов, такая как "Bbm F Bbm Gb Db Ebm Db F Bbm F F7 Bbm" (песня русалки), получается очень легко. Надо только сдвинуться вверх и вниз на один лад. Есть полшага для смены ключей, но это просто означает, что надо двигаться вверх по ладу. Тем не менее, я не понял, что лучше делать с двумя другими строками.
суперкат
@supercat: интересно, я попробую это на моей гитаре завтра ...
перестал вращаться против часовой стрелки
Я хотел бы услышать, что вы думаете. Я брал гитару несколько раз, несколько лет, и продолжал сдаваться, потому что пальчики казались произвольными и неловкими. Потом я задумался о том, какие настройки позволят просто перебирать. Поскольку у аккордов замкнутой формы есть интервалы, которые варьируются от младшей трети до идеальной четверти, настройка строк на второстепенные трети означает, что каждая строка будет затухать в точке, которая не ниже, чем строка ниже. Если бы я мог попробовать левую гитару, я мог бы попробовать идеальные четверти с обратным порядком струн, так как он должен быть похожим.
суперкат
Таким образом, настройка на второстепенные трети означает, что для каждой позиции первого пальца на самой нижней струне будет доступно три основных инверсии аккордов и три младших инверсии аккордов. Можно также сыграть седьмой аккорд, поместив второй палец на три верхние струны. Для Песни Русалки начните с третьего лада и играйте в F-Bb-DF (пальцами 1-3-3-4). Тогда F является FACF (1-2-2-4). Гб до ладу, с пальцами 1-2-2-4 (как F). Db возвращается на лад, 1-3-4-4. Эбм вернулся, 1-2-4-4.
суперкат
Мне потребовалось всего несколько часов, чтобы добраться до точки, где я мог плавно играть некоторые пьесы (включая вышеупомянутую Песню Русалки) после того, как разработал с помощью клавиатуры, какими должны быть надлежащие ноты аккордов. После того, как я попробовал этот стиль, он стал удивительно естественным, и мне очень понравилось, как можно использовать все три инверсии каждого мажорного и минорного аккорда. Если бы кто-то просто хотел мажорные и минорные аккорды, то настройка типа F-Ab-B-Eb-Gb-D теоретически могла бы позволить мажорные и минорные аккорды с шестью пальцами с легкими пальцами (1-2-2-3-4-4 или 1 -1-2-3-3-4) но без инверсий.
суперкат
2

390 345 340 Постскриптум

Упрощено до прагматического подхода к гитаре (форма E - это всего лишь вариация формы A, сдвинутая вниз по струне, со сменой одного пальца). Заимствовал идею закодированной строки из других ответов.

[/p{print}/x{exch}/e{cvx exec}/d{dup 0
get}/f{forall}(A0#1B2C3D5E7F8G:b;){}forall/m{dup
4 2 copy get 1 sub put}109{m 48}/+{[3 1 roll x{1
index add x}f]}/*{[0 0 2 2 2 0 0]x{load e 48 sub
+}f d 12 gt{-12 +}if d 6 gt{m -7 + 1}{0}ifelse 6
getinterval}>>begin[ARGUMENTS{*}f][(E)(A)(D)(G)(B)(e)]6{[x
e p( )p]x[x{[x e( )cvs p(---)p]}f]x()=}repeat

Ранее:

450 442 418 Постскриптум

Я исправил выходной формат с этим тоже. (Предыдущие версии начинались с «E ---», а не «e».)

<</i{index}/a{add}/p{pop}/x{exch}/g{getinterval}/r{print}/f{forall}/e{exec}>>begin<<65[0
2 3 5 -5 -4 -2]{1 i 1 a}f p 35{1 a}98{1 sub}109{x dup
4 20 put x}>>begin[ARGUMENTS{[x[0 5 12 17 21 24 29
0]x{load e}f x{1 i a x}f]dup 0 get 0 ge{0}{1}ifelse 7
g[0 -5 -10 -15 -19 -24 -29]0 1 6{2 copy get 3 i 2 i
get a 3 copy put p p}for x p 0 6
g}f][(E)(A)(D)(G)(B)(e)]6{[x cvx e r( )r]x[x{[x cvx
e( )cvs r(---)r]}f]x(\n)r}repeat

Как его запустить: gsnd -q -- tab.ps Bm Gb A E G D Em F\#(спрячьте острие от раковины).

Версия без гольфа была почти сложнее, чем игра в гольф. Но я старался быть тщательным. Изменить: еще несколько комментариев на хитрости.

%!PS
<<    %axioms and operations
/t{2 2 1}    %major tetrachord
/m{t t 2}    %mixolydian mode
/u{2 1 2}    %minor tetrachord
/a{u u}      %aolian mode
/s{m m t}    %2.5-octave mixolydian intervals
/r{3 1 roll}
/${[exch 0 exch{1 index add}forall]}    %running sum: convert (relative)intervals to (abstract)fretstops
/+{[r exch{1 index add exch}forall pop]}    %scale array by scalar
/@{[r{2 copy get r pop}forall pop]}    %select array elements from array of indices
/&{0 1 3 index length 1 sub{    %array2 += array1
    2 copy get 3 index 2 index get add 3 copy put pop pop}for exch pop}
>>begin<<    %map ascii values to scaling functions
65[a]$    %generate fretstops of the A aolian scale to assign scalars to note names
[0 0 0 0 -12 -12 -12]&    %drop E F and G down an octave
{[exch/+ cvx]cvx 1 index 1 add}forall pop    %generate the pairs 'A'->{0 +}, 'B'->{2 +}
35{1 +}     %'#'-> scale up by one
98{-1 +}    %'b'-> scale down by one
109{dup 4 2 copy get 1 sub put}     %'m'-> tweak the 'third' down by one
%generate chord pattern from (string)
/*{[s]$       %generate fretstops of the E mixolydian scale
  [1 4 8 11 13 15 18]    %A-shape figured bass: IV chord of E mixolydian
  -1 +       %convert scale degrees to array indices
  @       %generate chord template by selecting indices from mixolydian scale
  exch{load exec}forall       %execute ascii values, scaling the pattern
  dup 0 get 0 ge{0}{1}ifelse 6 getinterval    %discard first note if it has fallen off the bottom
  [0 -5 -10 -15 -19 -24]&}    %subtract the string offsets
>>begin    %activate definitions
%(A)* pstack()= clear    %[0 0 2 2 2 0]
%(B)* pstack()= clear    %[2 2 4 4 4 2]
%(F#)* pstack()= clear    %[2 4 4 3 2 2]
%(Abm)* pstack()=    %[4 6 6 4 4 4]
[ARGUMENTS{*}forall]    %convert array of strings to array of patterns
[(E)(A)(D)(G)(B)(e)]    %array of string names
6{    %for each "string"
    [exch cvx exec print( )print]    %pop string name and print with space
    exch       %put names behind numbers
    [exch{     %for each "chord"
        [exch cvx exec( )cvs print(---)print]    %pop number, convert, print with trailing hyphens
    }forall]    %zip up chord array for next iteration
    ()=         %print a newline
    exch        %put numbers behind names
}repeat

А как насчет Дома Восходящего Солнца в качестве теста?

04:51 PM:~ 0> gsnd -q -- tabb.ps Em G A C Em G B B Em G A C Em B Em B|sed 's/^/    /'
e 0---3---0---3---0---3---2---2---0---3---0---3---0---2---0---2---
B 0---3---2---5---0---3---4---4---0---3---2---5---0---4---0---4---
G 0---4---2---5---0---4---4---4---0---4---2---5---0---4---0---4---
D 2---5---2---5---2---5---4---4---2---5---2---5---2---4---2---4---
A 2---5---0---3---2---5---2---2---2---5---0---3---2---2---2---2---
E 0---3---0---3---0---3---2---2---0---3---0---3---0---2---0---2---
Люзер Дрог
источник
Я написал комментарий к этому коду в другом ответе здесь .
luser droog