Created
October 25, 2010 10:29
-
-
Save coffeeaddict/644740 to your computer and use it in GitHub Desktop.
Bulls and Cows - an attempt to get a sane solution for http://rosettacode.org/wiki/Bulls_and_cows/Player
This file contains 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 Game | |
attr_reader :secret | |
def initialize | |
@secret = Secret.new | |
end | |
def console_play | |
bulls = -1 | |
while bulls != 4 | |
bulls = 0 | |
cows = 0 | |
print "Your guess please: " | |
guess = gets.chomp.split("").collect { |d| d.to_i } | |
(bulls,cows) = secret.score(guess) | |
puts "You have #{cows} cows and #{bulls} bulls" | |
end | |
end | |
end |
This file contains 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 'game' | |
require 'player' | |
# let the automated player play a game | |
game = Game.new | |
player = Player.new(game) | |
player.play |
This file contains 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 'game.rb' | |
class Player | |
attr_reader :game | |
def initialize(game=nil) | |
@game = game | |
@game ||= Game.new | |
end | |
def play | |
# find the numbers in play | |
numbers = [] | |
1.upto(9) do |i| | |
(bulls,cows) = game.secret.score(Array.new(4) { i }) | |
if ( bulls > 0 || cows > 0 ) | |
numbers << i | |
end | |
end | |
# try a forward rotating approach | |
# | |
# keep track of the scoring, if we can't find a match in mere rotating we | |
# must be able to calculate the best results | |
# | |
bulls = -1 | |
count = 0 | |
high = {} | |
while bulls != 4 | |
(bulls, cows) = game.secret.score(numbers) | |
high[numbers] = bulls if bulls >= 2 | |
numbers = rotate(numbers, count += 1) if bulls != 4 | |
break if count > 20 | |
end | |
if bulls != 4 | |
numbers = must_be(high) | |
end | |
puts "#{numbers.join} -- #{game.secret.secret} : #{numbers == game.secret.s\ | |
ecret}" | |
end | |
# figure out what it must be, given the high scoring combinations | |
# | |
def must_be(high) | |
# make a list of positions and numbers | |
pos = { 0 => [], 1 => [], 2 => [], 3 => [] } | |
high.each_key { |key| | |
key.each_index { |i| pos[i] << key[i] } | |
} | |
# find double occurences on the given position, they must be right | |
must_be = Array.new(4) { 0 } | |
pos.each_key { |i| | |
prev = 0 | |
pos[i].sort { |a,b| a <=> b }.each do |n| | |
must_be[i] = n if n == prev | |
prev = n | |
end | |
} | |
if must_be.include? 0 | |
# There are still empty positions we have figured out only 2. | |
# The other 2 numbers are known - try them at each available position | |
# | |
# First copy the must be positions | |
# | |
could_be = [ must_be.dup ] | |
could_be[0].each_index { |i| | |
# substract any already known numbers from the pool | |
pos[i] -= must_be | |
while could_be[0][i] == 0 | |
# assume the first number is right unless it already occurs | |
candidate = pos[i].shift | |
could_be[0][i] = candidate unless could_be[0].include? candidate | |
end | |
} | |
# The newly found numbers might be reversed, fix that | |
could_be[1] = could_be[0].dup | |
must_be.each_index { |i| | |
if must_be[i] == 0 | |
could_be[1][ | |
i == 0 ? 3 : i == 1 ? 2 : i == 2 ? 1 : 0 | |
] = could_be[0][i] | |
end | |
} | |
# Check if the first guess fits | |
(bulls, cows) = game.secret.score(could_be[0]) | |
must_be = bulls == 4 ? could_be[0] : could_be[1] | |
end | |
must_be | |
end | |
# Rotate the numbers forward | |
# | |
def rotate(array,count) | |
pos = count % 4 | |
return array if pos == 0 | |
dup = array.dup | |
dup[pos] = dup[pos-1] | |
dup[pos-1] = array[pos] | |
return dup | |
end | |
end |
This file contains 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
# A Bulls and Cows secret | |
# | |
class Secret | |
attr_reader :secret | |
def initialize | |
@secret = [] | |
while @secret.length < 4 | |
rnd = 1 + rand(9) | |
@secret << rnd unless @secret.include? rnd | |
end | |
end | |
def score(guess) | |
bulls = 0 | |
cows = 0 | |
guess.each_index { |i| | |
if @secret[i] == guess[i] | |
bulls += 1 | |
elsif @secret.include? guess[i] | |
cows += 1 | |
end | |
} | |
return [bulls,cows] | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment