[QUIZ] Lost Cities (#51)

This is the nice thing about sharing your code. You go to bed, and
magically all your bugs are found when you wake up.

This is an updated version of the tester. It makes a random number
between 0 and 999,999 (not 0 and 1), and it creates a new player for
each game (I can't believe I tried reusing players). It also overrides
the player objects to account for the extra newline character that
sockets players should be getting.

Now on to the fun bit.... making that damn computer THINK.

···

----

require 'lost_cities'
require 'nano/enumerable/each_combination'

class Player
  @@players = []
  def self.inherited( subclass )
    @@players << subclass unless subclass == SocketPlayer
  end
  def self.players
    @@players
  end
end
class Game
    public :score
end

count = 10
count = ARGV.shift.to_i if /^\d*$/=== ARGV[0]
srand(ARGV.shift.to_i) if /^\d*$/=== ARGV[0]

ARGV.each { |file| require file } if ARGV.length > 0

RecordStruct = Struct.new( :type, :wins, :scores )
records = Hash.new { |h,k| h[k] = RecordStruct.new(k.to_s, 0, []) }

seeds = Array.new(count) { rand(1_000_000) }

play_proc = lambda do |player_classes|
    p "Playing #{player_classes.inspect}"
    seeds.each do |seed|
        players = player_classes.map do |x|
            x = x.new
            class << x
                alias :orig_show :show
                def show(data); orig_show (data + "\n"); end
            end
            x
        end
        srand(seed)
        game = Game.new(*players)
        until game.over?
            game.rotate_player
            game.play
            game.draw
        end
        scores = players.map{ |player| game.score(player.lands)
}.zip(players.map {|player| player.class})
        scores = scores.sort_by { |a,b| a }
        scores.each { |a,b| records[b].scores << a }
        records[scores[-1][1]].wins += 1
    end
end

if(Player.players.size > 1)
    Player.players.each_combination(2, &play_proc)
else
    Player.players.map{ |x| [x,x] }.each(&play_proc)
end

puts
printf("%-30s %4s %5s %5s %5s", "Class", "Wins", "Avg.", "Min.",
"Max.")
puts
records.values.sort_by {|r| -r.wins}.each { |record|
    printf("%-30s %4d %2.2f %2.2f %2.2f",
        record.type,
        record.wins,
        record.scores.inject(0) { |s,x| s + x }
/record.scores.size.to_f,
        record.scores.min,
        record.scores.max)
    puts
}
#####################################################################################
This email has been scanned by MailMarshal, an email content filter.
#####################################################################################