多少个半音


21

指导方针

任务

给定两个以字符串或列表/数组形式输入的音符,计算它们之间有多少个半音(包括音符本身),并以数字形式输出。

半音说明:

半音是键盘上移或下移的一步。一个例子是C到C#。如您所见,音符C在白色音符上,而C#在其上方是黑色音符。半音是从黑色音符到下一个白色音符(向上或向下)的跳跃,除了:

  • 企业对企业
  • C到B
  • E到F
  • 从F到E

键盘

例子

'A, C' -> 4

'G, G#' -> 2

'F#, B' -> 6

'Bb, Bb' -> 13


规则

  • 两个音符之间的最大距离是13个半音。
  • 第二个输入的注释将始终位于第一个输入的注释上方。
  • 您可以将输入作为字符串或数组/列表。如果将其作为字符串,则注释将以逗号分隔(例如String -> 'A, F'Array -> ['A', 'F'])。
  • 您可以假设您将始终得到两个有效的注释。
  • 锐利将表示为#,单位将表示为b
  • 您的代码必须支持等效谐波(例如,它必须同时支持F#和Gb)
  • 您的代码不需要支持以命名的注释,但是可以不带尖锐或平整的名称来命名(即,您不需要支持E#或Cb)。如果您的代码确实支持它,则可以加分。
  • 您的代码不需要支持双尖或双平。
  • 您可以假设,如果您获得了相同的音符或相同的音高(例如“ Gb,Gb”或“ A#,Bb”),则第二个音符将不比第一个音符高一个八度。
  • 这是代码高尔夫,因此字节数最少的答案会获胜。

我得到2,G -> G#因为它们都包括在内。
HyperNeutrino

@HyperNeutrino是的,抱歉。代表我的错误。
Amorris

1
我们必须迎合像Cb或这样的音符E#吗?那双尖锐/平坦的东西呢?
Sok

1
@Sok不,您的代码不需要支持E#或Cb之类的注释,也不需要支持双尖或平坦。我已经更新了问题,以使其更清楚。对不起,造成任何混乱。
阿莫里斯

2
只是要清楚一点,从音乐理论讲起时,半音的感应距离包括您开始的音符。在数学上,它将表示为(X, Y]C至C#为1个半音,而C至C为12个半音。
Dom '18

Answers:



7

JavaScript(ES6),78个字节

@Neil节省了1个字节

以currying语法记录笔记(a)(b)

a=>b=>((g=n=>'0x'+'_46280ab_91735'[parseInt(n+3,36)*2%37%14])(b)-g(a)+23)%12+2

测试用例

哈希函数

哈希函数的目的是在包含半音偏移量(C = 0,C#= 1,...,B = 11)的查找表中将注释转换为指针,并以十六进制存储。

我们首先追加一个“3”的说明和解析在碱-36得到的字符串,从而导致的整数Ñ。因为“#”是无效字符,所以它以及其后的任何字符都会被忽略。

然后我们计算:

H(N) = ((N * 2) MOD 37) MOD 14

以下是结果摘要。

 note | +'3' | parsed as | base 36->10 |   *2  | %37 | %14 | offset
------+------+-----------+-------------+-------+-----+-----+--------
  C   |  C3  |    c3     |         435 |   870 |  19 |   5 |  0x0
  C#  |  C#3 |    c      |          12 |    24 |  24 |  10 |  0x1
  Db  |  Db3 |    db3    |       17247 | 34494 |  10 |  10 |  0x1
  D   |  D3  |    d3     |         471 |   942 |  17 |   3 |  0x2
  D#  |  D#3 |    d      |          13 |    26 |  26 |  12 |  0x3
  Eb  |  Eb3 |    eb3    |       18543 | 37086 |  12 |  12 |  0x3
  E   |  E3  |    e3     |         507 |  1014 |  15 |   1 |  0x4
  F   |  F3  |    f3     |         543 |  1086 |  13 |  13 |  0x5
  F#  |  F#3 |    f      |          15 |    30 |  30 |   2 |  0x6
  Gb  |  Gb3 |    gb3    |       21135 | 42270 |  16 |   2 |  0x6
  G   |  G3  |    g3     |         579 |  1158 |  11 |  11 |  0x7
  G#  |  G#3 |    g      |          16 |    32 |  32 |   4 |  0x8
  Ab  |  Ab3 |    ab3    |       13359 | 26718 |   4 |   4 |  0x8
  A   |  A3  |    a3     |         363 |   726 |  23 |   9 |  0x9
  A#  |  A#3 |    a      |          10 |    20 |  20 |   6 |  0xa
  Bb  |  Bb3 |    bb3    |       14655 | 29310 |   6 |   6 |  0xa
  B   |  B3  |    b3     |         399 |   798 |  21 |   7 |  0xb

关于公寓和利器

下面是证明此哈希函数可确保后跟'#'的注释与下一个后跟'b'的注释具有相同的结果。在本段中,我们对以36为基数的数量使用前缀@

例如,Db将转换为@ db3C#将转换为@c(请参见上一段)。我们想证明:

H(@db3) = H(@c)

或通常情况下,Y = X + 1

H(@Yb3) = H(@X)

@ b3是十进制的399。因此:

H(@Yb3) =
@Yb3 * 2 % 37 % 14 =
(@Y * 36 * 36 + 399) * 2 % 37 % 14 =
((@X + 1) * 36 * 36 + 399) * 2 % 37 % 14 =
(@X * 1296 + 1695) * 2 % 37 % 14

1296是全等1个37,所以这可以简化为:

(@X + 1695) * 2 % 37 % 14 =
((@X * 2 % 37 % 14) + (1695 * 2 % 37 % 14)) % 37 % 14 =
((@X * 2 % 37) + 23) % 37 % 14 =
((@X * 2 % 37) + 37 - 14) % 37 % 14 =
@X * 2 % 37 % 14 =
H(@X)

一种特殊情况是从G#Ab的过渡,正如我们期望Hb以便符合上述公式一样。但是,由于以下原因,它也可以工作:

@ab3 * 2 % 37 % 14 = @hb3 * 2 % 37 % 14 = 4

@尼尔谢谢!您的优化节省了比我更多的字节。
Arnauld

呵呵,实际上我的Batch解决方案发现了相反的情况
Neil

@Neil因为批处理中模的符号是除数的符号,所以我猜想吗?
Arnauld

不,与JS一样,它是分红的标志,但事实证明,由于早期打高尔夫球,对结果结果的标志进行校正的程度有点高。
尼尔

4

Perl,39 32字节

包括+1用于p

在STDIN的两行中给出开始和结束注释

(echo "A"; echo "C") | perl -pe '$\=(/#/-/b/-$\+5/3*ord)%12+$.}{'; echo

只是代码:

$\=(/#/-/b/-$\+5/3*ord)%12+$.}{


@wastl所以有人告诉我。我想知道是哪个meta帖子,所以我可以去那里不同意:-)
Ton Hospel

我的评论是一个链接。随时单击它。
wastl

看起来这与我的工作原理非常相似-但Perl,+ 1的绝佳缩写
Level River St

@LevelRiverSt好,这 Ton Hospel。
msh210 '18

4

Japt,27个字节

®¬x!b"C#D EF G A"ÃrnJ uC +2

在线测试!将输入作为两个字符串的数组。

也适用于任何基音上的任何尖锐或平坦!

说明

®¬x!b"C#D EF G A"ÃrnJ uC +2   Let's call the two semitones X and Y.
®                Ã            Map X and Y by
 ¬                              splitting each into characters,
  x                             then taking the sum of
   !b"C#D EF G A"               the 0-based index in this string of each char.
                                C -> 0, D -> 2, E -> 4, F -> 5, G -> 7, A -> 9.
                                # -> 1, adding 1 for each sharp in the note.
                                b -> -1, subtracting 1 for each flat in the note.
                                B also -> -1, which happens to be equivalent to 11 mod 12.
                                The sum will be -2 for Bb, 2 for D, 6 for F#, etc.
                              Now we have a list of the positions of the X and Y.
                  rnJ         Reduce this list with reversed subtraction, starting at -1.
                              This gets the difference Y - (X - (-1)), or (Y - X) - 1.
                      uC      Find the result modulo 12. This is 0 if the notes are 1
                              semitone apart, 11 if they're a full octave apart.
                         +2   Add 2 to the result.

2

Perl 5 + -p,66字节

s/,/)+0x/;y/B-G/013568/;s/#/+1/g;s/b/-1/g;$_=eval"(-(0x$_-1)%12+2"

在线尝试!

取逗号分隔的值。也适用于Cb,B#,E#,Fb和多个#/ b。

说明:

# input example: 'G,G#'
s/,/)+0x/; # replace separator with )+0x (0x for hex) => 'G)+0xG#'
y/B-G/013568/; # replace keys with numbers (A stays hex 10) => '8)+0x8#'
s/#/+1/g; s/b/-1/g; # replace accidentals with +1/-1 => '8)+0x8+1'
$_ = eval # evaluate => 2
    "(-(0x$_-1)%12+2" # add some math => '(-(0x8)+0x8+1-1)%12+2'

评估说明:

(
    - (0x8) # subtract the first key => -8
    + 0x8 + 1 # add the second key => 1
    - 1 # subtract 1 => 0
) % 12 # mod 12 => 0
+ 2 # add 2 => 2
# I can't use % 12 + 1 because 12 (octave) % 12 + 1 = 1, which is not allowed

2

Ruby,56个字节

->a{a.map!{|s|s.ord*5/3-s[-1].ord/32}
13-(a[0]-a[1])%12}

在线尝试!

字母将按照其ASCII码时间进行解析5/3,如下所示(这给出了所需的半音数加上108的偏移量)

A    B    C    D    E    F    G
108  110  111  113  115  116  118

的最后一个字符(#b或再次字母)如下被解析为ASCII码除以32

# letter (natural) b 
1  { --- 2 --- }   3

这是从字母代码中减去的。

然后将最终结果返回为 13-(difference in semitones)%12


2

Stax25 24 字节

╝─°U┤ƒXz☺=≡eA╕δ┴╬\¿☺zt┼§

在线运行和调试

同一程序的相应ascii表示法是这样的。

{h9%H_H32/-c4>-c9>-mrE-v12%^^

有效地,它使用公式计算每个音符的键盘索引,然后计算结果间隔。

  1. 从基音开始,A = 2,B = 4,... G = 14
  2. 计算意外偏移量2 - code / 32,其中,code是最后一个字符的ASCII码。
  3. 将它们加在一起。
  4. 如果结果> 4,则减1以删除B#。
  5. 如果结果> 7,则减1以删除E#。
  6. 以模块化方式减去两个结果便笺索引,然后加1。

1
["F#","B"]应该是6
卫军周

1
谢谢。我更改了计算的一半,而没有调整另一半。它是固定的。
递归

1

批处理,136135字节

@set/ac=0,d=2,e=4,f=5,g=7,a=9,r=24
@call:c %2
:c
@set s=%1
@set s=%s:b=-1%
@set/ar=%s:#=+1%-r
@if not "%2"=="" cmd/cset/a13-r%%12

说明:在该置换c子程序更换#的说明名称用+1b-1。由于这是不区分大小写的,因此Bb变为-1-1。因此,C... 的变量A(也不区分大小写)应选择为远离的适当数量的半音B=-1。然后评估结果字符串,并使用@xnor的技巧从值中减去结果,从而获得了彼此减去音符值的预期效果。编辑:最后,我使用@Arnauld的技巧,从13中减去模数以获得所需的答案,节省了1个字节。



1

果冻,28 个字节

O64_ṠH$2¦ḅ-AḤ’d5ḅ4µ€IḞṃ12FṪ‘

一个接受两个字符列表并返回一个整数的单子链接。

在线尝试!或查看所有可能的情况

怎么样?

在输入字符的序数上执行一些奇异的算术,以将音符映射到零到十二的整数,然后执行基数解压缩,以十二为模的代数,然后零被12取代,然后加一。

O64_ṠH$2¦ḅ-AḤ’d5ḅ4µ€IḞṃ12FṪ‘ - Main link, list of lists    e.g. [['F','#'],['B']]  ...or [['A','b'],['G','#']]
                  µ€         - for €ach note list          e.g.  ['F','#'] ['B']          ['A','b'] ['G','#']
O                            - { cast to ordinal (vectorises)    [70,35]   [66]           [65,98]   [71,35]
 64                          -   literal 64
   _                         -   subtract (vectorises)           [-6,29]   [-2]           [-1,-34]  [-7,29]
        ¦                    -   sparse application...
       2                     -   ...to indices: [2] (just index 2)
      $                      -   ...do: last two links as a monad:
    Ṡ                        -          sign                     [-6,1]    [-2]           [-1,-1]   [-7,1]
     H                       -          halve                    [-6,-0.5] [-2]           [-1,-0.5] [-7,0.5]
         ḅ-                  -   convert from base -1            5.5       -2             0.5       7.5
           A                 -   absolute value                  5.5       2              0.5       7.5
            Ḥ                -   double                          11.0      4              1.0       15.0
             ’               -   decrement                       10.0      3              0.0       14.0
              d5             -   divmod by 5                     [2.0,2.0] [0,3]          [0.0,0.0] [2.0,4.0]
                ḅ4           -   convert from base 4             10.0      3              0.0       12.0
                             - } -->                             [10.0,3]                 [0.0,12.0]
                    I        - incremental differences           [-7.0]                   [12.0]
                     Ḟ       - floor (vectorises)                [-7]                     [12]
                      ṃ12    - base decompress using [1-12]      [[5]]                    [[1,12]]
                         F   - flatten                           [5]                      [1,12]
                          Ṫ  - tail                              5                        12
                           ‘ - increment                         6                        13

同样是28个字节...

xnor的Python 2答案的一个端口(不是那么直接)...

O×5:3z60_Ṡ¥2¦60U1¦Fḅ-‘N%12+2

尝试所有可能的情况


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.