diff --git a/code_breaker/kameda/codebreaker.rb b/code_breaker/kameda/codebreaker.rb new file mode 100644 index 0000000..a2b57c6 --- /dev/null +++ b/code_breaker/kameda/codebreaker.rb @@ -0,0 +1,66 @@ +# -*- encoding: utf-8 -*- + + +module Enumerable + def sum + self.inject(0) {|memo,i| memo + i} + end +end + +class Object + def try(message) + self.nil? ? nil : self.send(message) + end +end + +module Codebreaker + class Game + def initialize(output) + @output = output + end + + def start(secret) + @secret = secret + end + + def guess(guess) + secret_ary = @secret.split(//) + guess_ary = guess.split(//) + + match_count = self.match_count(secret_ary, guess_ary) + real_hit_count = self.total_hit_count(secret_ary, guess_ary) - match_count + + ('+' * match_count) + ('-' * real_hit_count) + end + + def total_hit_count(secret_ary, guess_ary) + secret_hash = secret_ary.group_by {|char| char} # {要素 => 要素数} というハッシュを作りたいが、次善策 + guess_hash = guess_ary .group_by {|char| char} + secret_hash.map {|key, chars| + secret_count = chars.size + guess_count = guess_hash[key].try(:size).to_i + [secret_count, guess_count].min + }.sum + end + + def match_count(secret_ary, guess_ary) + secret_ary.zip(guess_ary).select {|sec, gue| + sec == gue + }.size + end + + end +end + +case $0 +when __FILE__ + game = Codebreaker::Game.new(STDOUT) + game.start('1234') + while(code=gets.chomp) + puts game.guess(code) + end +when /spec[^\/]*$/ + # {spec of the implementation} +end + + diff --git a/code_breaker/kameda/features/codebreaker_submits_guess.feature b/code_breaker/kameda/features/codebreaker_submits_guess.feature new file mode 100644 index 0000000..2cd941d --- /dev/null +++ b/code_breaker/kameda/features/codebreaker_submits_guess.feature @@ -0,0 +1,57 @@ +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 "" + When I guess "" + Then the mark should be "" + + 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 | - | + diff --git a/code_breaker/kameda/features/step_definitions/codebreaker_steps.rb b/code_breaker/kameda/features/step_definitions/codebreaker_steps.rb new file mode 100644 index 0000000..ee81d31 --- /dev/null +++ b/code_breaker/kameda/features/step_definitions/codebreaker_steps.rb @@ -0,0 +1,41 @@ +# -*- encoding: utf-8 -*- + +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 + diff --git a/code_breaker/kameda/features/support/env.rb b/code_breaker/kameda/features/support/env.rb new file mode 100644 index 0000000..1e71fbe --- /dev/null +++ b/code_breaker/kameda/features/support/env.rb @@ -0,0 +1,6 @@ + + + +$LOAD_PATH << File.expand_path('../..', File.dirname(__FILE__)) +require 'codebreaker' +