-
Notifications
You must be signed in to change notification settings - Fork 6
Codebreaker解いてみました #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 6 commits
7bc57d7
b8618a0
1b5bf1a
63e0ff8
d62bfa2
d365eea
47c3beb
a85fc9c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| source "https://rubygems.org" | ||
|
|
||
| gem "rspec" | ||
| gem "cucumber" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| GEM | ||
| remote: http://rubygems.org/ | ||
| specs: | ||
| builder (3.2.2) | ||
| cucumber (1.3.9) | ||
| builder (>= 2.1.2) | ||
| diff-lcs (>= 1.1.3) | ||
| gherkin (~> 2.12) | ||
| multi_json (>= 1.7.5, < 2.0) | ||
| multi_test (>= 0.0.2) | ||
| diff-lcs (1.2.4) | ||
| gherkin (2.12.2) | ||
| multi_json (~> 1.3) | ||
| multi_json (1.8.2) | ||
| multi_test (0.0.2) | ||
| rspec (2.14.1) | ||
| rspec-core (~> 2.14.0) | ||
| rspec-expectations (~> 2.14.0) | ||
| rspec-mocks (~> 2.14.0) | ||
| rspec-core (2.14.7) | ||
| rspec-expectations (2.14.4) | ||
| diff-lcs (>= 1.1.3, < 2.0) | ||
| rspec-mocks (2.14.4) | ||
|
|
||
| PLATFORMS | ||
| ruby | ||
|
|
||
| DEPENDENCIES | ||
| cucumber | ||
| rspec |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| module Codebreaker | ||
| class Game | ||
| def initialize(output) | ||
| @output = output | ||
| end | ||
|
|
||
| def start(secret) | ||
| @secret = secret.each_char.to_a | ||
| @output.puts "Welcome to Codebreaker!" | ||
| @output.puts "Enter guess: " | ||
| end | ||
|
|
||
| def guess(numbers) | ||
| @numbers = numbers.each_char.to_a | ||
| @hit_count = nil | ||
|
|
||
| '+' * hit_count + '-' * match_count | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hit_count の処理が2回実行されることになりますね。
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. メモイズすれば良さげです
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. メモイズって初めて聞きました。
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. メモイズするとgessメソッド中で初期化処理書かないといけない気がするので、
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 現状 readable ですしね。 '+' * (h = hit_count) + '-' * (total_count - h)
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. なるほど、文字列の上書きができればそんな感じのやり方でもうちょっとうまく書ける気がしてきました
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. こんな感じに書けばメソッド呼び出し1回ずつでいけそうです うーん、でもやっぱり読みにくいですね。。。
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ('+' * total_count).each_char.to_aは、↓ で良さそうです。 total_count.times.map { '+' }この方法も面白いですね。
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. なるほど、ちょっとすっきりしますね 文字列を一旦配列にしてうんぬんが無駄な気がしますね みたいなのが理想です |
||
| end | ||
|
|
||
| private | ||
| def total_count | ||
| (0..9).map(&:to_s).reduce(0) do |count, n| | ||
| count + [@secret.count(n), @numbers.count(n)].min | ||
| end | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. この実装面白いですね。なるほどー、って感じです。
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 頭ひねってこのやり方しか出てこなかったです |
||
| end | ||
|
|
||
| def hit_count | ||
| @hit_count ||= @secret.each_index.reduce(0) do |count, idx| | ||
| count + (@secret[idx] == @numbers[idx] ? 1 : 0) | ||
| end | ||
| end | ||
|
|
||
| def match_count | ||
| total_count - hit_count | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| Feature: codebreaker starts game | ||
| As a codebreaker | ||
| I want to start a game | ||
| So that I can break the code | ||
|
|
||
| Scenario: start game | ||
| Given I am not yet playing | ||
| When I start a new game | ||
| Then I should see "Welcome to Codebreaker!" | ||
| And I should see "Enter guess: " | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| Feature: codebreaker submits guess | ||
| The codebreaker submits a guess of four numbers. The game marks the guess with + and - signs. | ||
|
|
||
| For each number in the guess that matches the number and position of a number in the secret code, the mark includes one + sign. For each number in the guess that matches the number but not the position of a number in the secret code, the mark includes one - sign. | ||
|
|
||
| Each position in the secret code can only be matched once. For example, a guess of 1134 against a secret code of 1234 would get three plus signs: one for each of the exact matches in the first, third and fourth positions. The number match in the second position would be ignored. | ||
|
|
||
| Scenario Outline: submit a guess | ||
| Given the secret code is "<code>" | ||
| When I guess "<guess>" | ||
| Then the mark should be "<mark>" | ||
|
|
||
| Scenarios: no matches | ||
| | code | guess | mark | | ||
| | 1234 | 5555 | | | ||
|
|
||
| Scenarios: 1 number correct | ||
| | code | guess | mark | | ||
| | 1234 | 1555 | + | | ||
| | 1234 | 2555 | - | | ||
|
|
||
| Scenarios: 2 numbers correct | ||
| | code | guess | mark | | ||
| | 1234 | 5254 | ++ | | ||
| | 1234 | 5154 | +- | | ||
| | 1234 | 2545 | -- | | ||
|
|
||
| Scenarios: 3 numbers correct | ||
| | code | guess | mark | | ||
| | 1234 | 5234 | +++ | | ||
| | 1234 | 5134 | ++- | | ||
| | 1234 | 5124 | +-- | | ||
| | 1234 | 5123 | --- | | ||
|
|
||
| Scenarios: all numbers correct | ||
| | code | guess | mark | | ||
| | 1234 | 1234 | ++++ | | ||
| | 1234 | 1243 | ++-- | | ||
| | 1234 | 1423 | +--- | | ||
| | 1234 | 4321 | ---- | | ||
|
|
||
| Scenarios: matches with duplicates | ||
| | code | guess | mark | | ||
| | 1234 | 1155 | + | | ||
| | 1234 | 5115 | - | | ||
| | 1134 | 1155 | ++ | | ||
| | 1134 | 5115 | +- | | ||
| | 1134 | 5511 | -- | | ||
| | 1134 | 1115 | ++ | | ||
| | 1134 | 5111 | +- | | ||
| | 1155 | 1234 | + | | ||
| | 1111 | 1112 | +++ | | ||
| | 1113 | 1121 | ++- | | ||
| | 3111 | 1311 | ++-- | | ||
| | 3114 | 1251 | -- | | ||
| | 1511 | 2134 | - | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| Given /^I am not yet playing$/ do | ||
| end | ||
|
|
||
| When /^I start a new game$/ do | ||
| game = Codebreaker::Game.new(output) | ||
| game.start('1234') | ||
| end | ||
|
|
||
| Then /^I should see "([^\"]*)"$/ do |message| | ||
| output.messages.should include(message) | ||
| end | ||
|
|
||
| Given /^the secret code is "([^\"]*)"$/ do |secret| | ||
| @game = Codebreaker::Game.new(output) | ||
| @game.start(secret) | ||
| end | ||
|
|
||
| When /^I guess "([^\"]*)"$/ do |guess| | ||
| @guess = guess | ||
| end | ||
|
|
||
| Then /^the mark should be "([^\"]*)"$/ do |mark| | ||
| @game.guess(@guess).should == mark | ||
| end | ||
|
|
||
| class Output | ||
| def messages | ||
| @messages ||= [] | ||
| end | ||
|
|
||
| def puts(message) | ||
| messages << message | ||
| end | ||
| end | ||
|
|
||
| def output | ||
| @output ||= Output.new | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| $LOAD_PATH << File.expand_path('../..', File.dirname(__FILE__)) | ||
| require 'codebreaker' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| require 'spec_helper' | ||
| require 'codebreaker' | ||
|
|
||
| module Codebreaker | ||
| describe Game do | ||
| let(:output) { double('output').as_null_object } | ||
| let(:game) { Game.new(output) } | ||
|
|
||
| describe "#start" do | ||
| it "sends a welcome message" do | ||
| output.should_receive(:puts).with('Welcome to Codebreaker!') | ||
| game.start('1234') | ||
| end | ||
|
|
||
| it "prompts for the first guess" do | ||
| output.should_receive(:puts).with('Enter guess: ') | ||
| game.start('1234') | ||
| end | ||
| end | ||
|
|
||
| describe "#guess" do | ||
| context "with no matches" do | ||
| it "sends a mark with ''" do | ||
| game.start('1234') | ||
| game.guess('5555').should == '' | ||
| end | ||
| end | ||
|
|
||
| context "with 1 number match" do | ||
| it "sends a mark with '-'" do | ||
| game.start('1234') | ||
| game.guess('2555').should == '-' | ||
| end | ||
| end | ||
|
|
||
| context "with 1 exact match" do | ||
| it "sends a mark with '+'" do | ||
| game.start('1234') | ||
| game.guess('1555').should == '+' | ||
| end | ||
| end | ||
|
|
||
| context "with 2 number matches" do | ||
| it "sends a mark with '--'" do | ||
| game.start('1234') | ||
| game.guess('2355').should == '--' | ||
| end | ||
| end | ||
|
|
||
| context "with 1 number match and 1 exact match (in that order)" do | ||
| it "sends a mark with '+-'" do | ||
| game.start('1234') | ||
| game.guess('2535').should == '+-' | ||
| end | ||
| end | ||
|
|
||
| context "with 1 exact match duplicated in guess" do | ||
| it "sends a mark with '+'" do | ||
| game.start('1234') | ||
| game.guess('1155').should == '+' | ||
| end | ||
| end | ||
|
|
||
| context "with 1 exact match duplicated in secret" do | ||
| it "sends a mark with '+'" do | ||
| game.start('1155') | ||
| game.guess('1234').should == '+' | ||
| end | ||
| end | ||
|
|
||
| context "with 1 number match duplicated in secret" do | ||
| it "sends a mark with '-'" do | ||
| game.start('1511') | ||
| game.guess('2134').should == '-' | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # by default, rspec only loads lib/ into the path, not the root project directory | ||
| $LOAD_PATH << File.expand_path('..', File.dirname(__FILE__)) | ||
|
|
||
| RSpec.configure do |config| | ||
| # Use color in STDOUT | ||
| config.color_enabled = true | ||
|
|
||
| # Use color not only in STDOUT but also in pagers and files | ||
| # config.tty = true | ||
|
|
||
| # Use the specified formatter | ||
| config.formatter = :documentation # :progress, :html, :textmate | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この初期化は不要です。インスタンスメソッド存在しなくても
nilが返るのでhit_countの中でいきなり書けばOKです。There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2回目gessるとバグりませんか?
ちょっとテスト書いてみます
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
おお、ほんとですね。すみません。
そうするとメモイズがだいぶダサいので最初のコードが美しいと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます
戻しました