--Apple-Mail-6-493057168 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=ISO-8859-1; format=flowed On 16.5.2005, at 12:18, Brian Schr=F6der wrote: > 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--