数当てゲームの練習2（Hit&Blow）

#問題
>
これはｎ桁の数を探すゲームです。
適当な数を入れると桁も数字もあっていれば「Hit」としその個数が、
数字はあっているが桁が異なっていれば「Blow」としてその個数が出力されます。
それを繰り返すことで答えを探すことができます。
このゲームを作成しなさい。
答えの数は乱数を使って毎回別の答えを用意しましょう。

※[こちらのサイト](http://vipprog.net/wiki/exercise.html)から引用

#解答
```ruby:hit_blow.rb
# 桁数を設定（問題の仕様上、最大は10桁）
# 今回は例に従い4桁
DIGIT_NUMBER = 4

# 正解の数を乱数で生成するメソッド
# 正解の数は各桁の数字が異ならなければならない
# 返り値:生成されたn桁の乱数
def make_answer_number
  # 正解の数が生成できたか調べるフラグ
  answer_number_flag = false
  
  # 各桁の数が異なる数が生成されるまで無限ループ
  while !answer_number_flag
    # フラグは最初はtrue
    answer_number_flag = true
    
    # 正解の数を生成
    # 正解の数は10^(n-1)〜(10^n)-1の数
    rand_number = rand((10**(DIGIT_NUMBER - 1))..((10**DIGIT_NUMBER) - 1))
    
    # return用の変数
    return_answer_number = rand_number
    
    # 各桁の数を格納する配列
    rand_number_array = []
    
    # 各桁の数を配列に格納
    DIGIT_NUMBER.times do
      rand_number_array.push(rand_number % 10)
      rand_number /= 10
    end
    
    # 各桁の数が異なっているか調べる
    rand_number_array.each_with_index do |digit_number, index|
      (index + 1).upto(rand_number_array.length - 1) do |upto_times|
        if digit_number == rand_number_array[upto_times]
          answer_number_flag = false
        end
      end
    end
  end
  
  return_answer_number
end

# ゲーム説明を表示するメソッド
def show_rule
  puts "数当てゲームを行います"
  puts "これは#{DIGIT_NUMBER}桁の数を探すゲームです"
  puts "適当な数を入れると桁も数字もあっていれば「hit」としその個数が、"
  puts "数字はあっているが桁が異なっていれば「blow」としてその個数が出力されます"
  puts "それを繰り返すことで答えを探すことができます"
  puts "それではゲームを開始します"
end

# 入力された整数が設定した桁数と等しいか判断するメソッド
# n桁の整数の場合、10^(n-1)〜(10^n)-1の範囲に存在していればよい
# input_number:入力された整数
def input_number_judge(input_number)
  # 正しかったらtrueを、間違っていたらfalseを返す
  if input_number < 10**(DIGIT_NUMBER) && input_number >= 10**(DIGIT_NUMBER - 1)
    true
  else
    puts "入力された数は#{DIGIT_NUMBER}桁ではありません"
    puts "もう一度入力してください"
    false
  end
end

# n桁の整数の各桁の数を順に取り出していくメソッド
# 返り値は要素数nの配列
# number:n桁の整数
def number_to_array(number)
  number_array = []
  DIGIT_NUMBER.times do
    # 桁数の数だけ10で割った余りを配列に追加
    number_array.push(number % 10)
    # より上位の桁を求めるため10で割る
    number /= 10
  end
  
  # 下位の桁から順に入っているため配列を反転してreturn
  number_array.reverse
end

# 正解の数と入力された数を比較するメソッド
# input_number:入力された数
# set_number:正解の数
def input_answer_judge(input_number, set_number)
  # hitとblowの数を数えるための変数
  hit_time  = 0
  blow_time = 0
  
  # 入力された数を配列として取り出し
  input_number_array = number_to_array(input_number)
  # 正解の数を配列として取り出し
  set_number_array   = number_to_array(set_number)
  
  # 正解の数と入力された数の比較
  input_number_array.each_with_index do |current_input_number, input_index|
    # hitかどうか判定
    if current_input_number == set_number_array[input_index]
      hit_time += 1
      # hitしたら次の桁へ
      next
    # hitじゃなかったらblowかどうか判定
    else
      # 正解データと1つずつ比較
      set_number_array.each_with_index do |current_set_number, set_index|
        # 同じ桁は上でhitしていないので異なることは自明なので飛ばす
        next if input_index == set_index
        if current_set_number == current_input_number
          blow_time += 1
          # blowだったらループから抜ける
          break
        end
      end
    end
  end
  
  puts "#{hit_time}hit, #{blow_time}blow"
  
  # hit数が桁数と同じだったら正解と完全一致だからtrueを返す
  # 一致しなかったらfalseを返す
  if hit_time == DIGIT_NUMBER
    true
  else
    false
  end
end

#=========================================================
#                   ここからゲーム開始
#=========================================================

# 正解の数を生成
answer_number = make_answer_number

# ゲーム説明を表示
show_rule

# 正解かどうか判定するフラグ
answer_flag = false

# 不正解の間はずっとループ
while !answer_flag
  print "#{DIGIT_NUMBER}桁の数を入力してください : "
  # 数を入力
  anticipated_number = gets.to_i
  
  # 入力された数の桁数が正しいか判定
  # 正しくなかったらもう一度入力
  redo unless input_number_judge(anticipated_number)
  
  # 入力された数を正解の数と比較する
  answer_flag = input_answer_judge(anticipated_number, answer_number)
end

puts "正解です！"
```

#結果
```
数当てゲームを行います
これは4桁の数を探すゲームです
適当な数を入れると桁も数字もあっていれば「hit」としその個数が、
数字はあっているが桁が異なっていれば「blow」としてその個数が出力されます
それを繰り返すことで答えを探すことができます
それではゲームを開始します
4桁の数を入力してください : 999
入力された数は4桁ではありません
もう一度入力してください
4桁の数を入力してください : 10000
入力された数は4桁ではありません
もう一度入力してください
4桁の数を入力してください : 1359
0hit, 0blow
4桁の数を入力してください : 1627
1hit, 1blow
4桁の数を入力してください : 2615
2hit, 0blow
4桁の数を入力してください : 2604
2hit, 2blow
4桁の数を入力してください : 2640
4hit, 0blow
正解です！
```

#参考
>
* [複数桁10進数の*桁目だけを抽出したい 【OKWave】](http://okwave.jp/qa/q2747962.html)
* [配列内の要素を逆順に並び替える - 配列(Array)クラス - Ruby入門](http://www.rubylife.jp/ini/array_class/index13.html)
* [each_with_index (Enumerable) - Rubyリファレンス](http://ref.xaio.jp/ruby/classes/enumerable/each_with_index)