1#!/usr/bin/env python 2# -*- mode: python; coding: utf-8; -*- 3# ---------------------------------------------------------------------------## 4# 5# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer 6# Copyright (C) 2003 Mt. Hood Playing Card Co. 7# Copyright (C) 2005-2009 Skomoroh 8# 9# This program is free software: you can redistribute it and/or modify 10# it under the terms of the GNU General Public License as published by 11# the Free Software Foundation, either version 3 of the License, or 12# (at your option) any later version. 13# 14# This program is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17# GNU General Public License for more details. 18# 19# You should have received a copy of the GNU General Public License 20# along with this program. If not, see <http://www.gnu.org/licenses/>. 21# 22# ---------------------------------------------------------------------------## 23 24import time 25 26from pysollib.gamedb import GI 27from pysollib.mfxutil import format_time 28from pysollib.mygettext import _ 29 30from six.moves import range 31 32# ************************************************************************ 33# * 34# ************************************************************************ 35 36 37class PysolStatsFormatter: 38 39 def getStatHeader(self): 40 return (_("Game"), 41 _("Played"), 42 _("Won"), 43 _("Lost"), 44 _('Playing time'), 45 _('Moves'), 46 _("% won")) 47 48 def getStatResults(self, player, sort_by='name'): 49 app = self.app 50 # 51 sort_functions = { 52 'name': app.getGamesIdSortedByName, 53 'played': app.getGamesIdSortedByPlayed, 54 'won': app.getGamesIdSortedByWon, 55 'lost': app.getGamesIdSortedByLost, 56 'time': app.getGamesIdSortedByPlayingTime, 57 'moves': app.getGamesIdSortedByMoves, 58 'percent': app.getGamesIdSortedByPercent, 59 } 60 sort_func = sort_functions[sort_by] 61 g = sort_func(player=player) 62 t_won, tlost, tgames, ttime, tmoves = 0, 0, 0, 0, 0 63 for id in g: 64 won, lost, time, moves = app.stats.getFullStats(player, id) 65 tot = won + lost 66 if tot > 0 or id == app.game.id: 67 # yield only played games 68 name = app.getGameTitleName(id) 69 t_won, tlost = t_won + won, tlost + lost 70 ttime, tmoves = ttime+time, tmoves+moves 71 perc = "%.1f" % (100.0 * won / tot) if tot > 0 else '0.0' 72 t = format_time(time) 73 m = str(round(moves, 1)) 74 yield [name, won+lost, won, lost, t, m, perc, id] 75 tgames += 1 76 # summary 77 won, lost = t_won, tlost 78 if won + lost > 0: 79 if won > 0: 80 time = format_time(ttime/tgames) 81 moves = round(tmoves/tgames, 1) 82 else: 83 time = format_time(0) 84 moves = 0 85 perc = "%.1f" % (100.0*won/(won+lost)) 86 else: 87 perc = "0.0" 88 self.total_games = len(g) 89 self.played_games = tgames 90 self.won_games = won 91 self.lost_games = lost 92 self.avrg_time = time 93 self.avrg_moves = moves 94 self.percent = perc 95 # yield (_("Total (%d out of %d games)") % (tgames, len(g)), 96 # won+lost, won, lost, time, moves, perc, '') 97 98 def getStatSummary(self): 99 return self.total_games, \ 100 self.played_games, \ 101 self.won_games, \ 102 self.lost_games, \ 103 self.avrg_time, \ 104 self.avrg_moves, \ 105 self.percent 106 107 def getLogHeader(self): 108 return _("Game"), _("Game number"), _("Started at"), _("Status") 109 110 def getLogResults(self, player, prev_games): 111 t_won, tlost = 0, 0 112 for pg in prev_games: 113 if not isinstance(pg, tuple): 114 continue 115 if len(pg) == 5: 116 pg = pg + ("", None, None, 1) 117 elif len(pg) == 7: 118 pg = pg + (None, 1) 119 elif len(pg) == 8: 120 pg = pg + (1,) 121 if len(pg) < 8: 122 continue 123 gameid = pg[0] 124 if not isinstance(gameid, int): 125 continue 126 gi = self.app.getGameInfo(gameid) 127 if not gi: 128 gi = self.app.getGameInfo(GI.PROTECTED_GAMES.get(gameid)) 129 if gi: 130 name = gi.name 131 else: 132 name = _("** UNKNOWN %d **") % gameid 133 f = pg[1] 134 if len(f) == 16: 135 # gamenumber = "%s-%s-%s-%s" % \ 136 # (f[0:4], f[4:8], f[8:12], f[12:16]) 137 gamenumber = "%s-%s-%s" % (f[4:8], f[8:12], f[12:16]) 138 elif len(f) <= 20: 139 gamenumber = f 140 else: 141 gamenumber = _("** ERROR **") 142 date = time.strftime("%Y-%m-%d %H:%M", time.localtime(pg[3])) 143 if pg[2] >= 0: 144 won = pg[2] > 0 145 t_won, tlost = t_won + won, tlost + (1 - won) 146 status = "*error*" 147 if -2 <= pg[2] <= 2: 148 status = (_("Loaded"), _("Not won"), _("Lost"), 149 _("Won"), _("Perfect"))[pg[2]+2] 150 # writer.plog(name, gamenumber, date, status, gameid=gameid, 151 # won=pg[2]) 152 yield [name, gamenumber, date, status, pg[2], gameid] 153 154 # 155 # 156 # 157 158 def writeStats(self, player, sort_by='name'): 159 pass 160 161 def writeFullLog(self, player): 162 pass 163 164 def writeSessionLog(self, player): 165 pass 166 167 168class FileStatsFormatter(PysolStatsFormatter): 169 170 def __init__(self, app, file): 171 self.app = app 172 self.file = file 173 174 def p(self, s): 175 self.file.write(s) 176 177 def nl(self, count=1): 178 self.p("\n" * count) 179 180 def pheader(self, s): 181 self.p(s) 182 183 def pstats(self, *args, **kwargs): 184 s = "%-30s %7s %7s %7s %7s %7s %7s\n" % args 185 self.p(s) 186 187 def plog(self, gamename, gamenumber, date, status, gameid=-1, won=-1): 188 self.p("%-25s %-20s %17s %s\n" % 189 (gamename, gamenumber, date, status)) 190 191 def writeHeader(self, header, pagewidth=72): 192 date = time.ctime(time.time()) 193 date = time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time())) 194 blanks = max(pagewidth - len(header) - len(date), 1) 195 self.pheader(header + " "*blanks + date + "\n") 196 self.pheader("-" * pagewidth + "\n") 197 self.pheader("\n") 198 199 def writeStats(self, player, sort_by='name'): 200 if player is None: 201 player = _('Demo') 202 header = _("Statistics for %(player)s") % {'player': player} 203 self.writeHeader(header, 62) 204 header = self.getStatHeader() 205 self.pstats(*header) 206 self.nl() 207 for result in self.getStatResults(player, sort_by): 208 gameid = result.pop() 209 self.pstats(gameid=gameid, *result) 210 self.nl() 211 total, played, won, lost, time, moves, perc = self.getStatSummary() 212 self.pstats(_("Total (%(played)d out of %(total)d games)") % 213 {'played': played, 'total': total}, 214 won+lost, won, lost, time, moves, perc) 215 self.nl(2) 216 return played 217 218 def writeLog(self, player, header, prev_games): 219 if not player or not prev_games: 220 return 0 221 self.writeHeader(header, 71) 222 header = self.getLogHeader() 223 self.plog(*header) 224 self.nl() 225 for result in self.getLogResults(player, prev_games): 226 gameid = result.pop() 227 won = result.pop() 228 self.plog(gameid=gameid, won=won, *result) 229 self.nl(2) 230 return 1 231 232 def writeFullLog(self, player): 233 if player is None: 234 player = _('Demo') 235 header = _("Full log for %(player)s") % {'player': player} 236 prev_games = self.app.stats.prev_games.get(player) 237 return self.writeLog(player, header, prev_games) 238 239 def writeSessionLog(self, player): 240 if player is None: 241 player = _('Demo') 242 header = _("Session log for %(player)s") % {'player': player} 243 prev_games = self.app.stats.session_games.get(player) 244 return self.writeLog(player, header, prev_games) 245 246 247# ************************************************************************ 248# * 249# ************************************************************************ 250 251class ProgressionFormatter: 252 253 def __init__(self, app, player, gameid): 254 255 all_results = {} # key: (year, month, day); value: [played, won] 256 self.all_results = all_results 257 game_results = {} 258 self.game_results = game_results 259 games = app.stats.prev_games.get(player) 260 if not games: 261 return 262 for g in games: 263 id = g[0] 264 status = g[2] 265 start_time = g[3] 266 t = time.localtime(start_time)[:3] 267 if t not in all_results: 268 all_results[t] = [0, 0] 269 all_results[t][0] += 1 270 if status > 0: 271 all_results[t][1] += 1 272 if id == gameid: 273 if t not in game_results: 274 game_results[t] = [0, 0] 275 game_results[t][0] += 1 276 if status > 0: 277 game_results[t][1] += 1 278 # from pprint import pprint; pprint(all_results) 279 280 def norm_time(self, t): 281 if len(t) == 3: 282 t = list(t)+[0, 0, 0, -1, -1, -1] 283 return list(time.localtime(time.mktime(tuple(t)))) 284 285 def getResults(self, interval, all_games=True): 286 if all_games: 287 results = self.all_results 288 else: 289 results = self.game_results 290 t = list(time.localtime()) 291 if interval == 'week': 292 t[2] -= 7 293 lt = self.norm_time(t) 294 marks = None 295 delta = 1 296 format = '%d.%m' 297 elif interval == 'month': 298 tt = t[:] 299 t[1] -= 1 300 lt = self.norm_time(t) 301 marks = [lt[:3], tt[:3]] 302 tt[2] -= 10 303 marks.append(self.norm_time(tt)[:3]) 304 tt[2] -= 10 305 marks.append(self.norm_time(tt)[:3]) 306 delta = 1 307 format = '%d.%m' 308 elif interval == 'year': 309 tt = t[:] 310 t[0] -= 1 311 lt = self.norm_time(t) 312 marks = [lt[:3], tt[:3]] 313 for i in range(5): 314 tt[1] -= 2 315 marks.append(self.norm_time(tt)[:3]) 316 delta = 7 317 format = '%d.%m.%y' 318 else: # all 319 tt = t[:] 320 tt[1] -= 1 321 tt = self.norm_time(tt) 322 if results: 323 lt = self.norm_time(min(results.keys())) 324 lt = min(lt, tt) # min 1 month 325 else: 326 lt = tt 327 dt = time.time()-time.mktime(tuple(lt)) 328 if dt > 63072000: # 2 years 329 d = 6 330 elif dt > 31536000: # 1 year 331 d = 4 332 elif dt > 10512000: # 4 month 333 d = 2 334 else: 335 d = 1 336 marks = [lt[:3], t[:3]] 337 while t > lt: 338 t[1] -= d 339 t = self.norm_time(t) 340 marks.append(t[:3]) 341 delta = 7 342 format = '%d.%m.%y' 343 344 res = [] 345 ct = list(time.localtime()) 346 while lt <= ct: 347 # assert type(lt) is type(ct) 348 played = 0 349 won = 0 350 text = None 351 for i in range(delta): 352 if (not marks) or ct[:3] in marks: 353 text = time.strftime(format, tuple(ct)) 354 t = tuple(ct[:3]) 355 if t in results: 356 played += results[t][0] 357 won += results[t][1] 358 ct[2] -= 1 359 ct = self.norm_time(ct) 360 res.append((text, played, won)) 361 res.reverse() 362 # from pprint import pprint; pprint(res) 363 return res 364