Hit&Blow を Ruby で

qiita.comおもしろそうなので、自分でも書いてみた。
 

ルール

コンピュータの決めた、各桁に重複のない3桁の数を当てるゲーム。
当たらなかった場合、

  • 入力と桁の合っている数字の数を、ヒット
  • 入力と桁は合っていないが重複はしている数字の数を、ブロウ

として教えてくる。
 

実行例

各桁のそれぞれちがう、3桁の数を入力して下さい(例:012): 135
ヒット:1, ブロウ:0
各桁のそれぞれちがう、3桁の数を入力して下さい(例:012): 315
ヒット:0, ブロウ:1
各桁のそれぞれちがう、3桁の数を入力して下さい(例:012): 351
ヒット:0, ブロウ:1
各桁のそれぞれちがう、3桁の数を入力して下さい(例:012): 124
ヒット:1, ブロウ:0
各桁のそれぞれちがう、3桁の数を入力して下さい(例:012): 106
ヒット:1, ブロウ:1
各桁のそれぞれちがう、3桁の数を入力して下さい(例:012): 160
ヒット:2, ブロウ:0
各桁のそれぞれちがう、3桁の数を入力して下さい(例:012): 170
ヒット:2, ブロウ:0
各桁のそれぞれちがう、3桁の数を入力して下さい(例:012): 180
ヒット:2, ブロウ:0
各桁のそれぞれちがう、3桁の数を入力して下さい(例:012): 190
正解です! 9回で当てました!

 

コード

hit_and_blow.rb

module Hit_and_Blow
  module_function
  
  N = 3
  
  def input
    expl = (0...N).to_a.join
    loop do
      print "各桁のそれぞれちがう、#{N}桁の数を入力して下さい(例:#{expl}): "
      s = gets.chomp.chars
      if s.size != N || s.uniq.size != N || s.any?(/\D/)
        puts "不正な入力です。"
      else
        return s
      end
    end
  end
  
  def judge(target, number)
    overlap = (target & number).size
    hit = target.zip(number).count { |a, b| a == b }
    [hit, overlap - hit]
  end
  
  def play
    target = [*"0".."9"].sample(N)
    (1..).each do |n|
      number = input
      
      if target == number
        puts "正解です! #{n}回で当てました!"
        break
      else
        hit, blow = judge(target, number)
        puts "ヒット:#{hit}, ブロウ:#{blow}"
      end
    end
  end
end

Hit_and_Blow.play

N = 3だと簡単ですが、N = 4にすると結構手ごわいです。