Last active
December 11, 2015 08:08
-
-
Save ngsw-taro/4570923 to your computer and use it in GitHub Desktop.
Rubyの学習のため、ヒット&ブローを作ってみた。
Rubyよくわからないので、指摘しまくってください。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ヒット&ブローを表すクラス。 | |
# このクラスのオブジェクトはイミュータブル。 | |
class HitAndBlow | |
NUMBERS_LENGTH = 4 | |
NUMBER_RANGE = (1..9) | |
# 指定された配列が、正解の数の形式として妥当か判定する。 | |
# 数の重複がなく、所定の範囲ないの値を持ち、長さがNUMBERS_LENGTHの配列ならばtrueを、それ以外ならfalseを返す。 | |
def self.valid_numbers? submitted_numbers | |
submitted_numbers.uniq.size == NUMBERS_LENGTH && | |
submitted_numbers.all? do |i| | |
NUMBER_RANGE === i | |
end | |
end | |
# 引数に指定された配列を、正解の数とする。 | |
# 引数が省略された場合、ランダムな数を設定する。 | |
# 正解の数として妥当でない値が指定された場合、ArgumentErrorを起こす。 | |
def initialize(numbers = NUMBER_RANGE.to_a.shuffle.shuffle.take(NUMBERS_LENGTH)) | |
raise ArgumentError if not HitAndBlow.valid_numbers? numbers | |
@numbers = numbers | |
@count = 0 | |
end | |
# 回答の試行回数を表す | |
attr_reader :count | |
# 正解の数を表す | |
def numbers | |
@numbers.dup | |
end | |
# 回答をする。 | |
# 引数に指定した配列と、正解の数を比較し、ヒントとして | |
# ヒット数とブロー数をハッシュで返す。 | |
# ヒット数のキーは :hit, ブロー数のキーは :blow である。 | |
# 回答として指定された配列の形式が妥当でない場合、ArgumentErrorを起こす。 | |
def submit(submitted_numbers) | |
raise ArgumentError if not HitAndBlow.valid_numbers? submitted_numbers | |
@count += 1 | |
hit = count_hit submitted_numbers | |
blow = count_blow submitted_numbers | |
{:hit => hit, :blow => blow} | |
end | |
private | |
# 指定された配列について、ヒット数を返す。 | |
def count_hit(submitted_numbers) | |
submitted_numbers.zip(@numbers).select do |num1, num2| | |
num1 == num2 | |
end.count | |
end | |
# 指定された配列について、ブロー数を返す。 | |
def count_blow(submitted_numbers) | |
(submitted_numbers & @numbers).count - count_hit(submitted_numbers) | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "../src/hit_and_blow" | |
require "rspec" | |
describe HitAndBlow do | |
describe "初期化する場合" do | |
it "4桁以外の配列を引数に渡すと例外を投げること" do | |
proc do | |
HitAndBlow.new [1, 2, 3] | |
end.should raise_error(ArgumentError) | |
proc do | |
HitAndBlow.new [1, 2, 3, 4, 5] | |
end.should raise_error(ArgumentError) | |
end | |
it "重複する数が含まれる配列を引数に渡すと例外を投げること" do | |
proc do | |
HitAndBlow.new [1, 1, 2, 3] | |
end.should raise_error(ArgumentError) | |
proc do | |
HitAndBlow.new [9, 8, 7, 9] | |
end.should raise_error(ArgumentError) | |
end | |
it "範囲外の数を含む配列を引数に渡すと例外を投げること" do | |
proc do | |
HitAndBlow.new [0, 1, 2, 3] | |
end.should raise_error(ArgumentError) | |
proc do | |
HitAndBlow.new [7, 8, 9, 10] | |
end.should raise_error(ArgumentError) | |
end | |
it "引数に渡した配列が正解の数となること" do | |
HitAndBlow.new([3, 2, 5, 6]).numbers.should == [3, 2, 5, 6] | |
end | |
it "newに引数を指定しなくても_妥当な正解の数が設定されること" do | |
HitAndBlow.new.numbers.uniq.should have(4).item | |
end | |
end | |
describe "正しく初期化された場合" do | |
# スコープを絞るため | |
hab = nil | |
before do | |
hab = HitAndBlow.new [1, 2, 3, 4] | |
end | |
it "正解の数は変更不可であること" do | |
hab.numbers[0] = 9 | |
hab.numbers[0].should == 1 | |
end | |
it "直後の回答回数は0回であること" do | |
hab.count.should == 0 | |
end | |
end | |
describe "回答する場合" do | |
hab = HitAndBlow.new | |
it "4桁以外の配列で回答すると例外を投げること" do | |
proc do | |
hab.submit [1, 2, 3] | |
end.should raise_error ArgumentError | |
proc do | |
hab.submit [1, 2, 3, 4, 5] | |
end.should raise_error ArgumentError | |
end | |
it "重複する数が含まれる配列で回答すると例外を投げること" do | |
proc do | |
hab.submit [6, 4, 2, 4] | |
end.should raise_error ArgumentError | |
proc do | |
hab.submit [1, 9, 1, 1] | |
end.should raise_error ArgumentError | |
end | |
it "指定外の範囲を含む配列で回答すると例外を投げること" do | |
proc do | |
hab.submit [0, 1, 2, 3] | |
end.should raise_error ArgumentError | |
proc do | |
hab.submit [7, 8, 9, 10] | |
end.should raise_error ArgumentError | |
end | |
it "4桁の重複しない、所定の範囲内の値をもった配列で回答するとヒントを返すこと" do | |
hab.submit([1, 2, 3, 4]).should be_an_instance_of Hash | |
end | |
end | |
describe "正しく回答した場合" do | |
it "ヒントとして正しいヒット数を返すこと" do | |
hab = HitAndBlow.new [1, 2, 3, 4] | |
hab.submit([4, 3, 2, 1])[:hit].should == 0 | |
hab.submit([9, 8, 7, 6])[:hit].should == 0 | |
hab.submit([1, 8, 5, 7])[:hit].should == 1 | |
hab.submit([6, 2, 3, 5])[:hit].should == 2 | |
hab.submit([9, 2, 3, 4])[:hit].should == 3 | |
hab.submit([1, 2, 3, 4])[:hit].should == 4 | |
end | |
it "ヒントとして正しいブロー数を返すこと" do | |
hab = HitAndBlow.new [1, 2, 3, 4] | |
hab.submit([4, 3, 2, 1])[:blow].should == 4 | |
hab.submit([9, 8, 7, 6])[:blow].should == 0 | |
hab.submit([1, 8, 5, 7])[:blow].should == 0 | |
hab.submit([6, 2, 3, 5])[:blow].should == 0 | |
hab.submit([9, 2, 3, 4])[:blow].should == 0 | |
hab.submit([1, 2, 3, 4])[:blow].should == 0 | |
hab.submit([2, 3, 4, 5])[:blow].should == 3 | |
hab.submit([3, 8, 6, 9])[:blow].should == 1 | |
end | |
it "正しい回答回数を取得できること" do | |
hab = HitAndBlow.new | |
hab.submit [1, 2, 3, 4] | |
hab.count.should == 1 | |
hab.submit [1, 2, 3, 4] | |
hab.count.should == 2 | |
hab.submit [1, 2, 3, 4] | |
hab.count.should == 3 | |
end | |
end | |
describe "クラスメソッド valid_number?" do | |
it "4桁以外の配列はinvalidであること" do | |
HitAndBlow.valid_numbers?([1, 2, 3]).should be_false | |
HitAndBlow.valid_numbers?([1, 2, 3, 4, 5]).should be_false | |
end | |
it "重複する数が含まれる配列はinvalidであること" do | |
HitAndBlow.valid_numbers?([6, 4, 2, 4]).should be_false | |
HitAndBlow.valid_numbers?([1, 9, 1, 1]).should be_false | |
end | |
it "指定外の範囲を含む配列はinvalidであること" do | |
HitAndBlow.valid_numbers?([0, 1, 2, 3]).should be_false | |
HitAndBlow.valid_numbers?([7, 8, 9, 10]).should be_false | |
end | |
it "4桁の重複しない、所定の範囲内の値をもった配列はvalidであること" do | |
HitAndBlow.valid_numbers?([1, 2, 3, 4]).should be_true | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ヒット&ブローをCUIで遊べるプログラム | |
require "hit_and_blow" | |
def get_count(count) | |
case count | |
when 1 then "once" | |
when 2 then "twice" | |
else "#{count} times" | |
end | |
end | |
HIT_AND_BLOW = HitAndBlow.new | |
loop do | |
print "> " | |
answer = STDIN.gets.strip.split(//).map do |c| | |
c.to_i | |
end | |
if not HitAndBlow.valid_numbers? answer | |
puts "Please input 4 digit number. It should not contain 0." | |
redo | |
end | |
hint = HIT_AND_BLOW.submit answer | |
if hint[:hit] == 4 | |
puts "Congratulations!! That is correct!" | |
puts "You answered #{get_count HIT_AND_BLOW.count}." | |
break | |
end | |
puts "HIT: #{hint[:hit]}, BLOW: #{hint[:blow]}" | |
end |
気になったところが同じだったので、細かすぎるところを…
def HitAndBlow.valid_numbers?
は
def self.valid_numbers?
って書きますね。自分のばやい。
あと、case と when のインデント位置は揃えるのが一般的な気がします。
そういう自分は、ブロック引数の書き方が一般的じゃないです。
L47とか
before {@hab = HitAndBlow.new [1, 2, 3, 4]}
とか?
まず無いだろうけど L54 の前に別のテストとかで hab.submit ... って呼ぶとあわわわ
以下こんな書き方あるとか
HitAndBlow.new.numbers.uniq.should have(4).items // L43
hab.submit([1, 2, 3, 4]).should be_an_instance_of(Hash) // L93
自分も正直そんな詳しくないので、「こう書け!!」とはいえないけどw
ありがとうございます!
アドバイス通りに修正してみました!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
eachの中でeachをあまりしたくないので、俺ならこう書くかな〜
あと好みで…w