OSDN Git Service

The utility programs have been moved under 'shogi-server'
authorbeatles <beatles@b8c68f68-1e22-0410-b08e-880e1f8202b4>
Fri, 16 May 2008 14:41:34 +0000 (14:41 +0000)
committerbeatles <beatles@b8c68f68-1e22-0410-b08e-880e1f8202b4>
Fri, 16 May 2008 14:41:34 +0000 (14:41 +0000)
utils/eval_graph.rb [new file with mode: 0755]
utils/players_graph.rb [new file with mode: 0755]

diff --git a/utils/eval_graph.rb b/utils/eval_graph.rb
new file mode 100755 (executable)
index 0000000..8f212f6
--- /dev/null
@@ -0,0 +1,218 @@
+#!/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>
+#
+#    Version: $Id$
+#
+#    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.
+#
+#    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 'rubygems'
+require 'gnuplot'
+
+def to_svg_file(csa_file)
+  "#{csa_file}.svg"
+end
+
+def reformat_svg(str)
+  str.gsub(%r!<svg.*?>!m, <<-END) 
+                <svg viewBox="0 0 800 600" 
+                                             xmlns="http://www.w3.org/2000/svg" 
+                                                               xmlns:xlink="http://www.w3.org/1999/xlink">
+                END
+end
+
+module EvalGraph
+  def parse_comment(str)
+    return nil unless str
+    str.strip!
+    items = str.split(" ")
+    if items.size > 0
+      return items[0]
+    else
+      return nil
+    end
+  end
+  module_function :parse_comment
+  
+  class Player
+    attr_accessor :theOther
+    attr_reader   :name, :comments, :start_time
+    
+    def initialize(type)
+                       @comments = []
+      @type = type
+      @regexp_move = Regexp.new("^\\#{@type}\\d{4}\\w{2}")
+      @regexp_name = Regexp.new("^N\\#{@type}(.*)")
+      @flag = false
+      @name = nil
+    end
+
+    def reset
+      if @flag
+        @comments << nil
+      end
+      @flag = false
+    end
+
+    def <<(comment)
+      case comment
+      when @regexp_move
+        @flag = true
+        @theOther.reset
+      when /^'\*\*(.*)/
+        if @flag
+          @comments << EvalGraph::parse_comment($1)
+          @flag = false
+        end
+      when @regexp_name
+        @name = $1
+      when /\$START_TIME:(.*)/
+        @start_time = $1
+      end
+    end
+
+  end
+
+  class Black < Player
+    def name
+      @name ? "#{@name} (B)" : "black"
+    end
+
+    # Gluplot can not show nil vlaues so that a return value has to contain
+    # [[0], [0]] at least.
+    def eval_values
+      moves = []
+      comments.each_with_index do |c, i|
+        moves << i*2 + 1 if c
+      end
+      moves.unshift 0
+      [moves, comments.compact.unshift(0)]
+    end
+  end
+
+  class White < Player
+    def name
+      @name ? "#{@name} (W)" : "white"
+    end
+
+    def eval_values
+      moves = []
+      comments.each_with_index do |c, i|
+        moves << i*2 if c
+      end
+      moves.unshift 0
+      [moves, comments.compact.unshift(0)]
+    end
+  end
+
+  
+  def create_players
+    black = Black.new("+")
+    white = White.new("-")
+    black.theOther = white
+    white.theOther = black
+    return black,white
+  end
+  module_function :create_players
+end
+
+
+def plot(csa_file, title, black, white)
+  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.output   to_svg_file(csa_file)
+      
+      plot.title  title
+      plot.size   "ratio #{1/1.618}"
+      plot.xlabel "Moves"
+      plot.ylabel "Evaluation Value"
+      plot.xrange "[0:#{width}]"
+      plot.yrange "[-3000:3000]"
+      plot.xtics  "20"
+      plot.mxtics "2"
+      plot.ytics  %Q!("2000" 2000, "-2000" -2000)!
+      plot.xzeroaxis "lt -1"
+      plot.grid
+      plot.size   "0.9,0.9"
+      plot.key "left"
+     
+      plot.data << Gnuplot::DataSet.new( black.eval_values ) do |ds|
+        ds.with  = "lines"
+        ds.title = black.name
+      end
+      
+      plot.data << Gnuplot::DataSet.new( white.eval_values ) do |ds|
+        ds.with  = "lines"
+        ds.title = white.name
+      end
+      
+    end
+  end  
+end
+
+
+
+def read(lines, file_name)
+  lines.map! {|l| l.strip}
+  
+  black,white = EvalGraph.create_players
+  while l = lines.shift do
+    black << l
+    white << l
+  end
+  
+  title = "#{file_name}" 
+  plot(file_name, title, black, white)
+end
+
+
+if $0 == __FILE__
+  def usage
+    puts "Usage: #{$0} [--update] <csa_files>..."
+    puts "Options:"
+    puts "  --update        Update .svg files if exist."
+    exit 1
+  end
+
+  usage if ARGV.empty?
+
+  parser = GetoptLong.new
+  parser.set_options(['--update', GetoptLong::NO_ARGUMENT])
+  begin
+    parser.each_option do |name, arg|
+      eval "$OPT_#{name.sub(/^--/, '').gsub(/-/, '_').upcase} = '#{arg}'"
+    end
+  rescue
+    usage
+  end
+  
+  while file = ARGV.shift
+    next if !$OPT_UPDATE && File.exists?(to_svg_file(file))
+    read(Pathname.new(file).readlines, file)
+    str = reformat_svg(Pathname.new(to_svg_file(file)).read)
+    open(to_svg_file(file),"w+") {|f| f << str}
+  end
+end
diff --git a/utils/players_graph.rb b/utils/players_graph.rb
new file mode 100755 (executable)
index 0000000..0057851
--- /dev/null
@@ -0,0 +1,198 @@
+#!/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
+#    
+#    Copyright (C) 2008  Daigo Moriwaki <daigo@debian.org>
+#
+#    Version: $Id$
+#
+#    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.
+#
+#    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 'yaml'
+require 'date'
+require 'set'
+require 'rubygems'
+require 'gnuplot'
+
+$players = {}
+
+class Format
+  attr_reader :ext, :size
+  def initialize(root)
+    @root = root
+    @size = "1,1"
+  end
+
+  def apply(plot)
+    plot.terminal @ext
+    plot.size     @size
+  end
+end
+
+class LargeFormat < Format
+  def initialize(root)
+    super
+  end
+
+  def apply(plot)
+    super
+    plot.format 'x "%y/%m/%d"'
+    plot.ytics  "100"
+    plot.mytics "5"
+  end
+end
+
+class LargePngFormat < LargeFormat
+  def initialize(root)
+    super
+    @ext = "png"
+  end
+
+  def to_image_file(name)
+    return File.join(@root, "#{name}-large.#{ext}")
+  end
+end
+
+class SmallPngFormat < Format
+  def initialize(root)
+    super
+    @ext = "png"
+    @size = "0.4,0.4"
+  end
+
+  def to_image_file(name)
+    return File.join(@root, "#{name}-small.#{ext}")
+  end
+
+  def apply(plot)
+    super
+    plot.format 'x "%b"'
+    plot.ytics  "200"
+    plot.mytics "2"
+  end
+end
+
+class SvgFormat < LargeFormat
+  def initialize(root)
+    super
+    @ext = "svg"
+  end
+
+  def to_image_file(name)
+    return File.join(@root, "#{name}.#{ext}")
+  end
+end
+
+def plot(format, name, dates, rates, rdates, rrates)
+  Gnuplot.open do |gp|
+    Gnuplot::Plot.new( gp ) do |plot|
+      format.apply(plot)
+      plot.title   name
+      plot.output format.to_image_file(name)
+      
+      plot.size    "ratio #{1/1.618}"
+      plot.xlabel  "Date"
+      plot.ylabel  "Rate"
+      plot.xdata   "time"
+      plot.timefmt '"%Y-%m-%d"'
+      plot.xrange  "[\"%s\":\"%s\"]" % 
+                    [dates.first.strftime("%Y-%m-%d"),
+                     dates.last.strftime("%Y-%m-%d")]
+      ymin = ((rates + rrates).min/50) * 50
+      ymax = ((rates + rrates).max/50 + 1) * 50
+      plot.yrange "[%s:%s]" % [ymin, ymax]
+      plot.grid
+      data = []
+      data << Gnuplot::DataSet.new([dates, rates]) do |ds|
+                ds.using = "1:2"
+                ds.with  = "lines"
+                ds.title = "original"
+              end
+      if !rdates.empty?
+        data << Gnuplot::DataSet.new([rdates, rrates]) do |ds|
+                  ds.using = "1:2"
+                  ds.with  = "lines"
+                  ds.title = "relative (rate24)"
+                end
+      end
+      plot.data = data
+    end
+  end  
+end
+
+def load_file(file_name)
+  if /^.*-(\d{8}).yaml$/ =~ file_name
+    date = Date::parse($1)
+  else
+    return
+  end
+  db = YAML::load_file(file_name)
+  return unless db['players'][0]
+  db['players'][0].each do |name, hash|
+    $players[name] ||= {}
+    $players[name][date] = hash['rate'].to_i
+  end
+end
+
+if $0 == __FILE__
+  def usage
+    puts "Usage: #{$0} [--output-dir dir] <players_yaml_files>..."
+    puts "Options:"
+    puts "  --output-dir dir  Images will be located in the dir."
+    exit 1
+  end
+
+  usage if ARGV.empty?
+
+  parser = GetoptLong.new
+  parser.set_options(['--output-dir', '-o', GetoptLong::REQUIRED_ARGUMENT])
+  begin
+    parser.each_option do |name, arg|
+      eval "$OPT_#{name.sub(/^--/, '').gsub(/-/, '_').upcase} = '#{arg}'"
+    end
+  rescue
+    usage
+  end
+  
+  while file = ARGV.shift
+    load_file(file)
+  end
+  
+  formats = [LargePngFormat.new($OPT_OUTPUT_DIR),
+             SmallPngFormat.new($OPT_OUTPUT_DIR),
+             SvgFormat.new($OPT_OUTPUT_DIR)]
+
+  $players.each do |name, hash|
+    dates, rates = hash.sort.transpose
+    rdates = dates.find_all do |date| 
+      $players["YSS+707d4f98d9d2620cdaab58f19d02a2e4"] &&
+      $players["YSS+707d4f98d9d2620cdaab58f19d02a2e4"][date] 
+    end
+    rrates = rdates.map do |date|
+      2300 - $players["YSS+707d4f98d9d2620cdaab58f19d02a2e4"][date] + hash[date]
+    end
+    formats.each do |format|
+      plot(format, name, dates, rates, rdates, rrates)
+    end
+  end
+end
+