29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
|
# File 'lib/mjai/game_stats.rb', line 29
def self.print(mjson_paths)
num_errors = 0
name_to_ranks = {}
name_to_scores = {}
name_to_kyoku_count = {}
name_to_hora_count = {}
name_to_yaku_stats = {}
name_to_dora_stats = {}
name_to_hoju_count = {}
name_to_furo_kyoku_count = {}
name_to_reach_count = {}
name_to_hora_points = {}
for path in mjson_paths
archive = Archive.load(path)
first_action = archive.raw_actions[0]
last_action = archive.raw_actions[-1]
if !last_action || last_action.type != :end_game
num_errors += 1
next
end
archive.do_action(first_action)
scores = last_action.scores
id_to_name = first_action.names
chicha_id = archive.raw_actions[1].oya.id
ranked_player_ids =
(0...4).sort_by(){ |i| [-scores[i], (i + 4 - chicha_id) % 4] }
for r in 0...4
name = id_to_name[ranked_player_ids[r]]
name_to_ranks[name] ||= []
name_to_ranks[name].push(r + 1)
end
for p in 0...4
name = id_to_name[p]
name_to_scores[name] ||= []
name_to_scores[name].push(scores[p])
end
id_to_done_reach = {}
id_to_done_furo = {}
for raw_action in archive.raw_actions
if raw_action.type == :hora
name = id_to_name[raw_action.actor.id]
name_to_hora_count[name] ||= 0
name_to_hora_count[name] += 1
name_to_hora_points[name] ||= []
name_to_hora_points[name].push(raw_action.hora_points)
for yaku, fan in raw_action.yakus
if yaku == :dora || yaku == :akadora || yaku == :uradora
name_to_dora_stats[name] ||= {}
name_to_dora_stats[name][yaku] ||= 0
name_to_dora_stats[name][yaku] += fan
next
end
name_to_yaku_stats[name] ||= {}
name_to_yaku_stats[name][yaku] ||= 0
name_to_yaku_stats[name][yaku] += 1
end
if raw_action.actor.id != raw_action.target.id
target_name = id_to_name[raw_action.target.id]
name_to_hoju_count[target_name] ||= 0
name_to_hoju_count[target_name] += 1
end
end
if raw_action.type == :reach_accepted
id_to_done_reach[raw_action.actor.id] = true
end
if raw_action.type == :pon
id_to_done_furo[raw_action.actor.id] = true
end
if raw_action.type == :chi
id_to_done_furo[raw_action.actor.id] = true
end
if raw_action.type == :daiminkan
id_to_done_furo[raw_action.actor.id] = true
end
if raw_action.type == :end_kyoku
for p in 0...4
name = id_to_name[p]
if id_to_done_furo[p]
name_to_furo_kyoku_count[name] ||= 0
name_to_furo_kyoku_count[name] += 1
end
if id_to_done_reach[p]
name_to_reach_count[name] ||= 0
name_to_reach_count[name] += 1
end
name_to_kyoku_count[name] ||= 0
name_to_kyoku_count[name] += 1
end
id_to_done_furo = {}
id_to_done_reach = {}
end
end
end
if num_errors > 0
puts("errors: %d / %d" % [num_errors, mjson_paths.size])
end
puts("Ranks:")
for name, ranks in name_to_ranks.sort
rank_conf_interval = ConfidenceInterval.calculate(ranks, :min => 1.0, :max => 4.0)
puts(" %s: %.3f [%.3f, %.3f]" % [
name,
ranks.inject(0, :+).to_f() / ranks.size,
rank_conf_interval[0],
rank_conf_interval[1],
])
end
puts("Scores:")
for name, scores in name_to_scores.sort
puts(" %s: %d" % [
name,
scores.inject(0, :+).to_i() / scores.size,
])
end
puts("Hora rates:")
for name, hora_count in name_to_hora_count.sort
puts(" %s: %.1f%%" % [
name,
100.0 * hora_count / name_to_kyoku_count[name]
])
end
puts("Hoju rates:")
for name, hoju_count in name_to_hoju_count.sort
puts(" %s: %.1f%%" % [
name,
100.0 * hoju_count / name_to_kyoku_count[name]
])
end
puts("Furo rates:")
for name, furo_kyoku_count in name_to_furo_kyoku_count.sort
puts(" %s: %.1f%%" % [
name,
100.0 * furo_kyoku_count / name_to_kyoku_count[name]
])
end
puts("Reach rates:")
for name, reach_count in name_to_reach_count.sort
puts(" %s: %.1f%%" % [
name,
100.0 * reach_count / name_to_kyoku_count[name]
])
end
puts("Average hora points:")
for name, hora_points in name_to_hora_points.sort
puts(" %s: %d" % [
name,
hora_points.inject(0, :+).to_i() / hora_points.size,
])
end
puts("Yaku stats:")
for name, yaku_stats in name_to_yaku_stats.sort
hora_count = name_to_hora_count[name]
puts(" %s (%d horas):" % [name, hora_count])
for yaku, count in yaku_stats.sort_by{|yaku, count| -count}
yaku_name = YAKU_JA_NAMES[yaku]
puts(" %s: %d (%.1f%%)" % [yaku_name, count, 100.0 * count / hora_count])
end
end
puts("Dora stats:")
for name, dora_stats in name_to_dora_stats.sort
hora_count = name_to_hora_count[name]
puts(" %s (%d horas):" % [name, hora_count])
for dora, count in dora_stats.sort_by{|dora, count| -count}
dora_name = YAKU_JA_NAMES[dora]
puts(" %s: %d (%.3f/hora)" % [dora_name, count, count.to_f() / hora_count])
end
end
end
|