2014-01-10 07:15:39 -05:00
|
|
|
#!/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;
|
2014-01-10 12:00:37 -05:00
|
|
|
stroke-width:2;
|
2014-01-10 07:15:39 -05:00
|
|
|
stroke-opacity:1;
|
|
|
|
|
}}
|
|
|
|
|
rect.bar {{
|
|
|
|
|
fill:#{0};
|
|
|
|
|
fill-opacity:1;
|
|
|
|
|
stroke:#000000;
|
|
|
|
|
stroke-width:2;
|
|
|
|
|
stroke-opacity:1;
|
|
|
|
|
}}
|
2014-05-26 19:50:02 -07:00
|
|
|
g.bar3d polygon {{
|
|
|
|
|
fill:#{0};
|
|
|
|
|
fill-opacity:1;
|
|
|
|
|
stroke:#000000;
|
|
|
|
|
stroke-width:1;
|
|
|
|
|
stroke-opacity:1;
|
|
|
|
|
}}
|
2014-01-10 07:15:39 -05:00
|
|
|
</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'
|
2014-05-26 19:50:02 -07:00
|
|
|
ylabel = '<text x="90" y="{0:.2f}" font-size="16" text-anchor="end">{1}</text>\n'
|
2014-01-10 07:15:39 -05:00
|
|
|
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>
|
|
|
|
|
"""
|
|
|
|
|
|
2014-05-26 19:50:02 -07:00
|
|
|
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
|
|
|
|
|
|
2014-01-16 16:25:09 -08:00
|
|
|
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()
|
|
|
|
|
|
2014-01-10 07:15:39 -05:00
|
|
|
def ylimits(x):
|
|
|
|
|
ll = [2, 3, 4, 5, 6, 8, 10, 15]
|
|
|
|
|
m = 1
|
|
|
|
|
size = 0
|
|
|
|
|
while True:
|
|
|
|
|
for i in ll:
|
2014-05-26 19:50:02 -07:00
|
|
|
if i * m > x * 1.1:
|
2014-01-10 07:15:39 -05:00
|
|
|
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
|
|
|
|
|
|
2014-01-16 16:25:09 -08:00
|
|
|
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")
|
2014-01-10 07:15:39 -05:00
|
|
|
xlgraph.write(framerect)
|
2014-05-26 19:50:02 -07:00
|
|
|
xlgraph.write('<clipPath id="framer">\n')
|
|
|
|
|
xlgraph.write(framerect)
|
|
|
|
|
xlgraph.write('</clipPath>\n')
|
2014-01-16 16:25:09 -08:00
|
|
|
xldivs, xlmax = ylimits(max([ pt[1] for pt in xldata ]))
|
2014-01-10 07:15:39 -05:00
|
|
|
scale = 500 / xlmax
|
2014-01-16 16:25:09 -08:00
|
|
|
for xl, count in xldata:
|
2014-01-10 07:15:39 -05:00
|
|
|
barx = xl * 50 + 60
|
2014-05-26 19:50:02 -07:00
|
|
|
barh = scale * count
|
2014-01-10 07:15:39 -05:00
|
|
|
bary = 550 - barh
|
2014-05-26 19:50:02 -07:00
|
|
|
if count > 0:
|
|
|
|
|
xlgraph.write(bar3d(barx, 30, barh))
|
2014-01-10 07:15:39 -05:00
|
|
|
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))
|
2014-01-16 10:07:49 -08:00
|
|
|
xlgraph.write(xlabelf.format("Experience level"))
|
|
|
|
|
xlgraph.write(ylabelf.format("# of games"))
|
2014-01-16 16:25:09 -08:00
|
|
|
xlgraph.write(titles(sitename, game.name, timestr))
|
2014-01-16 10:07:49 -08:00
|
|
|
xlgraph.close()
|
|
|
|
|
return
|
2014-01-10 07:15:39 -05:00
|
|
|
|
2014-01-16 16:25:09 -08:00
|
|
|
def mkscoregraph(game, scoredata):
|
2014-01-16 10:07:49 -08:00
|
|
|
if isinstance(game, rlgall.ARogueGame):
|
|
|
|
|
scorewidth = 1000
|
2015-01-21 10:45:00 -05:00
|
|
|
else:
|
|
|
|
|
scorewidth = 500
|
2014-01-16 16:25:09 -08:00
|
|
|
scoregraph = SVGChart("{0}/score-{1}.svg".format(svgpath, game.uname))
|
|
|
|
|
scoregraph.style("ffff00")
|
2014-01-16 10:07:49 -08:00
|
|
|
scoregraph.write(framerect)
|
2014-05-26 19:50:02 -07:00
|
|
|
scoregraph.write('<clipPath id="framer">\n')
|
|
|
|
|
scoregraph.write(framerect)
|
|
|
|
|
scoregraph.write('</clipPath>\n')
|
2014-01-16 16:25:09 -08:00
|
|
|
scoredivs, scoremax = ylimits(max([ pt[1] for pt in scoredata ]))
|
2014-01-10 07:15:39 -05:00
|
|
|
scale = 500 / scoremax
|
2014-01-16 16:25:09 -08:00
|
|
|
for block, count in scoredata:
|
|
|
|
|
n = block // scorewidth
|
2015-01-21 10:45:00 -05:00
|
|
|
barx = n * 50 + 100
|
2014-05-26 19:50:02 -07:00
|
|
|
barh = scale * count
|
2014-01-10 07:15:39 -05:00
|
|
|
bary = 550 - barh
|
2014-05-26 19:50:02 -07:00
|
|
|
if count > 0:
|
2015-01-21 10:45:00 -05:00
|
|
|
scoregraph.write(bar3d(barx, 50, barh))
|
|
|
|
|
if n % 2 == 0:
|
|
|
|
|
scoregraph.write(xllabel.format(barx, block))
|
2014-01-10 07:15:39 -05:00
|
|
|
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"))
|
2014-01-16 16:25:09 -08:00
|
|
|
scoregraph.write(titles(sitename, game.name, timestr))
|
2014-01-10 07:15:39 -05:00
|
|
|
scoregraph.close()
|
2014-01-16 10:07:49 -08:00
|
|
|
return
|
|
|
|
|
|
2014-01-16 16:25:09 -08:00
|
|
|
def mkdeepgraph(game, deepdata):
|
|
|
|
|
deepgraph = SVGChart("{0}/deep-{1}.svg".format(svgpath, game.uname))
|
|
|
|
|
deepgraph.style("808000")
|
2014-01-16 10:07:49 -08:00
|
|
|
deepgraph.write(framerect)
|
2014-05-26 19:50:02 -07:00
|
|
|
deepgraph.write('<clipPath id="framer">\n')
|
|
|
|
|
deepgraph.write(framerect)
|
|
|
|
|
deepgraph.write('</clipPath>\n')
|
2014-01-16 16:25:09 -08:00
|
|
|
deepdivs, deepmax = ylimits(max([ pt[1] for pt in deepdata ]))
|
2014-01-16 10:07:49 -08:00
|
|
|
scale = 500 / deepmax
|
2014-01-16 16:25:09 -08:00
|
|
|
for lev, count in deepdata:
|
2014-01-16 10:07:49 -08:00
|
|
|
barx = lev * 25 + 75
|
2014-05-26 19:50:02 -07:00
|
|
|
barh = scale * count
|
2014-01-16 10:07:49 -08:00
|
|
|
bary = 550 - barh
|
2014-05-26 19:50:02 -07:00
|
|
|
if count > 0:
|
|
|
|
|
deepgraph.write(bar3d(barx, 25, barh))
|
2014-01-16 10:07:49 -08:00
|
|
|
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"))
|
2014-01-16 16:25:09 -08:00
|
|
|
deepgraph.write(titles(sitename, game.name, timestr))
|
2014-01-16 10:07:49 -08:00
|
|
|
deepgraph.close()
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
for game in rlgall.gamelist:
|
2014-01-16 16:25:09 -08:00
|
|
|
xldata = game.getXLCounts(15)
|
|
|
|
|
deepdata = game.getDepthCounts(30)
|
2014-01-16 10:07:49 -08:00
|
|
|
if isinstance(game, rlgall.ARogueGame):
|
|
|
|
|
scorewidth = 1000
|
2015-01-21 10:45:00 -05:00
|
|
|
else:
|
|
|
|
|
scorewidth = 500
|
|
|
|
|
scoredata = game.getScoreCounts(15, scorewidth)
|
2014-01-16 16:25:09 -08:00
|
|
|
mkxlgraph(game, xldata)
|
|
|
|
|
mkscoregraph(game, scoredata)
|
|
|
|
|
mkdeepgraph(game, deepdata)
|
2014-01-10 07:15:39 -05:00
|
|
|
|
|
|
|
|
exit()
|