##はじめに
この記事は以下のサイトにあった問題を解いてみたものです。Rubyのアウトプットを目的として作成しました。
[アウトプットのネタに困ったらこれ!?Ruby初心者向けのプログラミング問題を集めてみた(全10問)]
(https://blog.jnito.com/entry/2019/05/03/121235)
##問題
CodeIQに「カラオケマシン問題」を出題しました。みんなチャレンジしてね!より引用。
みなさんには、「かえるのうた」を自由自在にキーチェンジするプログラムを作成してもらいます。
かえるのうたのメロディは以下のような文字列で表現されます。
"C D E F |E D C |E F G A |G F E |C C |C C |CCDDEEFF|E D C "
縦棒( | )は小節の区切りです。
半角スペースは休符です。
音符と休符が8つ集まると1小節になります。
このメロディ(文字列)を変更するKaraokeMachineというクラスを作ります。
このクラスはインスタンス作成時にメロディを受け取ります。
transposeというメソッドに変化させたいキーの量を渡すと、その分だけキーを上げたり下げたりしたメロディが返却されます。
コード
class KaraokeMachine
def initialize(melody)
@melody = melody
end
def transpose(amount)
melody_line = %w(C C# D D# E F F# G G# A A# B)
changed_melody = ""
calc_amount = amount % -12
@melody.each_char do |m|
if m =~ / |\|/
changed_melody = changed_melody + m
else
new_key = melody_line.index(m) + calc_amount
changed_melody = changed_melody + melody_line[new_key]
end
end
return changed_melody
end
end
melody = "C D E F |E D C |E F G A |G F E |C C |C C |CCDDEEFF|E D C "
karaoke = KaraokeMachine.new(melody)
方針
音階は全部で12種類あります。そこで、音の配列を用意してやり、1音ずつ変換させていけば、目的が達成できそうです。変換については、当初12で割ったあまりを利用する予定でしたが、問題が発生したので-12で割ったあまりを利用することで問題を解決しました。
##解説
まずは音階を用意します。
melody_line = %w(C C# D D# E F F# G G# A A# B)
例えばドの音はCと表されますが、Cはこの配列のインデックスの0にあたります。
音を変換する際に、インデックスの値を利用するためにそれぞれの音に対して
index
メソッドを利用しました。
今回用意した配列のインデックスは-11~11の値を取りうることができます。当初は12で割った余をindex
メソッドを使った後の値に足していたのですが、これだと用意した配列のインデックスの取りうる値の範囲から逸脱することがある問題が発生しました。そこで-12で割った余を利用することでこの問題を回避しています。
あとは、melodyに出てくる音以外の文字列の処理です。
これには" "と"|"が含まれます。これらはそのまま表示させたいので、
m =~ / |\|/ #" "または"|"にマッチする正規表現
が含まれる際はそのままとしました。
##参考にしたサイト
Array#find_index (Ruby 3.0.0 リファレンスマニュアル)
String#each_char (Ruby 3.0.0 リファレンスマニュアル)