Berapa banyak semi-nada

21

Pedoman

Tugas

Diberikan dua catatan, dimasukkan sebagai string atau daftar / array, menghitung berapa banyak semi-terpisah mereka (termasuk catatan itu sendiri), menghasilkan sebagai angka.

Penjelasan tentang semitone:

Semitone adalah satu langkah ke atas atau ke bawah keyboard. Contohnya adalah C to C #. Seperti yang Anda lihat di bawah, catatan C ada pada catatan putih dan C # adalah catatan hitam hanya satu di atasnya. Semitones adalah lompatan dari catatan hitam ke catatan putih berikutnya, atas atau bawah, kecuali untuk:

  • B ke C
  • C ke B
  • E ke F
  • F ke E

keyboard

Contohnya

'A, C' -> 4

'G, G#' -> 2

'F#, B' -> 6

'Bb, Bb' -> 13


Aturan

  • Jarak terbesar antara dua not adalah 13 semitone.
  • Catatan yang dimasukkan kedua akan selalu berada di atas catatan yang dimasukkan pertama.
  • Anda dapat mengambil input baik sebagai string, atau array / daftar. Jika Anda menganggapnya sebagai string, catatan akan dipisahkan dengan koma (mis. String -> 'A, F', Array -> ['A', 'F']).
  • Anda dapat mengasumsikan bahwa Anda akan selalu diberikan dua catatan yang valid.
  • Benda tajam akan dilambangkan sebagai #dan flat akan dilambangkan sebagaib
  • Kode Anda harus mendukung setara setara denganarmarmonik (misalnya, harus mendukung F # dan Gb)
  • Kode Anda tidak perlu mendukung catatan yang diberi nama, tetapi dapat dinamai tanpa tajam atau datar (mis. Anda tidak perlu mendukung E #, atau Cb). Poin bonus jika kode Anda mendukungnya.
  • Kode Anda tidak perlu mendukung benda tajam ganda atau apartemen ganda.
  • Anda dapat mengasumsikan bahwa jika Anda mendapatkan kedua not yang sama, atau nada yang sama (misalnya 'Gb, Gb' atau 'A #, Bb'), not kedua tidak akan tepat satu oktaf di atas yang pertama.
  • Ini adalah kode golf sehingga jawabannya dengan jumlah byte terkecil menang.
Amorris
sumber
Saya mendapat 2 G -> G#karena mereka sama-sama termasuk.
HyperNeutrino
@HyperNeutrino Yep maaf. Kesalahan atas nama saya.
Amorris
1
Apakah kita harus memenuhi catatan suka Cbatau tidak E#? Bagaimana dengan benda tajam ganda / flat?
Sok
1
@ Oke Tidak, kode Anda tidak perlu mendukung catatan seperti E # atau Cb, dan tidak perlu mendukung benda tajam atau flat ganda. Saya telah memperbarui pertanyaan untuk membuatnya lebih jelas. Maaf tentang kebingungan.
Amorris
2
Hanya untuk menjadi jelas, ketika berbicara dari teori rasa musik dalam semitones tidak termasuk catatan Anda mulai. Dalam matematika itu wold diwakili sebagai (X, Y]C to C # adalah 1 semitone dan C to C adalah 12 semitones.
Dom

Jawaban:

7

Python 2 , 66 byte

r=1
for s in input():r=cmp(s[1:]+s,s)-ord(s[0])*5/3-r
print-r%12+2

Cobalah online!


Python 2 , 68 byte

lambda s,t:13-(q(s)-q(t))%12
q=lambda s:ord(s[0])*5/3+cmp(s,s[1:]+s)

Cobalah online!

Tidak
sumber
Poin ekstra karena bisa menangani catatan seperti B # dan Fb, sementara masih tetap terpendek sejauh ini.
Amorris
7

JavaScript (ES6), 78 byte

Disimpan 1 byte berkat @Neil

Membawa catatan dalam sintaks currying (a)(b).

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

Uji kasus

Fungsi hash

Tujuan dari fungsi hash adalah untuk mengubah catatan menjadi pointer dalam tabel pencarian yang mengandung offset semitone (C = 0, C # = 1, ..., B = 11), disimpan dalam heksadesimal.

Kami pertama append sebuah '3' ke catatan dan mengurai string yang dihasilkan dalam basis-36, yang mengarah ke integer N . Karena '#' adalah karakter yang tidak valid, itu hanya diabaikan, bersama dengan karakter yang mengikutinya.

Kemudian kami menghitung:

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

Di bawah ini adalah ringkasan dari hasilnya.

 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

Tentang flat dan benda tajam

Di bawah ini adalah bukti bahwa fungsi hash ini memastikan bahwa catatan diikuti oleh '#' memberikan hasil yang sama dari catatan berikutnya diikuti oleh 'b' . Dalam paragraf ini, kami menggunakan awalan @ untuk jumlah basis-36.

Misalnya, Db akan dikonversi ke @ db3 dan C # akan dikonversi ke @c (lihat paragraf sebelumnya). Kami ingin membuktikan bahwa:

H(@db3) = H(@c)

Atau dalam kasus umum, dengan Y = X + 1 :

H(@Yb3) = H(@X)

@ b3 adalah 399 dalam desimal. Karena itu:

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 sesuai dengan 1 modulo 37 , jadi ini dapat disederhanakan sebagai:

(@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)

Kasus khusus adalah transisi dari G # ke Ab , seperti yang kita harapkan Hb untuk mematuhi formula di atas. Namun, ini juga berfungsi karena:

@ab3 * 2 % 37 % 14 = @hb3 * 2 % 37 % 14 = 4
Arnauld
sumber
@Neil Terima kasih! Optimasi Anda menghemat lebih banyak byte daripada milikku.
Arnauld
Huh, saya benar-benar menemukan kebalikannya dengan solusi Batch saya ...
Neil
@ Neil Karena tanda modulo di Batch adalah tanda pembagi, saya kira?
Arnauld
Tidak, itu adalah tanda dari dividen, seperti pada JS, tetapi ternyata menjadi sedikit pegolf mengoreksi tanda hasil yang telah terbalik karena golf sebelumnya.
Neil
4

Perl, 39 32 byte

Termasuk +1untukp

Berikan catatan awal dan akhir sebagai dua baris pada STDIN

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

Hanya kode:

$\=(/#/-/b/-$\+5/3*ord)%12+$.}{
Ton Hospel
sumber
@astl Jadi saya sudah diberitahu. Saya ingin tahu pos meta mana sehingga saya bisa pergi ke sana dan tidak setuju :-)
Ton Hospel
Komentar saya adalah tautan. Jangan ragu untuk mengkliknya.
wastl
Sepertinya ini bekerja sangat mirip dengan saya - tetapi sangat pendek untuk Perl, +1
Level River St
@LevelRiverSt baik, ini adalah Ton Hospel.
msh210
4

Japt , 27 byte

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

Uji secara online! Mengambil input sebagai array dari dua string.

Juga berfungsi untuk jumlah benda tajam atau flat apa pun pada catatan dasar!

Penjelasan

®¬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.
Produksi ETH
sumber
2

Perl 5 + -p, 66 byte

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

Cobalah online!

Mengambil nilai yang dipisahkan koma. Juga berfungsi untuk Cb, B #, E #, Fb dan banyak # / b.

Penjelasan:

# 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'

Penjelasan untuk eval:

(
    - (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
wastl
sumber
2

Ruby , 56 byte

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

Cobalah online!

Huruf-huruf diurai sesuai dengan waktu kode ASCII mereka 5/3sebagai berikut (ini memberikan jumlah semitones yang diperlukan ditambah offset 108)

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

Karakter terakhir ( #, batau huruf lagi) diurai sebagai kode ASCII dibagi dengan 32 sebagai berikut

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

Ini dikurangi dari kode huruf.

Kemudian hasil akhir dikembalikan sebagai 13-(difference in semitones)%12

Level River St
sumber
2

Stax , 25 24 byte

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

Jalankan dan debug secara online

Representasi ascii yang sesuai dari program yang sama adalah ini.

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

Secara efektif, ini menghitung indeks keyboard dari setiap catatan menggunakan rumus, lalu menghitung interval yang dihasilkan.

  1. Mulai dari catatan dasar, A = 2, B = 4, ... G = 14
  2. Hitung offset kebetulan di 2 - code / 32manacode kode ascii dari karakter terakhir.
  3. Tambahkan bersama.
  4. Jika hasilnya> 4, kurangi 1 untuk menghapus B #.
  5. Jika hasilnya> 7, kurangi 1 untuk menghapus E #.
  6. Cukup kurangi dua indeks catatan yang dihasilkan, dan tambahkan 1.
rekursif
sumber
1
["F#","B"]seharusnya 6.
Weijun Zhou
1
Terima kasih. Saya mengubah setengah perhitungan tanpa menyesuaikan yang lain. Sudah diperbaiki.
rekursif
1

Batch, 136 135 byte

@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

Penjelasan: Penggantian di csubrutin menggantikan #nama catatan dengan +1dan bdengan -1. Karena hal ini tidak sensitif huruf, Bbmenjadi -1-1. Variabel untukC ... A(karena itu juga tidak peka huruf besar-kecil) oleh karena itu dipilih untuk menjadi jumlah semitones yang tepat dari B=-1. String yang dihasilkan kemudian dievaluasi, dan trik @ xnor untuk mengurangi hasil dari nilai memberikan efek yang diinginkan dengan mengurangkan nilai catatan dari satu sama lain. Sunting: Akhirnya saya menggunakan trik @ Arnauld untuk mengurangi modulo dari 13 untuk mencapai jawaban yang diinginkan, menghemat 1 byte.

Neil
sumber
1

Python 3 , 95 byte

lambda a,b:(g(b)+~g(a))%12+2
g=lambda q:[0,2,3,5,7,8,10][ord(q[0])-65]+" #".find(q.ljust(2)[1])

Cobalah online!

-14 byte terima kasih kepada user71546

HyperNeutrino
sumber
-8 byte dengan ord(q[0])-65mengganti "ABCDEFG".find(q[0]);)
Shieru Asakoto
Oh, -6 byte lebih banyak dengan (g(b)+~g(a))%12+2penggantian1+((g(b)-g(a))%12or 12)
Shieru Asakoto
@ user71546 oh keren, terima kasih!
HyperNeutrino
1

Jelly , 28 byte

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

Tautan monadik yang menerima daftar dua daftar karakter dan mengembalikan integer.

Cobalah online! atau lihat semua kemungkinan kasus .

Bagaimana?

Melakukan beberapa aritmatika aneh pada tata cara karakter input untuk memetakan catatan ke bilangan bulat nol sampai dua belas dan kemudian melakukan dekompresi dasar sebagai proksi untuk modulo oleh dua belas di mana nol kemudian diganti dengan 12 kemudian menambahkan satu.

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

Juga pada 28 byte ...

Port (tidak langsung) dari jawaban Python 2 xnor ...

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

Coba semua kemungkinan kasus

Jonathan Allan
sumber