🌟

カラオケマシン問題をやってみた

に公開

動機

Rubyのリハビリがてらにカラオケマシン問題をやってみました。

実装

lib/karaoke_machime.rb
# frozen_string_literal: true

class KaraokeMachine
  KEYBOARD_PATTERN = %w[C C# D D# E F F# G G# A A# B].freeze

  def initialize(melody)
    @melody = melody
  end

  def transpose(key)
    @melody.scan(/\|| |[ACDFG]#|[A-G]/).map do |pattern|
      if ['|', ' '].include?(pattern)
        pattern
      else
        KEYBOARD_PATTERN[(KEYBOARD_PATTERN.find_index(pattern) + key) % KEYBOARD_PATTERN.length]
      end
    end.join
  end
end
spec/karaoke_machime_spec.rb
# frozen_string_literal: true

RSpec.describe KaraokeMachine do
  let(:karaoke_machine) { described_class.new(melody) }

  describe '#transpose' do
    subject { karaoke_machine.transpose(key) }

    context '|を入力した場合' do
      let(:melody) { '|' }
      let(:key) { 1 }

      it { is_expected.to eq '|' }
    end

    context '半角スペースを入力した場合' do
      let(:melody) { ' ' }
      let(:key) { 1 }

      it { is_expected.to eq ' ' }
    end

    context '1キーを上げる場合' do
      let(:melody) { 'C#' }
      let(:key) { 1 }

      it { is_expected.to eq 'D' }
    end

    context '1キーを下げる場合' do
      let(:melody) { 'D' }
      let(:key) { -1 }

      it { is_expected.to eq 'C#' }
    end

    context '1オクターブを上げる場合' do
      let(:melody) { 'C#' }
      let(:key) { 12 }

      it { is_expected.to eq 'C#' }
    end

    context '1オクターブを下げる場合' do
      let(:melody) { 'C#' }
      let(:key) { -12 }

      it { is_expected.to eq 'C#' }
    end
  end
end

感想

地味ですがString#scanに対してmapしているところが実装の工夫ポイントです。

Discussion