OSDN Git Service

Added a tool to investicate statistics of csa kifu files
[shogi-server/shogi-server.git] / utils / statistics.rb
1 #!/usr/bin/ruby1.9.1
2 # This program filters CSA files. For example, if you want only CSA files
3 # played by GPS vs Bonanza,
4 #   $ ./csa-filter.rb --players gps-l,bonanza some_dir
5 # you will see such files under the some_dir directory.
6 #
7 # Author::    Daigo Moriwaki <daigo at debian dot org>
8 # Copyright:: Copyright (C) 2006-2008  Daigo Moriwaki <daigo at debian dot org>
9 #
10 # $Id$
11 #
12 #--
13 # This program is free software; you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation; either version 2 of the License, or
16 # (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 # GNU General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
26 #++
27
28 $:.unshift File.dirname(__FILE__)
29 require 'csa-filter'
30 require 'set'
31
32 class Monthly
33   def initialize
34     @games = Hash.new {|hash,key| hash[key] = 0}
35     @players = Hash.new {|hash,key| hash[key] = Set.new}
36   end
37
38   def add(csa)
39     st = csa.start_time
40     month = st.strftime("%Y%m")
41
42     @games[month] += 1
43
44     [csa.black_id, csa.white_id].each do |player|
45       @players[month].add(player)
46     end
47   end
48
49   def print
50     puts "YYYYMM\t#games\t#players"
51     @games.sort {|a,b| a[0] <=> b[0]}.each do |key,value|
52       puts "%s\t% 6d\t% 2d" % [key, value, @players[key].size]
53     end
54   end
55 end
56
57 class Values
58   def initialize
59     @v = []
60   end
61
62   def add(value)
63     case value
64     when Array 
65      @v.concat value
66     else
67       @v << value
68     end
69   end
70
71   def print(file)
72     total = @v.inject(0){|sum, item| sum+item}
73     avg   = 1.0*total/@v.size
74     puts "avg: %f sec (size: %d)" % [avg, @v.size]
75
76     File.open(file, "w") do |f|
77       @v.each {|v| f.puts v}
78     end
79   end
80 end
81
82 class State
83   def initialize
84     @hash = Hash.new {|hash,key| hash[key] = 0}
85   end
86
87   def add(value)
88     if value.nil? || value.empty?
89       value = "error"
90     end
91     @hash[value] += 1
92   end
93
94   def print
95     puts "status\t#games"
96     @hash.sort {|a,b| b[1] <=> a[1]}.each do |key, value|
97       puts "%s\t% 6d" % [key, value]
98     end
99   end
100 end
101
102 $monthly  = Monthly.new
103 $gametime = Values.new
104 $movetime = Values.new
105 $moves    = Values.new
106 $states   = State.new
107
108 def do_file(file)
109   $OPT_REPEAT -= 1 if $OPT_REPEAT > 0
110   csa = CsaFileReader.new(file)
111
112   # Want to see complete games
113   $states.add csa.state
114   return unless csa.state == "toryo"
115
116   # See games between 2008/03 to 2009/07
117   return if csa.start_time <  Time.parse("2008/03/01") ||
118             csa.start_time >= Time.parse("2009/08/01")
119
120   # Process monthly
121   $monthly.add(csa)
122
123   # Process gametime
124   duration = (csa.end_time - csa.start_time).to_i
125   if duration > 2200
126     $stderr.puts "Too long game: #{file}"
127     return
128   end
129   $gametime.add duration.to_i
130
131   # Process movetime
132   values = csa.movetimes
133   $movetime.add values
134
135   #Process moves
136   $moves.add values.size
137
138 rescue => ex
139   $stderr.puts "ERROR: %s" % [file]
140   throw ex
141 end
142
143 if $0 == __FILE__
144   def usage
145     puts "Usage: #{$0} [OPTIONS] dir [...]"
146     puts "Options:"
147     exit 1
148   end
149
150   usage if ARGV.empty?
151
152   parser = GetoptLong.new(
153              ['--repeat', '-n', GetoptLong::REQUIRED_ARGUMENT]
154            )
155   begin
156     parser.each_option do |name, arg|
157       eval "$OPT_#{name.sub(/^--/, '').gsub(/-/, '_').upcase} = '#{arg}'"
158     end
159   rescue
160     usage
161   end
162
163   $OPT_REPEAT = $OPT_REPEAT.to_i
164   if $OPT_REPEAT == 0
165     $OPT_REPEAT = -1
166   end
167
168   while (cmd = ARGV.shift)
169
170     if FileTest.directory?(cmd)
171       Dir.glob(File.join(cmd, "**", "*.csa")).each do |file|
172         break if $OPT_REPEAT == 0
173         do_file(file)
174       end
175     elsif FileTest.file?(cmd)
176       break if $OPT_REPEAT == 0
177       do_file(cmd)
178     else
179       throw "Unknown file or directory: #{cmd}"
180     end
181
182     puts "States"
183     puts "------"
184     $states.print
185     puts
186     puts "=== Toryo Games ==="
187     puts
188     puts "Montly"
189     puts "------"
190     $monthly.print
191     puts
192     puts "Play Time"
193     puts "---------"
194     $gametime.print("gametime.dat")
195     puts
196     puts "Move Time"
197     puts "---------"
198     $movetime.print("movetime.dat")
199     puts
200     puts "Moves"
201     puts "-----"
202     $moves.print("moves.dat")
203   end
204 end
205