Mercurial > hg > rlgallery-misc
view py/stats2.py @ 68:67bcca6e3cb1
Prevent crashes if no ttyrec files can be associated with a game.
If the postprocessing step finds no ttyrec files created between a
game's end and the previous game's end, it will no longer index an
empty list and crash.
The condition of finding no ttyrec files is still a bug that requires
investigation.
author | John "Elwin" Edwards |
---|---|
date | Sat, 16 Jan 2016 02:12:50 +0000 |
parents | 876786c55450 |
children |
line wrap: on
line source
#!/usr/bin/python3 import psycopg2 import rlgall from datetime import datetime sitename = "rlgallery.org" svgpath = rlgall.webdir timestr = datetime.utcnow().strftime("%Y-%m-%d %H:%M") dochead = """<?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="900" height="600"> """ stylesheet = """<style type="text/css"> rect.frame {{ fill:#ffffff; fill-opacity:1; stroke:#000000; stroke-width:2; stroke-opacity:1; }} rect.bar {{ fill:#{0}; fill-opacity:1; stroke:#000000; stroke-width:2; stroke-opacity:1; }} g.bar3d polygon {{ fill:#{0}; fill-opacity:1; stroke:#000000; stroke-width:1; stroke-opacity:1; }} </style> """ framerect = '<rect width="750" height="500" x="100" y="50" class="frame"/>\n' barstr = '<rect width="{0}" height="{1}" x="{2}" y="{3}" class="bar"/>\n' xllabel = '<text x="{0}" y="570" font-size="15" text-anchor="middle">{1}</text>\n' ylabel = '<text x="90" y="{0:.2f}" font-size="16" text-anchor="end">{1}</text>\n' xlabelf = '<text x="475" y="590" font-size="15" text-anchor="middle">{0}</text>\n' ltitle = '<text x="100" y="35" font-size="16" text-anchor="start">{0}</text>\n' ctitle = '<text x="475" y="34" font-size="18" text-anchor="middle">{0}</text>\n' rtitle = '<text x="850" y="35" font-size="16" text-anchor="end">{0}</text>\n' ylabelf = """<g transform="translate(100, 300)"> <g transform="rotate(-90)"> <text x="0" y="-60" font-size="16" text-anchor="middle">{0}</text> </g> </g> """ def makepolygon(coords): points = [ "{0:.2f},{1:.2f}".format(pt[0], pt[1]) for pt in coords ] pointstr = " ".join(points) return '<polygon points="{}"/>\n'.format(pointstr) def bar3d(x, w, h): ydelta = w / 2 xdelta = ydelta / 3 flowerleft = (x, 550) flowerright = (x + w, 550) fupperleft = (x, 550 - h) fupperright = (x + w, 550 - h) blowerright = (x + w + xdelta, 550 - ydelta) bupperleft = (x + xdelta, 550 - h - ydelta) bupperright = (x + w + xdelta, 550 - h - ydelta) frontface = makepolygon([flowerleft, flowerright, fupperright, fupperleft]) rightface = makepolygon([blowerright, flowerright, fupperright, bupperright]) topface = makepolygon([bupperleft, bupperright, fupperright, fupperleft]) gopen = '<g class="bar3d" clip-path="url(#framer)">\n' gclose = '</g>\n' return gopen + "".join([frontface, rightface, topface]) + gclose class SVGChart(): def __init__(self, filename): self.of = open(filename, "w", encoding="utf-8") self.of.write(dochead) def style(self, barcolor): self.of.write(stylesheet.format(barcolor)) def write(self, obj): self.of.write(obj) def close(self): self.of.write('</svg>\n') self.of.close() def ylimits(x): ll = [2, 3, 4, 5, 6, 8, 10, 15] m = 1 size = 0 while True: for i in ll: if i * m > x * 1.1: size = i lim = i * m break if size: break else: m *= 10 if size in [3, 6]: if lim == 3: divs = 3 else: divs = 6 elif size in [4, 8]: divs = 4 else: if lim == 2: divs = 2 else: divs = 5 return divs, lim def titles(l, c, r): return ltitle.format(l) + ctitle.format(c) + rtitle.format(r) def mkxlgraph(game, xldata): xlgraph = SVGChart("{0}/xl-{1}.svg".format(svgpath, game.uname)) xlgraph.style("0000ff") xlgraph.write(framerect) xlgraph.write('<clipPath id="framer">\n') xlgraph.write(framerect) xlgraph.write('</clipPath>\n') xldivs, xlmax = ylimits(max([ pt[1] for pt in xldata ])) scale = 500 / xlmax for xl, count in xldata: barx = xl * 50 + 60 barh = scale * count bary = 550 - barh if count > 0: xlgraph.write(bar3d(barx, 30, barh)) xlgraph.write(xllabel.format(barx + 15, xl)) for yl in range(xldivs + 1): labeln = int(xlmax * yl / xldivs) labelh = 550 + 8 - 500 * yl / xldivs xlgraph.write(ylabel.format(labelh, labeln)) xlgraph.write(xlabelf.format("Experience level")) xlgraph.write(ylabelf.format("# of games")) xlgraph.write(titles(sitename, game.name, timestr)) xlgraph.close() return def mkscoregraph(game, scoredata): if isinstance(game, rlgall.ARogueGame): scorewidth = 1000 else: scorewidth = 500 scoregraph = SVGChart("{0}/score-{1}.svg".format(svgpath, game.uname)) scoregraph.style("ffff00") scoregraph.write(framerect) scoregraph.write('<clipPath id="framer">\n') scoregraph.write(framerect) scoregraph.write('</clipPath>\n') scoredivs, scoremax = ylimits(max([ pt[1] for pt in scoredata ])) scale = 500 / scoremax for block, count in scoredata: n = block // scorewidth barx = n * 50 + 100 barh = scale * count bary = 550 - barh if count > 0: scoregraph.write(bar3d(barx, 50, barh)) if n % 2 == 0: scoregraph.write(xllabel.format(barx, block)) for yl in range(scoredivs + 1): labeln = int(scoremax * yl / scoredivs) labelh = 550 + 8 - 500 * yl / scoredivs scoregraph.write(ylabel.format(labelh, labeln)) scoregraph.write(xlabelf.format("Score")) scoregraph.write(ylabelf.format("# of games")) scoregraph.write(titles(sitename, game.name, timestr)) scoregraph.close() return def mkdeepgraph(game, deepdata): deepgraph = SVGChart("{0}/deep-{1}.svg".format(svgpath, game.uname)) deepgraph.style("808000") deepgraph.write(framerect) deepgraph.write('<clipPath id="framer">\n') deepgraph.write(framerect) deepgraph.write('</clipPath>\n') deepdivs, deepmax = ylimits(max([ pt[1] for pt in deepdata ])) scale = 500 / deepmax for lev, count in deepdata: barx = lev * 25 + 75 barh = scale * count bary = 550 - barh if count > 0: deepgraph.write(bar3d(barx, 25, barh)) if lev % 3 == 0: deepgraph.write(xllabel.format(barx + 12.5, lev)) for yl in range(deepdivs + 1): labeln = int(deepmax * yl / deepdivs) labelh = 550 + 8 - 500 * yl / deepdivs deepgraph.write(ylabel.format(labelh, labeln)) deepgraph.write(xlabelf.format("Deepest dungeon level")) deepgraph.write(ylabelf.format("# of games")) deepgraph.write(titles(sitename, game.name, timestr)) deepgraph.close() return for game in rlgall.gamelist: xldata = game.getXLCounts(15) deepdata = game.getDepthCounts(30) if isinstance(game, rlgall.ARogueGame): scorewidth = 1000 else: scorewidth = 500 scoredata = game.getScoreCounts(15, scorewidth) mkxlgraph(game, xldata) mkscoregraph(game, scoredata) mkdeepgraph(game, deepdata) exit()