📅  2021-12-07

点字メーカープログラム

🔖Ruby

Rubyプログラミング問題にチャレンジ! -改訂版・チェリー本発売記念-のカレンダー | Advent Calendar 2021- Qiita に参加しました。12/7の担当です。

週に一度AtCoder参加してRubyでプログラムを書く練習をしているんですが、難易度的にもボリューム的にもちょうど良さそうだったので参加してみました。

チェリー本やフィヨルドブートキャンプでお世話になっている伊藤さんの企画ということで少しでもお役に立てれば幸いです〜

🌵PR

点字メーカープログラム Advent Calendar 12/7 by obregonia1 · Pull Request #16 · JunichiIto/tenji-maker-challenge

🌵コードを書く前の段取り

今回のお題は「点字メーカープログラム」ということだったのでまずプログラムの仕様と点字の仕組みについて確認する必要がありました。

tenji_maker = TenjiMaker.new
puts tenji_maker.to_tenji('A HI RU')
#=> o- o- oo
#   -- o- -o
#   -- oo --

puts tenji_maker.to_tenji('KI RI N')
#=> o- o- --
#   o- oo -o
#   -o -- oo

あらかじめテストコードも作成されていてこのようなコードで動くプログラムを作成する必要があります。

image in the content

点字の仕組みもこのように母音と子音の点のパターンの組み合わせで表現することがわかりました。

今回の変換対象となる文字は「あいうえお、かきくけこ、(省略)、やゆよ、らりるれろ、わ、ん」のみでしたが、イレギュラーなパターンの文字は「や、ゆ、よ、わ、ん」の5文字だということもわかりました。

🌵ロジックの解説

まずどうやって実装していくか考え、受け取る文字列は空白区切りになっているので空白で区切ったあとそれぞれの文字を点で表現しました。

縦3点、横2点の点字をどう表現するか迷いましたがシンプルに左上から"Z"の向きに数えて変換することにしました。

あ 
o-
--
-- #=> 'o-----'
い
o-
o-
-- #=> 'o-o---'

🌞ローマ字を点字に変換

受け取ったローマ字を点に変換する際にハッシュを作っておいてそれを元に点字に変換しました。

# vowel: 母音
VOWELS = {
    A: 'o--',
    I: 'o-o',
    U: 'oo-',
    E: 'ooo',
    O: '-oo'
  }

# consonant: 子音
  CONSONANTS = {
    K: '--o',
    S: 'o-o',
    T: 'oo-',
    N: '-o-',
    H: '-oo',
    M: 'ooo',
    Y: '-o-',
    R: 'o--'
  }
# roman_charには'A', 'KA', 'SA'のようにローマ字一文字が入る
def to_tenji_each_char(roman_char)
  if roman_char.size == 1
    roman_char == 'N' ? '---ooo' : VOWELS[roman_char.to_sym] + '---'
  elsif roman_char.size == 2
    consonant, vowel = roman_char.chars
    if consonant == 'Y'
      CONSONANTS[:Y] +
        case vowel
        when 'A'
          '-o-'
        when 'U'
          '-oo'
        when 'O'
          'oo-'
        end
    elsif roman_char == 'WA'
      '----o-'
    else
      VOWELS[vowel.to_sym] + CONSONANTS[consonant.to_sym]
    end
  end
end

イレギュラーな「や、ゆ、よ、わ、ん」は愚直に条件分岐してしまったので入れ子になってしまい、少し読みにくくなってしまいました。

🌞変換した点字を上、中、下に分割する

点字を横一列で作っているので、点字として出力しやすいように上、中、下の3列に分割しました。

def split_three_row(one_line_tenji_array)
    top, middle, bottom = Array.new(3) { [] }
    push_to_row = ->(row, tenji, start_point) { row << tenji[start_point, 2] }
    one_line_tenji_array.each do |one_line_tenji|
      push_to_row.call(top, one_line_tenji, 0)
      push_to_row.call(middle, one_line_tenji, 2)
      push_to_row.call(bottom, one_line_tenji, 4)
    end
    return top, middle, bottom
  end

空配列を用意してそれぞれに点字を入れていく処理は push_to_row でLambdaで書いてみました。自分でプログラムを書くときにLambdaを使ったことがなかったので使いたかっただけです笑

あまりコードの短縮にはなってないですが少しだけ処理がわかりやすくなった気がする。。。

🌞点字として出力する

あとは文字毎にスペースを入れたものが返り値になればいいので Array#join とヒアドキュメントを使いました

def to_tenji(text)
  roman_chars = text.split(' ')
  one_line_tenji_array = roman_chars.map do |roman_char|
    to_tenji_each_char(roman_char)
  end

  top, middle, bottom = split_three_row(one_line_tenji_array)

  <<~TENJI.chomp
    #{top.join(' ')}
    #{middle.join(' ')}
    #{bottom.join(' ')}
  TENJI
end

🌵感想など

コードを書く前は「読みやすくてカッコいいコード書こう!」と思ってましたがやってみるとなかなかそうはいかないですね。まだまだ経験が浅いので色んなコードを書いて自分でも納得できるようなコードが書けるようになりたいです。

最初はとにかく動くコードを書いてみてどんどんリファクタリングしていったんですが、変数名などをわかりやすくして、他の人が読んでも処理の流れがわかりやすいように意識しました。

他に参加している方のコードも読んで勉強したいと思います!

タグ