X-Git-Url: http://git.sourceforge.jp/view?p=shogi-server%2Fshogi-server.git;a=blobdiff_plain;f=mk_rate;h=3678b452a037fde6195ea7c486abe213c8ff3e56;hp=568c4f41684739ab5292e55e598c52690be72348;hb=7a9b8f6315c13501a9936d89e66d93499c9e610b;hpb=9c4dad06f7ea9b2aefeb5dfdc5b6be234fe745d7 diff --git a/mk_rate b/mk_rate index 568c4f4..3678b45 100755 --- a/mk_rate +++ b/mk_rate @@ -5,7 +5,7 @@ # Homepage:: http://sourceforge.jp/projects/shogi-server/ # #-- -# Copyright (C) 2006-2008 Daigo Moriwaki +# Copyright (C) 2006-2009 Daigo Moriwaki # # 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 @@ -24,15 +24,23 @@ # # == Synopsis # -# mk_rate reads CSA files, calculates rating scores of each player, and then -# outputs a yaml file (players.yaml) that Shogi-server can recognize. +# mk_rate reads game results files generated by the mk_game_results command, +# calculates rating scores of each player, and then outputs a yaml file +# (players.yaml) that Shogi-server can recognize. # # == Usage # -# ./mk_rate [options] DIR.. +# ./mk_rate [options] GAME_RESULTS_FILE [...] +# +# ./mk_rate [options] # -# DIR:: -# CSA files are recursively looked up the directories. +# GAME_RESULTS_FILE:: +# a path to a file listing results of games, which is genrated by the +# mk_game_results command. +# In the second style above, the file content can be read from the stdin. +# +# --base-date:: +# a base time point for this calicuration (default now). Ex. '2009-10-31' # # --half-life:: # n [days] (default 60) @@ -41,12 +49,20 @@ # 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 # # --fixed-rate:: # rate # +# --skip-draw-games:: +# skip draw games. [default: draw games are counted in as 0.5 win and 0.5 +# lost.] +# # --help:: # show this message # @@ -70,13 +86,15 @@ # # $ sudo gem install rgl # -# == Run +# == Examples # -# $ ./mk_rate . > players.yaml +# $ ./mk_rate game_results.txt > players.yaml # -# or, if you do not want the file to be update in case of errors, +# $ ./mk_game_results . | ./mk_rate > players.yaml # -# $ ./mk_rate . && ./mk_rate . > players.yaml +# If you do not want the file to be update in case of errors, +# +# $ ./mk_rate game_results.txt && ./mk_rate game_results.txt > players.yaml # # == How players are rated # @@ -332,6 +350,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 @@ -348,6 +367,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! @@ -425,7 +445,7 @@ class WinLossMatrix 0 else p2 = keys[j] - v = p1_hash[p2] || Vector[0,0] + v = p1_hash[p2] || GSL::Vector[0,0] v[0] end end) @@ -591,13 +611,21 @@ def half_life(days) end def _add_win_loss(winner, loser, time) - how_long_days = (Time.now - time)/(3600*24) + how_long_days = ($options["base-date"] - time)/(3600*24) $players[winner] ||= Hash.new { GSL::Vector[0,0] } $players[loser] ||= Hash.new { GSL::Vector[0,0] } $players[winner][loser] += GSL::Vector[1.0*half_life(how_long_days),0] $players[loser][winner] += GSL::Vector[0,1.0*half_life(how_long_days)] end +def _add_draw(player1, player2, time) + how_long_days = ($options["base-date"] - time)/(3600*24) + $players[player1] ||= Hash.new { GSL::Vector[0,0] } + $players[player2] ||= Hash.new { GSL::Vector[0,0] } + $players[player1][player2] += GSL::Vector[0.5*half_life(how_long_days),0.5*half_life(how_long_days)] + $players[player2][player1] += GSL::Vector[0.5*half_life(how_long_days),0.5*half_life(how_long_days)] +end + def _add_time(player, time) $players_time[player] = time if $players_time[player] < time end @@ -608,7 +636,11 @@ def add(black_mark, black_name, white_name, white_mark, time) elsif black_mark == LOSS_MARK && white_mark == WIN_MARK _add_win_loss(white_name, black_name, time) elsif black_mark == DRAW_MARK && white_mark == DRAW_MARK - return + if $options["skip-draw-games"] + return + else + _add_draw(black_name, white_name, time) + end else raise "Never reached!" end @@ -623,46 +655,31 @@ def identify_id(id) id.gsub(/@.*?\+/,"+") end -def grep(file) - str = File.open(file).read - - if /^N\+(.*)$/ =~ str then black_name = $1.strip end - if /^N\-(.*)$/ =~ str then white_name = $1.strip end - - if /^'summary:(.*)$/ =~ str - state, p1, p2 = $1.split(":").map {|a| a.strip} - return if state == "abnormal" - p1_name, p1_mark = p1.split(" ") - p2_name, p2_mark = p2.split(" ") - if p1_name == black_name - black_name, black_mark = p1_name, p1_mark - white_name, white_mark = p2_name, p2_mark - elsif p2_name == black_name - black_name, black_mark = p2_name, p2_mark - white_name, white_mark = p1_name, p1_mark - else - raise "Never reach!: #{black} #{white} #{p3} #{p2}" - end - end - if /^'\$END_TIME:(.*)$/ =~ str - time = Time.parse($1.strip) +# Parse a game result line +# +def parse(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 + $stderr.puts "Failed to parse the line : #{line}" + return end - if /^'rating:(.*)$/ =~ str - black_id, white_id = $1.split(":").map {|a| a.strip} - black_id = identify_id(black_id) - white_id = identify_id(white_id) - if black_id && white_id && (black_id != white_id) && - black_mark && white_mark - add(black_mark, black_id, white_id, white_mark, time) - end + + return if state == "abnormal" + 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 -end -def usage - $stderr.puts <<-EOF -USAGE: #{$0} dir [...] - EOF - exit 1 + black_id = identify_id(black_id) + white_id = identify_id(white_id) + + if black_id && white_id && (black_id != white_id) && + black_mark && white_mark + add(black_mark, black_id, white_id, white_mark, time) + end end def validate(yaml) @@ -680,14 +697,25 @@ end def usage(io) io.puts <