OSDN Git Service

Merge branch 'logger'
[shogi-server/shogi-server.git] / utils / eval_graph.rb
index f051f57..fbf42fe 100755 (executable)
@@ -1,29 +1,32 @@
-#!/usr/bin/env ruby
-#    This generates graphs of evaluation values from comments in CSA files.
-#    Ruby libraries that are required: 
-#      - RubyGems: http://rubyforge.org/projects/rubygems/
-#      - rgplot:   http://rubyforge.org/projects/rgplot/
-#    OS librariles that is required:
-#      - Gnuplot:  http://www.gnuplot.info/
-#                  On Debian, $ sudo apt-get install gnuplot
-#    
-#    Copyright (C) 2006  Daigo Moriwaki <daigo@debian.org>
+#!/usr/bin/ruby
+# This generates graphs of evaluation values from comments in CSA files.
+# Ruby libraries that are required: 
+# * RubyGems: http://rubyforge.org/projects/rubygems/
+# * rgplot:   http://rubyforge.org/projects/rgplot/
+# OS librariles that is required:
+# * Gnuplot:  http://www.gnuplot.info/
+#   * On Debian, $ sudo apt-get install gnuplot
 #
 #
-#    Version: $Id$
+# Author::    Daigo Moriwaki <daigo at debian dot org>
+# Copyright:: Copyright (C) 2006-2008  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
-#    the Free Software Foundation; either version 2 of the License, or
-#    (at your option) any later version.
+# $Id$
 #
 #
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
+#--
+# 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
 #
 #
-#    You should have received a copy of the GNU General Public License
-#    along with this program; if not, write to the Free Software
-#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+#++
 
 require 'pathname'
 require 'getoptlong'
 
 require 'pathname'
 require 'getoptlong'
@@ -40,6 +43,16 @@ def reformat_svg(str)
 END
 end
 
 END
 end
 
+# Parse play time from the game_name, then return it. If the game_name is
+# not valid, return 0.
+#
+def play_time(game_name)
+  if /.*?\+.*?\-(\d*?)\-/ =~ game_name
+    return $1.to_i
+  end
+  return 0  
+end
+
 module EvalGraph
   def parse_comment(str)
     return nil unless str
 module EvalGraph
   def parse_comment(str)
     return nil unless str
@@ -62,9 +75,10 @@ module EvalGraph
       @comments = []
       @times = []
       @type = type
       @comments = []
       @times = []
       @type = type
