🍒Rubyプログラミング問題にチャレンジ！ －改訂版・チェリー本発売記念－🎸

# PRへのリンク
https://github.com/JunichiIto/tenji-maker-challenge/pull/26

# ロジック
## 処理の流れ
大まかな流れは
1. テキストを１文字に分解
2. 文字を0,1で構成された配列に変換する
3. 配列で表された文字を出力しやすいように整形して出力する

となります💡

## 文字を配列に変換する

### 文字をバイナリを要素とした配列で表現する

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053396/25cb3316-dee1-b0cd-d950-2f412ed1ced7.png)

今回のチャレンジに出てくるひらがなは６箇所に●またはーを入れることで表現することができるので、長さ6の配列を使えば表現できそうです。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053396/aad70ca5-5884-8b44-3da7-249df188a682.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053396/487c60bf-9e7b-5fa3-88c1-975ccd399cdd.png)
また「カ行」や「サ行」を見るとわかる通り、「ア行」の①、②、④の部分を残して●を加えて変化させているという規則性が見られます。ここで「加える」ということに注目すると、●とーを1,0で表現し加算することで多くのひらがなを表現できそうです💡
なので、要素は1または0であり長さ6の配列を使って点字を表すことにします。
（例：「あ」は`[1,0,0,0,0,0]`）

### 変換の方法

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053396/5d8b58f7-ef69-3e4f-70fa-f8f79ff2b9fa.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053396/2cbfb0b8-24ec-e684-2135-5a24e9f1546c.png)


上記のように

- 母音部分は①②④の点
- 子音部分は③⑤⑥の点

で規則的に表現することができます。（例外を除く）

そこで母音の配列、子音の配列を定数として定義し、配列をベクトル的に加算することで対象の文字を出すことができます。
例えば「し」を配列に変換したい場合、
母音部分のI`[1,1,0,0,0,0]`と子音部分のS`[0,0,0,0,1,1]`をベクトル的に加算して`[1,1,0,0,1,1]` とすることで変換が可能です。
なお、配列をそのまま加算してもベクトル的な加算はできないので工夫が必要です。

```ruby
# そのまま加算しても後ろに付け足されるだけ
[1,2,3] + [1,2,3]
=> [1, 2, 3, 1, 2, 3]

# ベクトル的に加算
[[1,2,3], [1,2,3]].transpose.map{|a| a.inject(:+) }
=> [2, 4, 6]
```

