アラビア数字をローマ数字へ
入力された4000未満のアラビア数字をローマ数字へ変換して出力させるプログラムを書こう!
対応
アラビア数字 | ローマ数字 |
---|---|
1 | I |
2 | II |
3 | III |
4 | IV |
5 | V |
6 | VI |
7 | VII |
8 | VIII |
9 | IX |
10 | X |
11 | XI |
14 | XIV |
15 | XV |
19 | XIX |
38 | XXXVIII |
40 | XL |
50 | L |
51 | LI |
90 | XC |
97 | XCVII |
439 | CDXXXIX |
483 | CDLXXXIII |
499 | CDXCIX |
732 | DCCXXXII |
999 | CMXCIX |
1999 | MCMXCIX |
無駄に長々と書きましたが、規則性は見つかりましたか?
規則性への考察
いきなりプログラミング書けるのは天才だけだと思います。僕は凡人なので日本語とかでいちいち書かないと無理です。
1999は、$ 1000+900+90+9 $に分けられます。つまり$ M + CM + XC + IX $この考えでいくと4000未満で考えることを念頭に置くと数字は最大で四桁を分けて考える。ってことは割るのでは…?
という考えかたは@evendemiaireさんがやってくれています。
僕はえげつないほど直感的で子供っぽい解き方をします。書いた本人も頭いい解き方と思ってません
一度完成させていますが、もう少しスマートな書き方がわかればそちらを追記できればなと思ってます。
規則性の考察とかいいながら全く規則性なんて考えていません
1ならI,2ならIIという完璧な一対一対応で行っていきます.それをするにあたって必要な知識を書いていきます。
私の解き方の解説
例えば1234を想定していきます.ローマ数字で表すと"MCCXXXIV"になります。
1000と200と30と4に分けます。というより配列を考えます.
numという配列を作ります。この場合num[0]=1,num[1]=2,num[2]=3,num[3]=4です。では、数字を4000未満の整数に想定して、このような配列の例をとりあえず示します
num = gets
num.chars.map(&:to_i)
puts num[0]
puts num[2]
実行結果が
1234 #ここは入力
1
3
となるはずです2行目がnumを配列にできるものになります。しかしこの場合0001などと入力しないとputs num[0]が1になっていまいます、1を入力しているのに。なので1を入力して0001,13を入力して0013などとなるようにしよう
num = gets
num ="%04d" % num
num.chars.map(&:to_i)
puts num[0]
puts num[2]
2行目を追加することで上記が可能になります。
ということで千の位、百の位、十の位、一の位に数字を分けてそれぞれを比較してその数字に対応したローマ数字をローカル変数に代入するというものを作る
てなわけで完成品がこちらです.
num = gets
if num.to_i >= 4000
puts "4000未満を入力してください"
exit
end
num = "%04d" % num
num.chars.map(&:to_i)
case num[0].to_i
when 1 then
word1 = "M"
when 2 then
word1 ="MM"
when 3 then
word1 = "MMM"
end
case num[1].to_i
when 1 then
word2 = "C"
when 2 then
word2 = "CC"
when 3 then
word2 = "CCC"
when 4 then
word2 = "CD"
when 5 then
word2 = "D"
when 6 then
word2 = "DC"
when 7 then
word2 = "DCC"
when 8 then
word2 = "DCCC"
when 9 then
word2 = "CM"
end
case num[2].to_i
when 1 then
word3 = "X"
when 2 then
word3 = "XX"
when 3 then
word3 = "XXX"
when 4 then
word3 = "XL"
when 5 then
word3 = "L"
when 6 then
word3 = "LX"
when 7 then
word3 = "LXX"
when 8 then
word3 = "LXXX"
when 9 then
word3 = "XC"
end
case num[3].to_i
when 1 then
word4 = "I"
when 2 then
word4 = "II"
when 3 then
word4 = "III"
when 4 then
word4 = "IV"
when 5 then
word4 = "V"
when 6 then
word4 = "VI"
when 7 then
word4 = "VII"
when 8 then
word4 = "VIII"
when 9 then
word4 = "IX"
end
words = "#{word1}" + "#{word2}" + "#{word3}" + "#{word4}"
puts "#{words}"
最初の"num"の入力の時点で4000以上の場合を排除しています。
最後の2行で各ローカル変数を連結しています。
力技感しかありませんがこれもこれでというところです.
改訂-1版
用いるローマ数字を配列に入れてみる
require 'colorize'
num = gets
if num.to_i >= 4000
puts "4000未満を入力してください"
exit
end
num = "%04d" % num
num.chars.map(&:to_i)
ronum = ["I" ,"V", "X", "L", "C", "D", "M"]
case num[0].to_i
when 1,2,3 then
word1 ="#{ronum[6] * num[0].to_i}"
end
case num[1].to_i
when 1,2,3 then
word2 = "#{ronum[4] * num[1].to_i}"
when 4 then
word2 = "CD"
when 5, 6, 7, 8 then
word2 = "#{ronum[5] + ronum[4] *(num[1].to_i-5)}"
when 9 then
word2 = "CM"
end
case num[2].to_i
when 1,2,3 then
word3 = "#{ronum[2] * num[2].to_i}"
when 4 then
word3 = "XL"
when 5, 6, 7, 8 then
word3 = "#{ronum[3] + ronum[2] *(num[2].to_i - 5)}"
when 9 then
word3 = "XC"
end
case num[3].to_i
when 1,2,3 then
word4 = "#{ronum[0] * num[3].to_i}"
when 4 then
word4 = "IV"
when 5, 6, 7, 8 then
word4 = "#{ronum[1] + ronum[0] *(num[3].to_i - 5)}"
when 9 then
word4 = "IX"
end
words = "#{word1}" + "#{word2}" + "#{word3}" + "#{word4}"
puts "#{words}"
少しだけ短くなった。
メソッドとして外に出してif文使ってそれぞれの数字に対してうまいこと数字考えてcase文を一回だけ表記するようにできたら短くできると思うが…改訂-2版に期待
参考文献
- source ~/my_ruby/grad_members_20f/members/majesty99/for_post/ronum2.org