OSDN Git Service

Simplify estimated rate of unrated players (less memory).
authorDaigo Moriwaki <daigo@debian.org>
Sat, 7 Dec 2013 09:50:19 +0000 (18:50 +0900)
committerDaigo Moriwaki <daigo@debian.org>
Sat, 7 Dec 2013 15:15:50 +0000 (00:15 +0900)
* [shogi-server]
  - pairing.rb, player.rb:
    Simplify estimated rate of unrated players (less memory).

changelog
shogi_server/pairing.rb
shogi_server/player.rb
test/TC_pairing.rb

index 1790cf0..109f434 100644 (file)
--- a/changelog
+++ b/changelog
@@ -1,3 +1,9 @@
+2013-12-07  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi-server]
+         - shogi_server/pairing.rb, player.rb:
+           Simplify estimated rate of unrated players (less memory).
+
 2013-12-05  Daigo Moriwaki <daigo at debian dot org>
 
        * [shogi-server]
 2013-12-05  Daigo Moriwaki <daigo at debian dot org>
 
        * [shogi-server]
index 7d70cbb..6d62891 100644 (file)
@@ -396,43 +396,74 @@ module ShogiServer
       players.shuffle
     end
 
       players.shuffle
     end
 
-    # Returns a player's rate value.
+    # Update estimated rate of a player.
     # 1. If it has a valid rate, return the rate.
     # 1. If it has a valid rate, return the rate.
-    # 2. If it has no valid rate, return average of the following values:
-    #   a. For games it won, the opponent's rate + 100
-    #   b. For games it lost, the opponent's rate - 100
-    #   (if the opponent has no valid rate, count out the game)
-    #   (if there are not such games, return 2150 (default value)
+    # 2. If it has no valid rate, return:
+    #   a. If it won the last game, the opponent's rate + 200
+    #   b. If it lost the last game, the opponent's rate - 200
+    #   c. otherwise, return 2150 (default value)
     #
     #
-    def get_player_rate(player, history)
-      return player.rate if player.rate != 0
-      return 2150 unless history
-
-      count = 0
-      sum = 0
-
-      history.win_games(player.player_id).each do |g|
-        next unless g[:loser]
-        name = g[:loser].split("+")[0]
-        p = $league.find(name)
-        if p && p.rate != 0
-          count += 1
-          sum += p.rate + 100
-        end
+    def estimate_rate(player, history)
+      player.estimated_rate = 2150 # default value
+
+      unless history
+        log_message("Floodgate: Without game history, estimated %s's rate: %d" % [player.name, player.estimated_rate])
+        return
       end
       end
-      history.loss_games(player.player_id).each do |g|
-        next unless g[:winner]
-        name = g[:winner].split("+")[0]
-        p = $league.find(name)
-        if p && p.rate != 0
-          count += 1
-          sum += p.rate - 100
-        end
+
+      g = history.last_valid_game(player.player_id)
+      unless g
+        log_message("Floodgate: Without any valid games in history, estimated %s's rate: %d" % [player.name, player.estimated_rate])
+        return
       end
 
       end
 
