roman numerals



# お題

アラビア数字(arabic numerals)を受け取って，ローマ数字(roman numerals)を返すmethodを書きなさい[^pine]．


# ローマ数字で使われる文字

| arabic numerals | roman numerals |
|----------------:|:---------------|
| 1               | I              |
| 5               | V              |
| 10              | X              |
| 50              | L              |
| 100             | C              |
| 500             | D              |
| 1000            | M              |


# 例

| arabic numerals | roman numerals |
|----------------:|:---------------|
| 1               | I              |
| 2               | II             |
| 4               | IV             |
| 5               | V              |
| 6               | VI             |
| 9               | IX             |
| 10              | X              |
| 11              | XI             |
| 14              | XIV            |
| 15              | XV             |
| 19              | XIX            |
| 38              | XXXVIII        |
| 42              | XLII           |
| 49              | XLIX           |
| 51              | LI             |
| 97              | XCVII          |
| 99              | XCIX           |
| 439             | CDXXXIX        |
| 483             | CDLXXXIII      |
| 499             | CDXCIX         |
| 732             | DCCXXXII       |
| 961             | CMLXI          |
| 999             | CMXCIX         |
| 1999            |                |


# コード

```ruby
require 'colorize'
class Number
  def initialize(arabic_numeral)
    @arabic_numeral = arabic_numeral.to_i # string to int

    @num_thousands = @arabic_numeral / 1000 
    @num_hundreds = (@arabic_numeral - @num_thousands*1000) / 100
    @num_tens = (@arabic_numeral - @num_thousands*1000 - @num_hundreds*100) / 10
    @num_ones = @arabic_numeral % 10

    @roman_numeral = ""

  end

  def convert_roman
    if  @arabic_numeral > 3999 or @arabic_numeral == 0
      puts "arabic_numeral :: #{@arabic_numeral.to_s}"
      puts "can't convert".red
      exit 0
    end

    self.to_roman(@num_thousands, 6)
    self.to_roman(@num_hundreds, 4)
    self.to_roman(@num_tens, 2)
    self.to_roman(@num_ones, 0)

  end

  def to_roman(num, digit)
    element = ['I','V','X','L','C','D','M']

    case num 
    when 0..3 then
      @roman_numeral = @roman_numeral + element[digit] * num
    when 4 then
      @roman_numeral = @roman_numeral + element[digit] + element[digit+1]
    when 5..8 then
      @roman_numeral = @roman_numeral + element[digit+1] +  element[digit]*(num-5)
    when 9 then
      @roman_numeral = @roman_numeral + element[digit] + element[digit+2]
    end
  end

  def puts_numeral
    puts "arabic_numeral :: #{@arabic_numeral.to_s}"
    puts "roman_numeral :: #{@roman_numeral}".green
  end

end     

def gets_num
  num = ARGV[0]
  if num == nil
    puts "What\'s the number?".green
    num = gets.chomp
  end

  return num
end

num = gets_num
numeral = Number.new(num)
#numeral.initialize(num)
numeral.convert_roman
numeral.puts_numeral

```


# 解説


## 初期化の部分

```ruby
def initialize(arabic_numeral)
    @arabic_numeral = arabic_numeral.to_i # string to int

    @num_thousands = @arabic_numeral / 1000 
    @num_hundreds = (@arabic_numeral - @num_thousands*1000) / 100
    @num_tens = (@arabic_numeral - @num_thousands*1000 - @num_hundreds*100) / 10
    @num_ones = @arabic_numeral % 10

    @roman_numeral = ""

    end
```

まずは必要な変数の初期化です． 

-   "@"をつけないとクラス内で使えないので忘れないようにしましょう．
-   それぞれの桁の数値をわける関数もあるようですが中身がよくわからないので，計算で求めました．


## アラビア数字からローマ数字へ

```ruby
def to_roman(num, digit)
    element = ['I','V','X','L','C','D','M']

    case num 
    when 0..3 then
      @roman_numeral = @roman_numeral + element[digit] * num
    when 4 then
      @roman_numeral = @roman_numeral + element[digit] + element[digit+1]
    when 5..8 then
      @roman_numeral = @roman_numeral + element[digit+1] +  element[digit]*(num-5)
    when 9 then
      @roman_numeral = @roman_numeral + element[digit] + element[digit+2]
    end
    end
```

アラビア数字からローマ数字への変換の部分です．

-   digit で桁数を指定して，num を元に場合分けを行います．
-   roman\_numeral に文字を追加する形で実装してます．

一つの桁に対して3種類の文字を使う可能性があります．

-   例えば 1~9 の場合だと 'I','V','X' の3つ必要になります．
-   使う文字の組み合わせはコードのように 4 通りあるのでそれぞれ分けましょう
-   10 以上の数値の場合については各桁ごとに分けてつなげます


## 実際の変換部分

```ruby
def convert_roman
    if  @arabic_numeral > 3999 or @arabic_numeral == 0
      puts "arabic_numeral :: #{@arabic_numeral.to_s}"
      puts "can't convert".red
      exit 0
    end

    self.to_roman(@num_thousands, 6)
    self.to_roman(@num_hundreds, 4)
    self.to_roman(@num_tens, 2)
    self.to_roman(@num_ones, 0)

  end
```

アラビア数字からローマ数字へ実際に変換する部分です．

まず，今回の実装では 1 ~ 3999 の数値しか変換が行なえません．そのためそれ以外が入力されている場合はエラーがでるようにしました．

-   数字以外が入力された場合は0になるので今回の処理で弾けるようですね
-   せっかくなのでエラーといえば赤という感じで色もつけました．成功した場合は緑になります．


# 参照文献

[^pine]: "初めてのプログラミング", Chris Pine (著), 西山 伸 (翻訳),オライリー・ジャパン (2006/7/24).



------
 - **source** ~/Documents/my_ruby/grad_members_20f/members/toshi0707/c6_roman_numerals.org