#初めに
クレジットカードはルーンアルゴリズムというもので出来ているそうです。
今回はrubyでこのアルゴリズムを作ってみたので、みなさんに見ていただこうと思いました。
イケてない書き方や、無駄な書き方があればおしえていただけると大変勉強になります。
#ルーンアルゴリズムとは
クレジットカードの奇数桁の総和と、偶数桁値を二倍した値の総和を足すと必ず10で割り切れるというものです。
精密には、偶数桁が2倍して2桁(5,6,7,8,9)になるものは、1桁目と2桁目の数字を足したものを偶数桁の総和へ足します。
この仕組を利用することで、クレジットカード番号の打ち間違えを防いでいるそうです。
#正しいクレジットカードの番号
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番目)に入る数字を探すプログラムを書きました。
# 何個のクレジットカードを作るか、この入力値で決める。
# ループの回数を標準入力から取得。変数は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
#ループ回数
1
#16桁の数字と文字
846087729128569Y
答えは:7
P.S. @scivolaさんにコメントいただいた方法でコードを編集してみました!
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) 記法を紐解く】
リスト内の要素を順に呼んで、型を変えてくれるんですね!
52行から31行に減りました!毎度行っていたintegerへの変更ともおさらばです!!
#またコードが短くなった!!
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】
#最後に
やっぱりプログラミングは面白いです!!
次はpythonでもっと短く書いてみようと思います!
最後まで見てくださり、ありがとうございました(^^)