-      estimate = (count == 0 ? 2150 : sum/count)
-      log_message("Floodgate: Estimated rate of %s is %d" % [player.name, estimate])
-      return estimate
+      opponent_id = nil
+      win         = true
+      case player.player_id
+      when g[:winner]
+        opponent_id = g[:loser]
+        win = true
+      when g[:loser]
+        opponent_id = g[:winner]
+        win = false
+      else
+        log_warning("Floodgate: The last valid game is invalid for %s!" % [player.name])
+        log_message("Floodgate: Estimated %s's rate: %d" % [player.name, player.estimated_rate])
+        return
+      end
+
+      opponent_name = opponent_id.split("+")[0]
+      p = $league.find(opponent_name)
+      unless p
+        log_message("Floodgate: No active opponent found. Estimated %s's rate: %d" % [player.name, player.estimated_rate])
+        return
+      end
+
+      opponent_rate = 0
+      if p.rate != 0
+        opponent_rate = p.rate
+      elsif p.estimated_rate != 0
+        opponent_rate = p.estimated_rate
+      end
+
+      if opponent_rate != 0
+        player.estimated_rate = opponent_rate + (win ? 200 : -200)
+      end
+
+      log_message("Floodgate: Estimated %s's rate: %d" % [player.name, player.estimated_rate])
+    end
+
+    # Return a player's rate based on its actual rate or estimated rate.
+    #
+    def get_player_rate(player, history)
+      if player.rate != 0
+        return player.rate
+      elsif player.estimated_rate != 0
+        return player.estimated_rate 
+      else
+        estimate_rate(player, history)
+        return player.estimated_rate
+      end
     end
 
     def calculate_diff_with_penalty(players, history)
     end
 
     def calculate_diff_with_penalty(players, history)
@@ -475,6 +506,9 @@ module ShogiServer
         return players
       end
 
         return players
       end
 
+      # Reset estimated rate
+      players.each {|p| p.estimated_rate = 0}
+
       # 10 trials
       matches = []
       scores  = []
       # 10 trials
       matches = []
       scores  = []
index b6b60f5..471119b 100644 (file)
@@ -27,6 +27,7 @@ class BasicPlayer
     @name = nil
     @password = nil
     @rate = 0
     @name = nil
     @password = nil
     @rate = 0
+    @estimated_rate = 0
     @win  = 0
     @loss = 0
     @last_game_win = false
     @win  = 0
     @loss = 0
     @last_game_win = false
@@ -48,6 +49,10 @@ class BasicPlayer
   # Score in the rating sysem
   attr_accessor :rate
 
   # Score in the rating sysem
   attr_accessor :rate
 
+  # Estimated rate for unrated player (rate == 0)
+  # But this value is not persisted and cleared when player logs off.
+  attr_accessor :estimated_rate
+
   # Number of games for win and loss in the rating system
   attr_accessor :win, :loss
   
   # Number of games for win and loss in the rating system
   attr_accessor :win, :loss
   
index d9871e3..30f353e 100644 (file)
@@ -551,6 +551,7 @@ class TestLeastDiff < Test::Unit::TestCase
   def test_get_player_rate_0
     assert_equal(2150, @pairing.get_player_rate(@x, @history))
 
   def test_get_player_rate_0
     assert_equal(2150, @pairing.get_player_rate(@x, @history))
 
+    @x.estimated_rate = 0
     dummy = nil
     def @history.make_record(game_result)
       {:game_id => "wdoor+floodgate-900-0-x-a-1", 
     dummy = nil
     def @history.make_record(game_result)
       {:game_id => "wdoor+floodgate-900-0-x-a-1", 
@@ -558,8 +559,9 @@ class TestLeastDiff < Test::Unit::TestCase
        :winner => "x", :loser => "a"}
     end
     @history.update(dummy)
        :winner => "x", :loser => "a"}
     end
     @history.update(dummy)
-    assert_equal(@a.rate+100, @pairing.get_player_rate(@x, @history))
+    assert_equal(@a.rate+200, @pairing.get_player_rate(@x, @history))
 
 
+    @x.estimated_rate = 0
     def @history.make_record(game_result)
       {:game_id => "wdoor+floodgate-900-0-x-b-1", 
        :black => "x",  :white => "b",
     def @history.make_record(game_result)
       {:game_id => "wdoor+floodgate-900-0-x-b-1", 
        :black => "x",  :white => "b",
@@ -567,7 +569,7 @@ class TestLeastDiff < Test::Unit::TestCase
     end
     @history.update(dummy)
 
     end
     @history.update(dummy)
 
-    assert_equal((@a.rate+100+@b.rate-100)/2, @pairing.get_player_rate(@x, @history))
+    assert_equal(@b.rate-200, @pairing.get_player_rate(@x, @history))
   end
 end
 
   end
 end