-      @regexp_move = Regexp.new("^\\#{@type}\\d{4}\\w{2}")
-      @regexp_name = Regexp.new("^N\\#{@type}(.*)")
-      @regexp_time = Regexp.new(/^T(\d+)/)
+      @regexp_move    = Regexp.new("^\\#{@type}\\d{4}\\w{2}")
+      @regexp_name    = Regexp.new("^N\\#{@type}(.*)")
+      @regexp_time    = Regexp.new(/^T(\d+)/)
+      @regexp_comment = Regexp.new(/^'\*\*(.*)/)
       @flag = false
       @name = nil
     end
       @flag = false
       @name = nil
     end
@@ -85,7 +99,7 @@ module EvalGraph
         if @flag
           @times << $1.to_i
         end
         if @flag
           @times << $1.to_i
         end
-      when /^'\*\*(.*)/
+      when @regexp_comment
         if @flag
           @comments << EvalGraph::parse_comment($1)
           @flag = false
         if @flag
           @comments << EvalGraph::parse_comment($1)
           @flag = false
@@ -97,18 +111,26 @@ module EvalGraph
       end
     end
 
       end
     end
 
-    def time_values(y_max, full_time)
-      consume = full_time
+    # Return times for each move which the player played. 
+    # return[0] is the initial play_time.
+    #
+    def time_values(y_max, play_time)
+      consume = play_time
       values = []
       values = []
-      values << 1.0*y_max/full_time*consume
+      values << 1.0*y_max/play_time*consume
       @times.each do |t|
       @times.each do |t|
+        if consume == 0
+          break
+        end
         consume -= t
         consume -= t
-        values << 1.0*y_max/full_time*consume
+        if consume < 0
+          consume = 0
+        end
+        values << 1.0*y_max/play_time*consume
       end
       return values
     end
       end
       return values
     end
-
-  end
+  end # Player
 
   class Black < Player
     def name
 
   class Black < Player
     def name
@@ -120,13 +142,14 @@ module EvalGraph
     def eval_values
       moves = []
       comments.each_with_index do |c, i|
     def eval_values
       moves = []
       comments.each_with_index do |c, i|
-        moves << i*2 + 1 if c
+        moves << i*2 if c
       end
       moves.unshift 0
       [moves, comments.compact.unshift(0)]
     end
 
       end
       moves.unshift 0
       [moves, comments.compact.unshift(0)]
     end
 
-    def time_values(y_max, full_time)
+    # Return moves and times. For example, [[0,1,3], [900, 899, 898]]
+    def time_values(y_max, play_time)
       values = super
       moves = [0]
       return [moves, values] if values.size <= 1
       values = super
       moves = [0]
       return [moves, values] if values.size <= 1
@@ -138,7 +161,7 @@ module EvalGraph
       end
       return [moves, values]
     end
       end
       return [moves, values]
     end
-  end
+  end # Black
 
   class White < Player
     def name
 
   class White < Player
     def name
@@ -148,13 +171,13 @@ module EvalGraph
     def eval_values
       moves = []
       comments.each_with_index do |c, i|
     def eval_values
       moves = []
       comments.each_with_index do |c, i|
-        moves << i*2 if c
+        moves << i*2+1 if c
       end
       moves.unshift 0
       [moves, comments.compact.unshift(0)]
     end
 
       end
       moves.unshift 0
       [moves, comments.compact.unshift(0)]
     end
 
-    def time_values(y_max, full_time)
+    def time_values(y_max, play_time)
       values = super
       moves = [0]
       return [moves, values] if values.size <= 1
       values = super
       moves = [0]
       return [moves, values] if values.size <= 1
@@ -165,8 +188,8 @@ module EvalGraph
         i += 2
       end
       return [moves, values]
         i += 2
       end
       return [moves, values]
-   end
-  end
+    end
+  end # White
 
   
   def create_players
 
   
   def create_players
@@ -177,20 +200,14 @@ module EvalGraph
     return black,white
   end
   module_function :create_players
     return black,white
   end
   module_function :create_players
-end
+end # module EvalGraph
 
 
-def max_time(game_name)
-  if /.*?\+.*?\-(\d*?)\-/ =~ game_name
-    return $1.to_i
-  end
-  return 0  
-end
 
 
-def plot(csa_file, title, black, white)
+def plot(csa_file, title, black, white, a_play_time)
   width = [black.comments.size, white.comments.size].max * 2 + 1
   Gnuplot.open do |gp|
     Gnuplot::Plot.new( gp ) do |plot|
   width = [black.comments.size, white.comments.size].max * 2 + 1
   Gnuplot.open do |gp|
     Gnuplot::Plot.new( gp ) do |plot|
-      plot.terminal "svg" # or png
+      plot.terminal "svg size 800 500 fixed" # or png
       plot.output   to_svg_file(csa_file)
       
       plot.title  title
       plot.output   to_svg_file(csa_file)
       
       plot.title  title
@@ -208,7 +225,7 @@ def plot(csa_file, title, black, white)
       plot.key "left"
      
       plot.style "line 1 linewidth 5 linetype 0 linecolor rgbcolor \"red\"" 
       plot.key "left"
      
       plot.style "line 1 linewidth 5 linetype 0 linecolor rgbcolor \"red\"" 
-      plot.style "line 2 linewidth 5 linetype 0 linecolor rgbcolor \"blue\"" 
+      plot.style "line 2 linewidth 4 linetype 0 linecolor rgbcolor \"dark-green\"" 
 
       plot.data << Gnuplot::DataSet.new( black.eval_values ) do |ds|
         ds.with  = "lines ls 1"
 
       plot.data << Gnuplot::DataSet.new( black.eval_values ) do |ds|
         ds.with  = "lines ls 1"
@@ -220,29 +237,33 @@ def plot(csa_file, title, black, white)
         ds.title = white.name
       end
 
         ds.title = white.name
       end
 
-      full_time = max_time(csa_file)
-      return if full_time == 0
-
-      plot.style "line 5 linewidth 1 linetype 0 linecolor rgbcolor \"red\"" 
-      plot.style "line 6 linewidth 1 linetype 0 linecolor rgbcolor \"blue\"" 
-      plot.style "fill solid 0.25 noborder"
+      if a_play_time > 0
+        plot.style "line 5 linewidth 1 linetype 0 linecolor rgbcolor \"red\"" 
+        plot.style "line 6 linewidth 1 linetype 0 linecolor rgbcolor \"green\"" 
+        plot.style "fill solid 0.25 noborder"
 
 
-      plot.data << Gnuplot::DataSet.new( black.time_values(2000, full_time) ) do |ds|
-        ds.with  = "boxes notitle ls 5"
-      end
-      
-      plot.data << Gnuplot::DataSet.new( white.time_values(-2000, full_time) ) do |ds|
-        ds.with  = "boxes notitle ls 6"
-      end
+        plot.data << Gnuplot::DataSet.new( black.time_values(3000, a_play_time) ) do |ds|
+          ds.with  = "boxes notitle ls 5"
+        end
+        
+        plot.data << Gnuplot::DataSet.new( white.time_values(-3000, a_play_time) ) do |ds|
+          ds.with  = "boxes notitle ls 6"
+        end
+      end # if
 
     end
   end  
 end
 
 
 
     end
   end  
 end
 
 
-
-def read(lines, file_name)
+# Read kifu, a record of moves, to generate a graph file. 
+# lines are contents of the kifu.
+# file is a file name of a genrating image file.
+# original_file_name is a file name of the csa file.
+#
+def read(lines, file_name, original_file_name=nil)
   lines.map! {|l| l.strip}
   lines.map! {|l| l.strip}
+  original_file_name ||=  file_name 
   
   black,white = EvalGraph.create_players
   while l = lines.shift do
   
   black,white = EvalGraph.create_players
   while l = lines.shift do
@@ -251,7 +272,8 @@ def read(lines, file_name)
   end
   
   title = "#{file_name}" 
   end
   
   title = "#{file_name}" 
-  plot(file_name, title, black, white)
+  a_play_time = play_time(original_file_name)
+  plot(file_name, title, black, white, a_play_time)
 end
 
 
 end