OSDN Git Service

The utility programs have been moved under 'shogi-server'
[shogi-server/shogi-server.git] / utils / players_graph.rb
1 #!/usr/bin/ruby
2 #    This generates graphs of evaluation values from comments in CSA files.
3 #    Ruby libraries that are required: 
4 #      - RubyGems: http://rubyforge.org/projects/rubygems/
5 #      - rgplot:   http://rubyforge.org/projects/rgplot/
6 #    OS librariles that is required:
7 #      - Gnuplot:  http://www.gnuplot.info/
8 #                  On Debian, $ sudo apt-get install gnuplot
9 #    
10 #    Copyright (C) 2008  Daigo Moriwaki <daigo@debian.org>
11 #
12 #    Version: $Id$
13 #
14 #    This program is free software; you can redistribute it and/or modify
15 #    it under the terms of the GNU General Public License as published by
16 #    the Free Software Foundation; either version 2 of the License, or
17 #    (at your option) any later version.
18 #
19 #    This program is distributed in the hope that it will be useful,
20 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
21 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 #    GNU General Public License for more details.
23 #
24 #    You should have received a copy of the GNU General Public License
25 #    along with this program; if not, write to the Free Software
26 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
27
28 require 'pathname'
29 require 'getoptlong'
30 require 'yaml'
31 require 'date'
32 require 'set'
33 require 'rubygems'
34 require 'gnuplot'
35
36 $players = {}
37
38 class Format
39   attr_reader :ext, :size
40   def initialize(root)
41     @root = root
42     @size = "1,1"
43   end
44
45   def apply(plot)
46     plot.terminal @ext
47     plot.size     @size
48   end
49 end
50
51 class LargeFormat < Format
52   def initialize(root)
53     super
54   end
55
56   def apply(plot)
57     super
58     plot.format 'x "%y/%m/%d"'
59     plot.ytics  "100"
60     plot.mytics "5"
61   end
62 end
63
64 class LargePngFormat < LargeFormat
65   def initialize(root)
66     super
67     @ext = "png"
68   end
69
70   def to_image_file(name)
71     return File.join(@root, "#{name}-large.#{ext}")
72   end
73 end
74
75 class SmallPngFormat < Format
76   def initialize(root)
77     super
78     @ext = "png"
79     @size = "0.4,0.4"
80   end
81
82   def to_image_file(name)
83     return File.join(@root, "#{name}-small.#{ext}")
84   end
85
86   def apply(plot)
87     super
88     plot.format 'x "%b"'
89     plot.ytics  "200"
90     plot.mytics "2"
91   end
92 end
93
94 class SvgFormat < LargeFormat
95   def initialize(root)
96     super
97     @ext = "svg"
98   end
99
100   def to_image_file(name)
101     return File.join(@root, "#{name}.#{ext}")
102   end
103 end
104
105 def plot(format, name, dates, rates, rdates, rrates)
106   Gnuplot.open do |gp|
107     Gnuplot::Plot.new( gp ) do |plot|
108       format.apply(plot)
109       plot.title   name
110       plot.output format.to_image_file(name)
111       
112       plot.size    "ratio #{1/1.618}"
113       plot.xlabel  "Date"
114       plot.ylabel  "Rate"
115       plot.xdata   "time"
116       plot.timefmt '"%Y-%m-%d"'
117       plot.xrange  "[\"%s\":\"%s\"]" % 
118                     [dates.first.strftime("%Y-%m-%d"),
119                      dates.last.strftime("%Y-%m-%d")]
120       ymin = ((rates + rrates).min/50) * 50
121       ymax = ((rates + rrates).max/50 + 1) * 50
122       plot.yrange "[%s:%s]" % [ymin, ymax]
123       plot.grid
124       data = []
125       data << Gnuplot::DataSet.new([dates, rates]) do |ds|
126                 ds.using = "1:2"
127                 ds.with  = "lines"
128                 ds.title = "original"
129               end
130       if !rdates.empty?
131         data << Gnuplot::DataSet.new([rdates, rrates]) do |ds|
132                   ds.using = "1:2"
133                   ds.with  = "lines"
134                   ds.title = "relative (rate24)"
135                 end
136       end
137       plot.data = data
138     end
139   end  
140 end
141
142 def load_file(file_name)
143   if /^.*-(\d{8}).yaml$/ =~ file_name
144     date = Date::parse($1)
145   else
146     return
147   end
148   db = YAML::load_file(file_name)
149   return unless db['players'][0]
150   db['players'][0].each do |name, hash|
151     $players[name] ||= {}
152     $players[name][date] = hash['rate'].to_i
153   end
154 end
155
156 if $0 == __FILE__
157   def usage
158     puts "Usage: #{$0} [--output-dir dir] <players_yaml_files>..."
159     puts "Options:"
160     puts "  --output-dir dir  Images will be located in the dir."
161     exit 1
162   end
163
164   usage if ARGV.empty?
165
166   parser = GetoptLong.new
167   parser.set_options(['--output-dir', '-o', GetoptLong::REQUIRED_ARGUMENT])
168   begin
169     parser.each_option do |name, arg|
170       eval "$OPT_#{name.sub(/^--/, '').gsub(/-/, '_').upcase} = '#{arg}'"
171     end
172   rescue
173     usage
174   end
175   
176   while file = ARGV.shift
177     load_file(file)
178   end
179   
180   formats = [LargePngFormat.new($OPT_OUTPUT_DIR),
181              SmallPngFormat.new($OPT_OUTPUT_DIR),
182              SvgFormat.new($OPT_OUTPUT_DIR)]
183
184   $players.each do |name, hash|
185     dates, rates = hash.sort.transpose
186     rdates = dates.find_all do |date| 
187       $players["YSS+707d4f98d9d2620cdaab58f19d02a2e4"] &&
188       $players["YSS+707d4f98d9d2620cdaab58f19d02a2e4"][date] 
189     end
190     rrates = rdates.map do |date|
191       2300 - $players["YSS+707d4f98d9d2620cdaab58f19d02a2e4"][date] + hash[date]
192     end
193     formats.each do |format|
194       plot(format, name, dates, rates, rdates, rrates)
195     end
196   end
197 end
198