[QUIZ] Cows and Bulls (#32)

R

Ruby Quiz

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

by Pat Eyler

My kids like to play a variant of "Cows and Bulls" when we're driving. One of
them (the server, to use a computing term -- you'll see why in a minute) will
think of a word (we usually play with either three or four letters), and the
other (the client) will try to guess it. With each guess, the server will
respond with the number of 'cows' (letters in the word, but not in the right
place) and bulls (letters in the correct place in the word).

Here's a short example:

Server: (thinks of the word cow) I'm thinking of a three letter word.
Client: cab
Server: 0 cows and 1 bull
Client: cat
Server: 0 cows and 1 bull
Client: cot
Server: 0 cows and 2 bulls
Client: cow
Server: That's right!

This weeks quiz has a couple of flavors:

1) You can write a server that will play our version of "Cows and Bulls". It
should follow a simplified version of the above, and look like:

Server: 3 # the number of letters in the word
Client: "cab"
Server: "0 1"
Client: "cat"
Server: "0 1"
Client: "cot"
Server: "0 2"
Client: "cow"
Server: 1 # indicating success

2) You should write also write a client that a player can interact with to play
the game.

3) You can also write a player that will interact with the server and play a
game.
 
B

Brian Schröder

Thank you for the quiz,

My design this week focuses on orthogonality. I made a basic game
class, a network interface to the game class communicating via the
given protocoll, a readline interface and a simple AI. You can plug
together the local or network game class with the Human or AI Player.

Find the source code and documentation at

http://ruby.brian-schroeder.de/quiz/cows-and-bulls/

best regards,

Brian

--=20
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/
 
I

Ilmari Heikkinen

--Apple-Mail-6-493057168
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
charset=ISO-8859-1;
format=flowed


Thank you for the quiz,

My design this week focuses on orthogonality. I made a basic game
class, a network interface to the game class communicating via the
given protocoll, a readline interface and a simple AI. You can plug
together the local or network game class with the Human or AI Player.

Find the source code and documentation at

http://ruby.brian-schroeder.de/quiz/cows-and-bulls/

Thank you for the quiz for my part aswell,

Here's my kinda ad-hoc solution.
No AI player, but networking and a human-readable client.
Didn't use readline though, so it's not the most usable
thing around :/

Oh and it uses IO#readpartial which doesn't seem to be in 1.8.2=20
(2004-12-25).
My debian computator says it has 1.8.2 (2005-01-10), and that has it.


--Apple-Mail-6-493057168
Content-Transfer-Encoding: 7bit
Content-Type: application/octet-stream;
x-unix-mode=0644;
name="cows_and_bulls.rb"
Content-Disposition: attachment;
filename=cows_and_bulls.rb

#!/usr/bin/ruby
=begin
Cows and bulls game for Ruby Quiz #32
<http://www.rubyquiz.com/quiz32.html>

Usage:
cows_and_bulls.rb # starts a new server on port 3085
cows_and_bulls.rb hostname # connects as client to server on hostname
cows_and_bulls.rb --local # plays a non-networked game

Implementation overview:
Reads the words from /usr/share/dict/words, and asks a random word.
The dict words and user replies are downcased and stripped of
preceding & succeeding whitespace.
Uses blocks for (somewhat) abstracting the reply-response protocol.

=end

require 'socket'

class CowsAndBulls

attr_accessor :success, :failure, :words

def initialize(success=1, failure=0, words=load_words)
@success = success
@failure = failure
@words = words
end

def load_words
File.readlines("/usr/share/dict/words").map{|w| w.strip.downcase}
end

def pick_word
@words[rand(words.size)]
end

