OSDN Git Service

Merge branch 'wdoor-stable'
[shogi-server/shogi-server.git] / mk_rate
diff --git a/mk_rate b/mk_rate
index b236811..6090225 100755 (executable)
--- a/mk_rate
+++ b/mk_rate
@@ -1,11 +1,11 @@
-#!/usr/bin/ruby
+#!/usr/bin/ruby1.9.1
 # $Id$
 #
 # Author:: Daigo Moriwaki
 # Homepage:: http://sourceforge.jp/projects/shogi-server/
 #
 #--
-# Copyright (C) 2006-2009 Daigo Moriwaki <daigo at debian dot org>
+# Copyright (C) 2006-2012 Daigo Moriwaki <daigo at debian dot org>
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # ./mk_rate [options]
 # 
 # GAME_RESULTS_FILE::
-#   a path to a file listing results of games, which is genrated by the
+#   a path to a file listing results of games, which is generated by the
 #   mk_game_results command.
 #   In the second style above, the file content can be read from the stdin.
 #
+# --abnormal-threshold::
+#   n [plies] (default 30)
+#   Games that end with the 'abnormal' status are counted in win/lost games
+#   for the rating calculation if a game plays more than n plies. Otherwise
+#   (or if n is zero), abnormal games are counted out of rating games.
+#
 # --base-date::
-#   a base time point for this calicuration (default now). Ex. '2009-10-31'
+#   a base time point for this calculation (default now). Ex. '2009-10-31'
 #
 # --half-life::
 #   n [days] (default 60)
 #   m [days] (default  7)
 #   after m days, the half-life effect works
 #
+# --ignore::
+#   m [days] (default  365*2)
+#   old results will be ignored
+#
 # --fixed-rate-player::
 #   player whose rate is fixed at the rate
 #
 #
 # == PREREQUIRE
 #
-# Sample Command lines that isntall prerequires will work on Debian.
-#
-# * Ruby 1.8.7
-#
-#   $ sudo aptitude install ruby1.8
+# Sample Command lines that install prerequires will work on Debian.
 #
-# * Rubygems
+# * Ruby 1.9.3 or 1.8.7 (including Rubygems)
 #
-#   $ sudo aptitude install rubygems
+#   $ sudo aptitude install ruby1.9.1
 #
 # * Ruby bindings for the GNU Scientific Library (GSL[http://rb-gsl.rubyforge.org/])
 #
-#   $ sudo aptitude install libgsl-ruby1.8
+#   $ sudo aptitude install ruby-gsl
 #
 # * RGL: {Ruby Graph Library}[http://rubyforge.org/projects/rgl/]
 #
-#   $ sudo gem install rgl
+#   $ sudo gem1.9.1 install rgl
 #
 # == Examples
 #
 # * (Rated) players, who played more than $GAMES_LIMIT [15] (rated) games. 
 #
 
+$:.unshift(File.dirname(File.expand_path(__FILE__)))
+require 'utils/csa-filter'
 require 'yaml'
 require 'time'
 require 'getoptlong'
-require 'gsl'
+require 'set'
 require 'rubygems'
+require 'gsl'
 require 'rgl/adjacency'
 require 'rgl/connected_components'
 
@@ -123,6 +132,8 @@ DRAW_MARK = "draw"
 $players = Hash.new
 # Holds the last time when a player gamed
 $players_time = Hash.new { Time.at(0) }
+# Holds history of input lines to check duplicated inputs
+$history = Set.new
 
 
 #################################################
@@ -346,6 +357,7 @@ class Rating
       old_f      = f
       old_f_nrm2 = old_f.nrm2
       deaccelrate(1.0, old_rate, a, old_f_nrm2)
+      #@rate -= a # Instead, do not deaccelerate
       @record.set(func_vector.nrm2, @rate)
 
       $stderr.printf "|error| : %5.2e\n", a.nrm2 if $DEBUG
