From 190bdbee9fe51b3ebab4390b7c92f9af02f7bc54 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 16 Jun 2012 23:29:57 -0400 Subject: [PATCH] doing something a bit more marco-polo-ish (and more interesting, too) --- ruby-sockets/marco-polo/client.rb | 55 +++++++++----- ruby-sockets/marco-polo/em-server.rb | 107 ++++++++++++++++++++++----- 2 files changed, 123 insertions(+), 39 deletions(-) diff --git a/ruby-sockets/marco-polo/client.rb b/ruby-sockets/marco-polo/client.rb index 2254671..4560269 100644 --- a/ruby-sockets/marco-polo/client.rb +++ b/ruby-sockets/marco-polo/client.rb @@ -1,25 +1,40 @@ require 'socket' -successes = 0 -backoff = 0.5 -loop do - begin - TCPSocket.open('127.0.0.1', 22000) do |sock| - sock.send("sally #{rand(101)} #{rand(101)}\n", 0) - sock.recv(100) - sock.close - STDOUT.write('.') - STDOUT.flush +def main + client_type = %w(read write).include?(ARGV.first) ? ARGV.first : 'read' + sleep_interval = (ARGV[1] || 0).to_f + puts "Starting #{client_type} client" + + successes = 0 + backoff = 0.5 + nextloc = [rand(0..99), rand(0..99)] + loop do + begin + TCPSocket.open('127.0.0.1', 22000) do |sock| + case client_type + when 'read' + sock.send("marco sally\n", 0) + location = sock.recv(100).to_s.split[2,4].map(&:to_i) + puts "#{location.first} #{location.last}" + when 'write' + sock.send("polo sally #{nextloc.first} #{nextloc.last}\n", 0) + nextloc = sock.recv(100).to_s.split.map(&:to_i) + puts "sent location '#{nextloc.first} #{nextloc.last}'" + end + sock.close + end + successes += 1 + backoff = 0.5 + sleep sleep_interval + rescue + puts "made it #{successes} times. sleeping #{backoff} secs" + successes = 0 + sleep backoff + backoff *= 2 end - successes += 1 - backoff = 0.5 - sleep 0.01 if ENV['SLEEP'] - rescue - STDOUT.write('E') - STDOUT.flush - STDERR.write("\nmade it #{successes} times. sleeping #{backoff} secs\n") - successes = 0 - sleep backoff - backoff *= 2 end end + +if $0 == __FILE__ + main +end diff --git a/ruby-sockets/marco-polo/em-server.rb b/ruby-sockets/marco-polo/em-server.rb index cec05a6..d7f491e 100644 --- a/ruby-sockets/marco-polo/em-server.rb +++ b/ruby-sockets/marco-polo/em-server.rb @@ -1,33 +1,102 @@ -require 'logger' - require 'eventmachine' require 'sequel' -DB = Sequel.connect("postgres://#{ENV['USER']}@localhost/marco_polo", - :max_connections => 10) -DB.create_table! :locations do - primary_key :id - String :client - Integer :x - Integer :y +class MarcoPolo + attr_reader :locations, :db + + def initialize + @pool_range = 0..99 + # I'm not using this (yet?) ... but don't want to forget how I did it + # @pool = [].tap do |board| + # @pool_range.each do |y| + # board << [].tap do |row| + # @pool_range.each do |x| + # row << "#{y}-#{x}" + # end + # end + # end + # end + @db = Sequel.connect("postgres://#{ENV['USER']}@localhost/marco_polo", + :max_connections => 10) + unless @db.table_exists?(:locations) + @db.create_table :locations do + primary_key :id + String :client + DateTime :timestamp + Integer :x + Integer :y + constraint(:in_the_pool, 'x > -1 and x < 100 and y > -1 and y < 100') + end + end + @locations = @db[:locations] + puts "LET GAME BEGIN NOW" + end + + def polo(client, x, y) + @locations.insert(:client => client, :x => x, :y => y, + :timestamp => Time.now) + nextloc(x, y) + end + + def marco(client = nil) + if client + @locations.where(:client => client).order_by(:timestamp.desc).first + else + @locations.order_by(:timestamp.desc).first + end + end + + private + def nextloc(x, y) + # we allow exiting the pool as long as you get back in on the opposite side + # a la pac man + move_x, move_y = rand(-2..2), rand(-2..2) + new_x = x + move_x + new_x = 100 + new_x if new_x <= -1 + new_y = y + move_y + new_y = 100 + new_y if new_y <= -1 + [ + new_x > 99 ? new_x % 100 : new_x, + new_y > 99 ? new_y % 100 : new_y + ] + end end -module MarcoPoloServer - def post_init - @locations = DB[:locations] +class MarcoPoloServer < EventMachine::Connection + class << self + attr_accessor :game end def receive_data(data) - client, x, y = data.split - @locations.insert(:client => client, :x => x.to_i, :y => y.to_i) - send_data("thanks\n") + parts = data.to_s.split + case parts.first + when 'polo' + client, x, y = parts[1,4] + newloc = self.class.game.polo(client, x.to_i, y.to_i) + send_data("#{newloc.first} #{newloc.last}\n") + when 'marco' + if loc = self.class.game.marco(parts[1]) + send_data("polo #{loc[:client]} #{loc[:x]} #{loc[:y]}\n") + else + send_data("polo NULL 0 0\n") + end + else + send_data("#{parts.first}???\n") + end rescue => e STDERR.puts("#{e.class.name} #{e.message}: #{e.backtrace.join("\n")}") end end -EventMachine.run do - host, port = '0.0.0.0', 22000 - EventMachine.start_server(host, port, MarcoPoloServer) - puts "Listening on #{host}:#{port}" +def main + MarcoPoloServer.game = MarcoPolo.new + EventMachine.run do + host, port = '0.0.0.0', 22000 + EventMachine.start_server(host, port, MarcoPoloServer) + puts "Listening on #{host}:#{port}" + end +end + +if $0 == __FILE__ + main end