OSDN Git Service

Implemented Swiss pairing.
authorbeatles <beatles@b8c68f68-1e22-0410-b08e-880e1f8202b4>
Fri, 7 Nov 2008 07:15:03 +0000 (07:15 +0000)
committerbeatles <beatles@b8c68f68-1e22-0410-b08e-880e1f8202b4>
Fri, 7 Nov 2008 07:15:03 +0000 (07:15 +0000)
shogi_server/pairing.rb
test/TC_floodgate.rb

index 992dbcb..26d0f9f 100644 (file)
@@ -25,7 +25,7 @@ module ShogiServer
 
     class << self
       def default_factory
 
     class << self
       def default_factory
-        return sort_by_rate_with_randomness
+        return swiss_pairing
       end
 
       def sort_by_rate_with_randomness
       end
 
       def sort_by_rate_with_randomness
@@ -44,6 +44,15 @@ module ShogiServer
                 StartGame.new]
       end
 
                 StartGame.new]
       end
 
+      def swiss_pairing
+        history = ShogiServer::League::Floodgate::History.factory
+        return [LogPlayers.new,
+                ExcludeSacrificeGps500.new,
+                MakeEven.new,
+                Swiss.new(history),
+                StartGame.new]
+      end
+
       def match(players)
         logics = default_factory
         logics.inject(players) do |result, item|
       def match(players)
         logics = default_factory
         logics.inject(players) do |result, item|
@@ -148,13 +157,42 @@ module ShogiServer
       @rand1, @rand2 = rand1, rand2
     end
 
       @rand1, @rand2 = rand1, rand2
     end
 
-    def match(players)
-      super
+    def match(players, desc=false)
+      super(players)
       cur_rate = Hash.new
       players.each{|a| cur_rate[a] = a.rate ? a.rate + rand(@rand1) : rand(@rand2)}
       players.sort!{|a,b| cur_rate[a] <=> cur_rate[b]}
       cur_rate = Hash.new
       players.each{|a| cur_rate[a] = a.rate ? a.rate + rand(@rand1) : rand(@rand2)}
       players.sort!{|a,b| cur_rate[a] <=> cur_rate[b]}
+      players.reverse! if desc
       log_players(players) do |one|
       log_players(players) do |one|
-        "%s %d (randomness %d)" % [one.name, one.rate, cur_rate[one] - one.rate]
+        "%s %d (+ randomness %d)" % [one.name, one.rate, cur_rate[one] - one.rate]
+      end
+    end
+  end
+
+  class Swiss < Pairing
+    def initialize(history)
+      super()
+      @history = history
+    end
+
+    def match(players)
+      super
+      winners = players.find_all {|pl| @history.last_win?(pl.player_id)}
+      rest    = players - winners
+
+      log_message("Floodgate: %d winners" % [winners.size])
+      sbrwr_winners = SortByRateWithRandomness.new(800, 2500)
+      sbrwr_winners.match(winners, true)
+      log_players(winners)
+
+      log_message("Floodgate: and the rest: %d" % [rest.size])
+      sbrwr_losers = SortByRateWithRandomness.new(200, 400)
+      sbrwr_losers.match(rest, true)
+      log_players(rest)
+
+      players.clear
+      [winners, rest].each do |group|
+        group.each {|pl| players << pl}
       end
     end
   end
       end
     end
   end
index aa499ef..be5b3af 100644 (file)
@@ -363,6 +363,74 @@ class TestExcludeSacrifice < Test::Unit::TestCase
   end
 end
 
   end
 end
 
+class TestSwissPairing < Test::Unit::TestCase
+  def setup
+    srand(10)
+    @a = ShogiServer::BasicPlayer.new
+    @a.player_id = "a"
+    @a.rate = 0
+    @b = ShogiServer::BasicPlayer.new
+    @b.player_id = "b"
+    @b.rate = 1000
+    @c = ShogiServer::BasicPlayer.new
+    @c.player_id = "c"
+    @c.rate = 1500
+    @d = ShogiServer::BasicPlayer.new
+    @d.player_id = "d"
+    @d.rate = 2000
+
+    @players = [@a, @b, @c, @d]
+
+    @file = Pathname.new(File.join(File.dirname(__FILE__), "floodgate_history.yaml"))
+    @history = ShogiServer::League::Floodgate::History.new @file
+
+    @swiss = ShogiServer::Swiss.new @history
+  end
+
+  def teardown
+    @file.delete if @file.exist?
+  end
+
+  def test_all_win
+    def @history.last_win?(player_id)
+      true
+    end
+    @swiss.match @players
+    assert_equal([@d, @c, @b, @a], @players)
+  end
+
+  def test_all_lose
+    def @history.last_win?(player_id)
+      false
+    end
+    @swiss.match @players
+    assert_equal([@d, @c, @b, @a], @players)
+  end
+
+  def test_one_win
+    def @history.last_win?(player_id)
+      if player_id == "a"
+        true
+      else
+        false
+      end
+    end
+    @swiss.match @players
+    assert_equal([@a, @d, @c, @b], @players)
+  end
+
+  def test_two_win
+    def @history.last_win?(player_id)
+      if player_id == "a" || player_id == "d"
+        true
+      else
+        false
+      end
+    end
+    @swiss.match @players
+    assert_equal([@d, @a, @c, @b], @players)
+  end
+end
 
 class TestFloodgateHistory < Test::Unit::TestCase
   def setup
 
 class TestFloodgateHistory < Test::Unit::TestCase
   def setup