参考：[https://qiita.com/Kta-M/items/b54f12d3eb49520925e7#comment-e192ccc9e888a565ce4b](https://qiita.com/Kta-M/items/b54f12d3eb49520925e7#comment-e192ccc9e888a565ce4b)

変換部分の実装は以下となります💡

```lib/constants.rb
VOWELS = { A: [1, 0, 0, 0, 0, 0],
            I: [1, 1, 0, 0, 0, 0],
            U: [1, 0, 0, 1, 0, 0],
            E: [1, 1, 0, 1, 0, 0],
            O: [0, 1, 0, 1, 0, 0] }.freeze

CONSONANTS = { K: [0, 0, 0, 0, 0, 1],
               S: [0, 0, 0, 0, 1, 1],
               T: [0, 0, 1, 0, 1, 0],
               N: [0, 0, 1, 0, 0, 0],
               H: [0, 0, 1, 0, 0, 1],
               M: [0, 0, 1, 0, 1, 1],
               R: [0, 0, 0, 0, 1, 0] }.freeze

IRREGULARS = { YA: [0, 0, 1, 1, 0, 0],
               YU: [0, 0, 1, 1, 0, 1],
               YO: [0, 0, 1, 1, 1, 0],
               WA: [0, 0, 1, 0, 0, 0],
                N: [0, 0, 1, 0, 1, 1] }.freeze
```

```lib/tenji_maker.rb
# 引数は　'KA'などの文字
def letter_to_tenji_binary(letter)
    return IRREGULARS[letter.to_sym] if letter.match?(/W|Y|N$/)

    consonant = CONSONANTS[letter[0].to_sym] || Array.new(6, 0)
    vowel = VOWELS[letter[-1].to_sym]

    [consonant, vowel].transpose.map { |a| a.inject(&:+) }.to_a
  end
```

### バイナリの配列を点字として出力しやすいように整形する
```ruby
puts tenji_maker.to_tenji('A HI RU')
#=> o- o- oo
#   -- o- -o
#   -- oo --
```
チャレンジでは上記のような出力が求められています。


![untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053396/1e4dd36b-25a1-a2f5-091c-15d3241afe30.png)

文字ごとに①と④→改行→②と⑤→改行→③と⑥
と出力すれば、求められている結果を出力できます。
よってN文字を変換する場合は、長さ3の配列で、

- １番目にはそれぞれの文字の①と④の値の配列がN個
- ２番目にはそれぞれの文字の②と⑤の値の配列がN個
- ３番目にはそれぞれの文字の③と⑥の値の配列がN個

入る配列を作ることにしました。

実際のコードは以下となります。

```lib/tenji_maker.rb
# 引数にはには①〜⑥の順番で並んだ長さ6の配列が文字数分だけ入る
# 例）"A SA"の場合[[1, 0, 0, 0, 0, 0],[1, 0, 0, 0, 1, 1]]
def tenji_binaries_to_matrix(tenji_binaries)
    tenji_binaries.map { |letter|
      letter.each_slice(3).to_a.transpose
    }.transpose
end
```

## 出力部分

ここまできたらあとはそれぞれ1はo、0は-として変換し、出力すれば完成となります💡

```lib/tenji_maker.rb
# 点字の出力
def matrix_to_tenji(tenji_binaries_matrix)
  tenji_binaries_matrix.map do |binary_array|
    binary_array_to_tenji_line(binary_array)
  end.join("\n")
end

# 一行分の点字を出力する
# [0,1],[1,1] => '-o oo'
def binary_array_to_tenji_line(binary_array)
  binary_array.map { |bin|
    bin.inject('') { |result, b| result + binary_to_dot(b) }
  }.join(' ')
end

def binary_to_dot(binary)
  binary.zero? ? '-' : 'o'
end
```

# 工夫したところ

## YA・YU・YOの規則的な変化を不規則として扱った
![スクリーンショット 2021-12-20 19.06.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053396/a5662efb-8f34-3fd6-06d6-87ac6c628fde.png)
上記の通りYA・YU・YOも規則的な変化をしている部分もありますが、たった３文字の規則性のためにロジックを実装するよりも不規則な文字として扱った方が圧倒的に実装の工数が減りそうだったので不規則文字として扱わせていただきました。（良い方法が思いつかなかったという言い訳でもあります。）

## 定数を外部ファイルに持たせた📁
オープンクラスの機能を使い、定数を外部ファイルに持たせました

```lib/constants.rb
class TenjiMaker
  VOWELS = { A: [1, 0, 0, 0, 0, 0],
              I: [1, 1, 0, 0, 0, 0],
              U: [1, 0, 0, 1, 0, 0],
              E: [1, 1, 0, 1, 0, 0],
              O: [0, 1, 0, 1, 0, 0] }.freeze

  CONSONANTS = { K: [0, 0, 0, 0, 0, 1],
                 S: [0, 0, 0, 0, 1, 1],
                 T: [0, 0, 1, 0, 1, 0],
                 N: [0, 0, 1, 0, 0, 0],
                 H: [0, 0, 1, 0, 0, 1],
                 M: [0, 0, 1, 0, 1, 1],
                 R: [0, 0, 0, 0, 1, 0] }.freeze

  IRREGULARS = { YA: [0, 0, 1, 1, 0, 0],
                 YU: [0, 0, 1, 1, 0, 1],
                 YO: [0, 0, 1, 1, 1, 0],
                 WA: [0, 0, 1, 0, 0, 0],
                 N: [0, 0, 1, 0, 1, 1] }.freeze
end
```

```lib/tenji_maker.rb
require 'constants'

class TenjiMaker
.
.
```

# 伊藤さんへのメッセージ

Railsエンジニアとなって約３ヶ月が経ちますが、チェリー本には今でもお世話になっております🎉
`block`  の項目などは初見では難しい上に「これ何に使うんだろ？」といった感じでした。しかし実務に入り色々なコードに触れてから改めて読んでみるとすんなりと理解することができ、gemのソースコードを読む時や難しい本を読む時の基礎として非常に役に立っております。ありがとうございました🍒🎸

# 参考リンク
[全視情協:点字とは \- 点字のしくみ](http://www.naiiv.net/braille/?tenji-sikumi)