この記事はRubyプログラミング問題にチャレンジ! -改訂版・チェリー本発売記念- Advent Calendar 2021 14日目の記事です。
バックエンドエンジニアをしておりますyukoonoと申します。
書いたコードを外部に公開したことがないので、力試しをしてみたいという動機で参加させていただきました。
よろしくお願いします。
プルリクエストのリンク、または自分が書いたコード
Github: 点字メーカーチャレンジ 12/14 #20 JunichiIto/tenji-maker-challenge
ロジックの解説
-
入力をひらがな一文字分ずつ分割する
例:
"KI RI N"
->"KI", "RI", "N"
このとき、"N"
または"NN"
が入力されていた場合は、「ん」を点字にした
"--\n-o\noo"
に直接変換し、次のひらがな一文字分の処理に移る。-
ひらがな一文字分のローマ字をさらに英字一文字に分割する
例:
"KI"
->"K", "I"
-
英字に
"Y"
,"W"
が含まれている場合、母音の位置を下に下げるフラグ (vowel_tenji_needs_shift_downward_flag
) を立てる -
英字を、母音・子音ごとにクラスで定義した点字対応表を用いて、それぞれ相当する点字に置き換える
例:
"K", "I"
->"--\n--\n-o", "o-\no-\n--"
-
母音の位置を下に下げるフラグがfalseであれば、5 に進む
-
フラグがtrueである場合、母音の o の位置を一段下げ、上に
"--"
を挿入する操作を行う例:
"A"
->"o-\n--\n--"
->"--\no-\n--"
-
一番下の段に o が移動するまで 4.1 の操作を繰り返す
-
-
母音と子音を組み合わせて一文字の点字にする
例:
"--\n--\n-o", "o-\no-\n--"
->"o-\no-\n-o"
-
-
得られた点字を横並びで表示できるよう、ひと続きの文字列に置き換える
例:
"o-\no-\n-o"
,"--\n-o\n--"
,"--\n-o\noo"\
->"o- -- --\no- -o --\n-- -o oo"
結果を出力すると、以下のように表示されます。
tenji = @tenji_maker.to_tenji('KI RI N')
assert_equal <<~TENJI.chomp, tenji
o- o- --
o- oo -o
-o -- oo
TENJI
コードのアピールポイント
一番のポイントは、音と点字の対応表を作成し、それを利用してテキストの変換を行なったことです。例えば、母音では以下です。
VOWELS = {
A: <<~A.chomp,
o-
--
--
A
I: <<~I.chomp,
o-
o-
--
I
U: <<~U.chomp,
oo
--
--
U
E: <<~E.chomp,
oo
o-
--
E
O: <<~O.chomp,
-o
o-
--
O
}
点字にしたときに、どの音がどのような形に対応するのかを視覚的に示したかったため、対応表を文字列で用意し、それを組み合わせたり、順番を入れ替えることでテキストの変換を進めました。コードを見る人に、処理するための材料を示すことが狙いです。
工夫したところ
- 母音を移動させる行について、母音を o が下の行に入るまでシフトさせる仕様にしたこと
1.4.1, 1.4.2の手順です。
この方法で、元々の変換対象ではなかった「を」について、変換できるようになりました。
実は、最初は「や・ゆ・わ」の変換はできていたのですが、母音由来の o が二段目にもある違いから「よ」の変換がうまくできず、試行していたら思いがけず「を」が変換できてしまった、という感じです。
自分で工夫した点なのか、と聞かれると微妙ですが、お題の範囲外の変換ができたので記しました。
- 「ん」について、
"N"
と"NN"
からの点字の変換ができるようにした
手順1に記述していますが、「ん」についてだけは、他の文字の変換処理と切り離して、"N"
または "NN"
の入力があれば変換する形式にしました。test.rb には "N"
から変換するケースのみが書かれていましたが、個人的によく "NN"
で入力することから、これも「ん」に変換したいというこだわりがありました。他の変換方法として、/N+ $/
が入力されていたら「ん」に変換したらどうか、とも考えましたが、"NNN"
も「ん」に変換されそうだったのでやめました。
苦労したところ
とにかく大変だったところは、変数の名付けです。
- 一文字分の点字
- ( ex:
"o-\n--\n--"
)
- ( ex:
- 点字が配列に複数入っている状態
- ( ex:
["o-\n--\n--", "o-\no-\noo"]
)
- ( ex:
- 点字の点と線を1文字ずつに分解したものが配列に入っている状態
- ( ex:
["o", "-", "\n", "-", "-", "\n", "-", "-"]
)
- ( ex:
- 点字の点と線を1文字ずつ取り出した状態
- ( ex:
"o"
,"-"
)
- ( ex:
などが処理の中で登場しました。
コードを書き始めた当初は、「これどうやって名付ければ状態伝わるの?」と、かなり困ることになりました。数日後に見返して理解できそうな表現か確かめる、図を描いて自分で状態遷移を整理するなどして、ようやくこれだ、と思う名付けができた、さあ Qiita に書こう!と書き始めたあとで、また違和感を覚えて書き直しました。ようやく自分の中では整理されて、わかりやすい表現になってきたのではないかと思っています。
おかげで、変数名を変えただけのコミットが積み上がってしまいましたが。苦笑
伊藤さんにメッセージ(もしあればw)
面白い企画を立ち上げて頂きありがとうございます。会社の方以外に自分のコードを見ていただく機会などなかなか無いので、怖くもありますが、わくわくもしています。
また、他の参加者の方のコードなどは見ていませんが、Qiitaのカレンダーからタイトルだけは見ています。読むのをとても楽しみにしています。