# Calls the player block first with word size,
# the player block's return value is the player's
# first guess.
# Then calls the player block with "#{cows_count} #{bulls_count}"
# until the player guesses right or exits the game by replying
# "quit."
# If the player solved the game, returns @success.
# If the player quit, returns @failure.
#
def play(word=pick_word, &player)
reply = player.call(word.size).downcase.strip
until word == reply or 'quit' == reply
cb = cows_and_bulls word, reply
stats = cb.join(" ")
reply = player.call(stats).downcase.strip
end
return @failure if word != reply
@success
end

def cows_and_bulls(word1, word2)
b = bulls(word1, word2)
w2 = word2.clone
cows = word1.split('').inject(0){|sum, c|
sum + (w2.sub!(c,'') ? 1 : 0)
} - b
[cows, b]
end

def bulls(word1, word2)
word1.split('').zip(word2.split('')).inject(0){
|sum, (a,b)|
sum + (a == b ? 1 : 0)
}
end

end


class RemoteCowsAndBulls < CowsAndBulls

# Create new RemoteCowsAndBulls proxy for socket connected
# to a CowsAndBulls server.
def initialize(socket, success=1, failure=0)
super success, failure, nil
@socket = socket
end

# Simulates a local CowsAndBulls game by
# proxying the game events to @socket.
#
def play(&player)
letters = @socket.gets.strip
reply = player.call(letters)
@socket.puts reply
server_reply = @socket.gets.strip
while server_reply.include?(" ")
reply = player.call(server_reply)
@socket.puts reply
server_reply = @socket.gets.strip
end
if server_reply == "1"
@success
else
@failure
end
end

end


class CabClient

# Plays a game on the given server object.
def self.play(server)
first = true
result = server.play{|server_reply|
if first
first = false
puts "Amount of letters in word: #{server_reply}"
else
cb = server_reply.split(" ")
puts "Cows: #{cb[0]}, Bulls: #{cb[1]}"
end
STDIN.gets
}
if result == server.success
puts "Good job!"
else
puts "See you again..."
end
end

end


if __FILE__ == $0

mode = nil
if ARGV.empty?
mode = :server
else
if ARGV[0] == '--local'
mode = :local
else
mode = :client
end
end

case mode
when :local
cab = CowsAndBulls.new
CabClient.play(cab)
when :server
cab = CowsAndBulls.new
server = TCPServer.new(3085)
STDERR.puts "Running CowsAndBulls server on TCP port 3085"
while sock = server.accept
Thread.new(sock) do |s|
begin
STDERR.puts "Got client #{s.peeraddr.join(", ")}"
result = cab.play{|server_reply|
s.puts server_reply
client_reply = s.readpartial(256)
unless client_reply.include? "\n"
msg = "Too long client reply, closing connection."
STDERR.puts msg
s.close
raise msg
end
client_reply
}
s.puts result
s.close
rescue => e
puts e, e.backtrace
ensure
s.close
end
end
end
when :client
host = ARGV.shift
sock = TCPSocket.new(host, 3085)
cab = RemoteCowsAndBulls.new(sock)
CabClient.play(cab)
end

end

--Apple-Mail-6-493057168
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=US-ASCII;
format=flowed



--Apple-Mail-6-493057168--
 
J

James Edward Gray II

You can grab my solution at:

http://rubyquiz.com/cowsnbulls.zip

I didn't build a player, but did provide three different interfaces.

The files in the zip are:

cowsnbulls.rb -- The library that handles the game.
Executing this gives a
command-line interface.
tc_library.rb -- Unit tests for the library.
telnet_server.rb -- Quiz solution. The protocol mentioned in
the quiz didn't
appeal to me, so I just targeted Telnet
instead. This isn't
exactly a true Telnet server, since it reads
line-by-line
(You won't see an answer to an "Are You
There" command, until
you press return, for example.), but it's
close enough
for this exercise.
web_server.rb -- Web interface through WEBrick servlets.
(Just for fun.)
english-words.10 -- The dictionary I've been using for testing.
Part of
Spell Checking Oriented Word Lists (SCOWL)
by Kevin Atkinson.

Enjoy.

James Edward Gray II
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top