クレジットカードのチェックディジットをrubyで作る

#初めに
クレジットカードはルーンアルゴリズムというもので出来ているそうです。

今回はrubyでこのアルゴリズムを作ってみたので、みなさんに見ていただこうと思いました。

イケてない書き方や、無駄な書き方があればおしえていただけると大変勉強になります。
#ルーンアルゴリズムとは

クレジットカードの奇数桁の総和と、偶数桁値を二倍した値の総和を足すと必ず10で割り切れるというものです。

精密には、偶数桁が2倍して2桁(5,6,7,8,9)になるものは、1桁目と2桁目の数字を足したものを偶数桁の総和へ足します。

この仕組を利用することで、クレジットカード番号の打ち間違えを防いでいるそうです。

```rb

#正しいクレジットカードの番号
8460877291285697

8 6 8 7 9 2 5 9 |7+3+7+5+9+4+1+9|=17+19+9=28+17=45

 4 0 7 2 1 8 6 7|13+15+7|=35

(35 + 45) % 10 == 0
#Trueを返す

```


#プログラム

16番目の数字は1-15番目のランダムな数字から決まるので、**846087729128569Y**となります。

今回Y(16番目)に入る数字を探すプログラムを書きました。


```check_digit.rb

# 何個のクレジットカードを作るか、この入力値で決める。
# ループの回数を標準入力から取得。変数はintegerに変える
count = gets.chomp.to_i
odd = 0
even = 0
count.times do
  # digitにはまだstringの数字が入っている
  digit = gets.chomp.split('')
  # クレジットカードは16桁
  16.times do |i|

    correct_count = i+1
    
    if correct_count.even?
      # iが15番目(16桁目)で、値がXの場合は処理を行わない
      # 数字にして、足す
      if correct_count == 16
        10.times do |r|
           if (odd+even+r) % 10 == 0
             puts "答えは:#{r}"
             break
           end
        end
        break
      end
      digit[i] = digit[i].to_i
      even += digit[i]
  elsif correct_count.odd?
      # 最初にintにして、数を二倍にする。
      digit[i] = digit[i].to_i * 2
      # 文字列に変換して、桁が2桁になる場合は、10の位と1の位を足す
      if digit[i].to_s.length == 2
        # 文字列にする
        digit[i] = digit[i].to_s
        digit[i] = digit[i].split('')
        # 1の位と10のくらいを足す計算
          a = digit[i][0].to_i
          b = digit[i][1].to_i
        # evenに足す
        even = even + a + b
      else
        # 二倍にしても、1桁の場合
        # integerにして、evenに足す
        digit[i] = digit[i].to_i
        even += digit[i]
      end
    end
    # 0-14番目(1-15番目)までの数字は計算し終わっているので
  end
  odd = 0
  even = 0
end

```

```ターミナル.rb
#ループ回数
1
#16桁の数字と文字
846087729128569Y

答えは:7

```

## P.S. @scivolaさんにコメントいただいた方法でコードを編集してみました！

```rb
count = gets.to_i
odd = 0
even = 0
count.times do
  digits = gets.chars.map(&:to_i)
  16.times do |i|
    correct_count = i+1
    if correct_count.even?
      if correct_count == 16
        10.times do |r|
           if (odd+even+r) % 10 == 0
             puts r
             break
           end
        end
      end
      even += digits[i]
    elsif correct_count.odd?
      odd_number = digits[i]* 2
      if 10 <= odd_number
        odd_number = odd_number.divmod(10).sum
        odd += odd_number
      else
        odd += odd_number
      end
    end
  end
  # ループごとに初期化
  odd = 0
  even = 0
end
```

mapの引数がわからなかったので、この記事を参考にしました！
@kenzan100さん【[Rubyの array.map(&:to_s) 記法を紐解く](https://qiita.com/kenzan100/items/6344766167299b9f7e91)】
リスト内の要素を順に呼んで、型を変えてくれるんですね！

52行から31行に減りました！毎度行っていたintegerへの変更ともおさらばです！！

#またコードが短くなった！！

```rb
count = gets.to_i
count.times do
  odd = 0
  even = 0
  digits = gets.chars.map(&:to_i)
  digits.each.with_index(1) do |digit, correct_count|
    if correct_count.even?
      if correct_count == 16
        10.times do |r|
           if (odd+even+r) % 10 == 0
             puts r
             break
           end
        end
      end
      even += digits[digit]
    else
      odd_number = digits[digit]* 2
        odd_number = odd_number.divmod(10).sum if 10 <= odd_number
        odd += odd_number unless 10 <= odd_number
    end
  end
end
```

32行→23行になりました！こんなに綺麗にかけるとは思っていませんでした😅


`digits.each.with_index(1) do |digit, correct_count|`

調べてみたのですが、この行はmapでもかけるそうです！

`digits.map.with_index(1) do |digit, correct_count|`

with_index便利すぎます！

参考@awakiaさん:【[with_indexが便利だという話とstable_sort_by](https://qiita.com/awakia/items/d417c735b869a4db5abc)】

#最後に

やっぱりプログラミングは面白いです！！

次はpythonでもっと短く書いてみようと思います！

最後まで見てくださり、ありがとうございました(^^)