白键钢琴和弦


9

背景故事[不正确]

钢琴的设置如下:

![http://www.piano-lessons-made-simple.com/images/2-Octave-Labled.gif

但是,在我的钢琴上,所有黑键都坏了!

我仍然希望能够在坏了的钢琴上弹奏一些和弦。

在音乐中,和弦是一起演奏的一组音符。为了输入和弦,我将首先定义什么是半音。

什么是半音?

半音是西方音乐中最小的距离。如果您看一下钢琴的顶部,您会发现通常可以从黑键移到白键,反之亦然。然而,与BCEF没有黑键。

什么是和弦?

出于此挑战的目的,我们将和弦定义为一堆音符,在它们之间具有一定数量的半音。例如,让我们开始学习一个4-3-3和弦C(对于音乐人来说,这是F大调中的V 7和弦)。我们从开始C。我们指望了4个半音:C#DD#E。接下来需要注意的是E,我们算3个半音起来后认为:FF#G。接下来需要注意的是G,我们算3个半音起来后认为:G#ABb。因此,我们得到了C-E-G-Bb。好极了!但是,等待... Bb是一把黑钥匙,那些钥匙已经坏了...但是,如果我们从开始G,我们会得到G-B-D-F!好极了!

输入项

输入以任何合理格式的整数列表形式给出。这代表如上所述的和弦。

输出量

输出应该是一个注释列表,我可以在此开始使用白键。这也可以是最多7个音符的字符串,因为所有键名都是一个字符。您还必须能够处理空的输出。

测试用例

input -> output // comments
4 3 -> C F G // this is a major triad
3 4 -> D E A // this is a minor triad
4 3 3 -> G // this is the major-minor seventh chord
3 3 3 -> [empty output] // this is the diminished-diminished seventh chord. All of them use black keys
4 4 -> [empty output] // this is an augmented triad
3 3 -> B // this is a diminished triad
1 -> B E // this is just a minor second
11 -> C F // this is just a major seventh

其他规格

  • 禁止标准漏洞
  • 您可以假定输入至少有一个整数
  • 您可以假设所有整数均为非负且小于12(因为钢琴每12个音符重复一次)
  • 输出可以是任何顺序

获奖标准

截至4月15日的最短有效提交将被接受。


我们可以假设“非负且小于12”-是否不应该为“正且小于或等于12”?
乔纳森·艾伦

@JonathanAllan根本没有区别;我的方法允许一个完美的同调,但不能一个完美的八度 反之亦然。从理论上讲,您的限制可能更有意义,但我想我不应该更改它,因为已经有了答案,并且从根本上不会改变挑战。
HyperNeutrino

Answers:


3

果冻,25 个字节

236ḃ2ṙЀ7+\€Ṭ
+\ịþ¢Ạ€TịØA

在线尝试!或查看测试套件

怎么样?

236ḃ2ṙЀ7+\€Ṭ - Link 1, white-note-offsets: no arguments
236ḃ2         - 236 in bijective base 2 [2, 2, 1, 2, 2, 1, 2] - semitones G->A, A->B ...
     ṙЀ7     - rotate left by, mapped over [1,2,3,4,5,6,7] - i.e. as above for each
                    starting white key (1st one A->B,B->C,...; 2nd B->C,C->D,...; etc)
         +\€  - reduce €ach with addition - i.e. absolute number of semitones: [[2,3,5,7,8,10,12],[1,3,5,6,8,10,12],[2,4,5,7,9,11,12],[2,3,5,7,9,10,12],[1,3,5,7,8,10,12],[2,4,6,7,9,11,12],[2,4,5,7,9,10,12]]
            Ṭ - untruth (vectorises) - make lists with 1s at those indexes: [[0,1,1,0,1,0,1,1,0,1,0,1],[1,0,1,0,1,1,0,1,0,1,0,1],[0,1,0,1,1,0,1,0,1,0,1,1],[0,1,1,0,1,0,1,0,1,1,0,1],[1,0,1,0,1,0,1,1,0,1,0,1],[0,1,0,1,0,1,1,0,1,0,1,1],[0,1,0,1,1,0,1,0,1,1,0,1]]

+\ịþ¢Ạ€TịØA - Main link: list of semitone gap integers (even negatives will work)
+\          - reduce by addition - gets the absolute semitone offsets needed
    ¢       - last link (1) as a nilad
   þ        - outer product with:
  ị         -     index into - 7 lists, each with 1s for white and 0s for black keys hit
                      note that indexing is modular and all the lists are length 12
                      so any integer is a valid absolute offset, not just 0-11 inclusive
     Ạ€     - all truthy for €ach - for each get a 1 if all keys are white ones, else 0
       T    - truthy indexes - get the valid starting white keys as numbers from 1 to 7
        ị   - index into:
         ØA -     the uppercase alphabet

6

MATL,31个字节

感谢乔纳森·艾伦的更正。

'BAGFEDC'"GYs12X\110BQX@YSYsm?@

在线尝试!验证所有测试用例

说明

该模式2 2 1 2 2 2 1指定连续的白键之间的间隔。程序使用将所有循环移位应用于此基本模式的循环,以便将每个琴键测试为输入和弦的潜在最低音。对于每个班次,都将获得图案的累计总和。例如,B作为潜在最低音符,该模式已移至1 2 2 1 2 2 2,其累积总和为1 3 5 6 8 10 12

现在,要查看它是否可以支持4 3 3和弦,我们计算和弦间隔的累积和,即4 7 10;通过基于1模12(的间隔减少它14会给2); 并检查这些数字是否全部为允许值的成员1 3 5 6 8 10 12。在此示例中情况并非如此。如果是这样,我们将输出这封信B

循环移位和输出字母之间的对应关系由字符串定义'BAGFEDC'。这表明'B'(第一个字符)对应于循环移位1'A'(第二个字符)对应于循环移位2等。

'BAGFEDC'  % Push this string
"          % For each character from the string
  G        %   Push input array
  Ys       %   Cumulative sum
  12X\     %   1-based modulo 12, element-wise (1,12,13,14 respectively give 1,12,1,2)
  110BQ    %   Push 110, convert to binary, add 1 element-wise: gives [2 2 1 2 2 2 1]
  X@       %   Push current iteration index, starting at 1
  YS       %   Cyclic shift to the right by that amount
  Ys       %   Cumulative sum
  m        %   Ismember. Gives an array of true of false entries
  ?        %   If all true
    @      %     Push current character
           %   End (implicit)
           % End (implicit)
           % Display (implicit)

5

Mathematica,110个字节(ISO 8859-1编码)

±i_:=#&@@@Select["A#BC#D#EF#G#"~StringTake~{Mod[#,12,1]}&/@#&/@(Accumulate[i~Prepend~#]&/@Range@12),FreeQ@"#"]

定义一元函数,±将整数列表作为输入(实际上对整数的大小或符号没有限制),并返回一个单字符字符串列表。例如,±{3,4}return {"A","D","E"}

"A#BC#D#EF#G#"~StringTake~{Mod[#,12,1]}&/@#是将整数列表转换为相应音符名称的函数,除了#代表任何黑键之外。这个被施加到的每个元素Accumulate[i~Prepend~#]&/@Range@12,它从音符的时间间隔的列表输入列表积聚音符值的列表,从每个可能的音符从1到12,我们筛选出包含所有这样的音符名列表"#"使用Select[...,FreeQ@"#"],然后使用来返回每个剩余列表中的第一个音符#&@@@


不错的提交!
HyperNeutrino

问题:Mathematica是否使用自己的字节系统?这是110个字符,但是在UTF-8中,由于+/-符号的原因,它是111个字节。
HyperNeutrino

您可以完全删除分配,而仅“隐式返回”一个函数。
wizzwizz4

@ wizzwizz4:我发现我不得不在其中命名变量,Accumulate[i~Prepend~#]&因为否则会发生冲突。随时找到解决方法!
格雷格·马丁

@HyperNeutrino:对的,UTF-8是标准编码,但是Mathematica也可以(通常)以ISO 8859-1编码运行。我已经在帖子中指出了这一点。
格雷格·马丁

3

Python 2中,159个 155字节

(在确保提交的有效提交短于此提交之后,发布此信息)

import numpy
s='C.D.EF.G.A.B'
def k(y):return lambda x:s[(x+y)%12]
for i in range(12):
    if s[i]!='.'and'.'not in map(k(i),numpy.cumsum(input())):print s[i]

几乎只是微不足道的解决方案。输入为整数列表,输出每个字符在一行上。

-4字节,通过删除不必要的变量


3

JavaScript(ES6),72 71 68字节

a=>[..."C1D1EF1G1A1B"].filter((c,i,b)=>!+c>a.some(e=>+b[i+=e,i%12]))

遍历每个键,省略黑键,然后检查半音的累积总和是否不会落在黑键上。

编辑:由于@Arnauld,节省了3个字节。


4
可读性?!您确定自己在正确的网站上吗?:-)
wizzwizz4
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.