@@ -362,6 +374,7 @@ class Rating
     @rate = @record.get
     $stderr.puts "resolved f: %s -> %f" %
       [func_vector.to_a.inspect, func_vector.nrm2] if $DEBUG
+    $stderr.puts "Count: %d" % [@count] if $DEBUG
 
     @rate *= 1.0/K
     finite!
@@ -652,6 +665,12 @@ end
 # Parse a game result line
 #
 def parse(line)
+  if $history.include? line
+    $stderr.puts "[WARNING] Duplicated: #{line}"
+    return
+  end
+  $history.add line
+
   time, state, black_mark, black_id, white_id, white_mark, file = line.split("\t")
   unless time && state && black_mark && black_id &&
          white_id && white_mark && file
@@ -659,9 +678,19 @@ def parse(line)
     return
   end
 
-  return if state == "abnormal"
+  if state == "abnormal"
+    csa = CsaFileReader.new(file, "EUC-JP")
+    if $options["abnormal-threshold"] == 0 || csa.ply <= $options["abnormal-threshold"]
+      return
+    end
+  end
   time = Time.parse(time)
   return if $options["base-date"] < time
+  how_long_days = ($options["base-date"] - time)/(3600*24)
+  if (how_long_days > $options["ignore"])
+    return
+  end
+
   black_id = identify_id(black_id)
   white_id = identify_id(white_id)
 
@@ -699,6 +728,8 @@ OPTOINS:
   --half-life         n [days] (default 60)
   --half-life-ignore  m [days] (default  7)
                       after m days, half-life effect works
+  --ignore            n [days] (default 730 [=365*2]).
+                      Results older than n days from the 'base-date' are ignored.
   --fixed-rate-player player whose rate is fixed at the rate
   --fixed-rate        rate 
   --skip-draw-games   skip draw games. [default: draw games are counted in
@@ -710,13 +741,15 @@ end
 def main
   $options = Hash::new
   parser = GetoptLong.new(
-    ["--base-date",         GetoptLong::REQUIRED_ARGUMENT],
-    ["--half-life",         GetoptLong::REQUIRED_ARGUMENT],
-    ["--half-life-ignore",  GetoptLong::REQUIRED_ARGUMENT],
-    ["--help", "-h",        GetoptLong::NO_ARGUMENT],
-    ["--fixed-rate-player", GetoptLong::REQUIRED_ARGUMENT],
-    ["--fixed-rate",        GetoptLong::REQUIRED_ARGUMENT],
-    ["--skip-draw-games",   GetoptLong::NO_ARGUMENT])
+    ["--abnormal-threshold", GetoptLong::REQUIRED_ARGUMENT],
+    ["--base-date",          GetoptLong::REQUIRED_ARGUMENT],
+    ["--half-life",          GetoptLong::REQUIRED_ARGUMENT],
+    ["--half-life-ignore",   GetoptLong::REQUIRED_ARGUMENT],
+    ["--help", "-h",         GetoptLong::NO_ARGUMENT],
+    ["--ignore",             GetoptLong::REQUIRED_ARGUMENT],
+    ["--fixed-rate-player",  GetoptLong::REQUIRED_ARGUMENT],
+    ["--fixed-rate",         GetoptLong::REQUIRED_ARGUMENT],
+    ["--skip-draw-games",    GetoptLong::NO_ARGUMENT])
   parser.quiet = true
   begin
     parser.each_option do |name, arg|
@@ -742,10 +775,14 @@ def main
   else
     $options["base-date"] = Time.now
   end
+  $options["abnormal-threshold"] ||= 30
+  $options["abnormal-threshold"] = $options["abnormal-threshold"].to_i
   $options["half-life"] ||= 60
   $options["half-life"] = $options["half-life"].to_i
   $options["half-life-ignore"] ||= 7
   $options["half-life-ignore"] = $options["half-life-ignore"].to_i
+  $options["ignore"] ||= 365*2
+  $options["ignore"] = $options["ignore"].to_i
   $options["fixed-rate"] = $options["fixed-rate"].to_i if $options["fixed-rate"]
 
   if ARGV.empty?