1
0

More than 3 years have passed since last update.

Roman Numerals

Last updated at Posted at 2020-12-18

アラビア数字をローマ数字へ

入力された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版に期待

参考文献

roman numerals

!ruby-2.5.5p157


  • source ~/my_ruby/grad_members_20f/members/majesty99/for_post/ronum2.org
1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0