SVG charts: separate database-querying and chart-printing code.
Create Game methods in rlgall.py to get histogram data for score, xl, maxdepth. In stats2.py, make the chart-printing functions use this data and avoid running hard-coded queries.
This commit is contained in:
parent
bc4dda7e9e
commit
479c173caf
2 changed files with 109 additions and 63 deletions
67
py/rlgall.py
67
py/rlgall.py
|
|
@ -296,6 +296,73 @@ class Game:
|
||||||
for d in data:
|
for d in data:
|
||||||
d["game"] = self
|
d["game"] = self
|
||||||
return data
|
return data
|
||||||
|
def getXLCounts(self, nmax=15):
|
||||||
|
"Returns a list of (xlevel, gamecount) pairs."
|
||||||
|
lquery = "SELECT count(*) FROM {0} WHERE xl = %s;".format(self.uname)
|
||||||
|
mquery = "SELECT count(*) FROM {0} WHERE xl >= %s;".format(self.uname)
|
||||||
|
try:
|
||||||
|
nmax = int(nmax)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return []
|
||||||
|
if nmax <= 0:
|
||||||
|
return []
|
||||||
|
xlevels = range(1, nmax)
|
||||||
|
results = []
|
||||||
|
conn = psycopg2.connect("dbname=rlg")
|
||||||
|
cur = conn.cursor()
|
||||||
|
for xl in xlevels:
|
||||||
|
cur.execute(lquery, [xl])
|
||||||
|
results.append((xl, cur.fetchone()[0]))
|
||||||
|
cur.execute(mquery, [nmax])
|
||||||
|
results.append((nmax, cur.fetchone()[0]))
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
return results
|
||||||
|
def getDepthCounts(self, nmax=30):
|
||||||
|
"Returns a list of (maxdepth, gamecount) pairs."
|
||||||
|
dqry = "SELECT count(*) FROM {0} WHERE maxdepth = %s;".format(self.uname)
|
||||||
|
mqry = "SELECT count(*) FROM {0} WHERE maxdepth >= %s;".format(self.uname)
|
||||||
|
try:
|
||||||
|
nmax = int(nmax)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return []
|
||||||
|
if nmax <= 0:
|
||||||
|
return []
|
||||||
|
depths = range(1, nmax)
|
||||||
|
results = []
|
||||||
|
conn = psycopg2.connect("dbname=rlg")
|
||||||
|
cur = conn.cursor()
|
||||||
|
for lev in depths:
|
||||||
|
cur.execute(dqry, [lev])
|
||||||
|
results.append((lev, cur.fetchone()[0]))
|
||||||
|
cur.execute(mqry, [nmax])
|
||||||
|
results.append((nmax, cur.fetchone()[0]))
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
return results
|
||||||
|
def getScoreCounts(self, blocks=10, size=1000):
|
||||||
|
"Returns a list of (minscore, gamecount) pairs."
|
||||||
|
sqry = "SELECT count(*) FROM {0} WHERE score >= %s AND score < %s;".format(self.uname)
|
||||||
|
mqry = "SELECT count(*) FROM {0} WHERE score >= %s;".format(self.uname)
|
||||||
|
try:
|
||||||
|
blocks = int(blocks)
|
||||||
|
size = int(size)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return []
|
||||||
|
if blocks <= 0 or size <= 0:
|
||||||
|
return []
|
||||||
|
marks = range(blocks - 1)
|
||||||
|
results = []
|
||||||
|
conn = psycopg2.connect("dbname=rlg")
|
||||||
|
cur = conn.cursor()
|
||||||
|
for m in marks:
|
||||||
|
cur.execute(sqry, [m * size, (m + 1) * size])
|
||||||
|
results.append((m * size, cur.fetchone()[0]))
|
||||||
|
cur.execute(mqry, [(blocks - 1) * size])
|
||||||
|
results.append(((blocks - 1) * size, cur.fetchone()[0]))
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
return results
|
||||||
# End Game class definition
|
# End Game class definition
|
||||||
|
|
||||||
class RogueGame(Game):
|
class RogueGame(Game):
|
||||||
|
|
|
||||||
105
py/stats2.py
105
py/stats2.py
|
|
@ -43,6 +43,18 @@ ylabelf = """<g transform="translate(100, 300)">
|
||||||
</g>
|
</g>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
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):
|
def ylimits(x):
|
||||||
ll = [2, 3, 4, 5, 6, 8, 10, 15]
|
ll = [2, 3, 4, 5, 6, 8, 10, 15]
|
||||||
m = 1
|
m = 1
|
||||||
|
|
@ -71,14 +83,16 @@ def ylimits(x):
|
||||||
divs = 5
|
divs = 5
|
||||||
return divs, lim
|
return divs, lim
|
||||||
|
|
||||||
def mkxlgraph(game, xls, xlcounts):
|
def titles(l, c, r):
|
||||||
xlgraph = open("{0}/xl-{1}.svg".format(svgpath, game.uname), "w")
|
return ltitle.format(l) + ctitle.format(c) + rtitle.format(r)
|
||||||
xlgraph.write(dochead)
|
|
||||||
xlgraph.write(stylesheet.format("0000ff"))
|
def mkxlgraph(game, xldata):
|
||||||
|
xlgraph = SVGChart("{0}/xl-{1}.svg".format(svgpath, game.uname))
|
||||||
|
xlgraph.style("0000ff")
|
||||||
xlgraph.write(framerect)
|
xlgraph.write(framerect)
|
||||||
xldivs, xlmax = ylimits(max(xlcounts))
|
xldivs, xlmax = ylimits(max([ pt[1] for pt in xldata ]))
|
||||||
scale = 500 / xlmax
|
scale = 500 / xlmax
|
||||||
for xl, count in zip(xls, xlcounts):
|
for xl, count in xldata:
|
||||||
barx = xl * 50 + 60
|
barx = xl * 50 + 60
|
||||||
barh = round(scale * count)
|
barh = round(scale * count)
|
||||||
bary = 550 - barh
|
bary = 550 - barh
|
||||||
|
|
@ -90,51 +104,44 @@ def mkxlgraph(game, xls, xlcounts):
|
||||||
xlgraph.write(ylabel.format(labelh, labeln))
|
xlgraph.write(ylabel.format(labelh, labeln))
|
||||||
xlgraph.write(xlabelf.format("Experience level"))
|
xlgraph.write(xlabelf.format("Experience level"))
|
||||||
xlgraph.write(ylabelf.format("# of games"))
|
xlgraph.write(ylabelf.format("# of games"))
|
||||||
xlgraph.write(ltitle.format(sitename))
|
xlgraph.write(titles(sitename, game.name, timestr))
|
||||||
xlgraph.write(ctitle.format(game.name))
|
|
||||||
xlgraph.write(rtitle.format(timestr))
|
|
||||||
xlgraph.write('</svg>\n')
|
|
||||||
xlgraph.close()
|
xlgraph.close()
|
||||||
return
|
return
|
||||||
|
|
||||||
def mkscoregraph(game, scoreblocks, scorecounts):
|
def mkscoregraph(game, scoredata):
|
||||||
if isinstance(game, rlgall.ARogueGame):
|
if isinstance(game, rlgall.ARogueGame):
|
||||||
scorewidth = 1500
|
scorewidth = 1500
|
||||||
else:
|
else:
|
||||||
scorewidth = 1000
|
scorewidth = 1000
|
||||||
scoregraph = open("{0}/score-{1}.svg".format(svgpath, game.uname), "w")
|
scoregraph = SVGChart("{0}/score-{1}.svg".format(svgpath, game.uname))
|
||||||
scoregraph.write(dochead)
|
scoregraph.style("ffff00")
|
||||||
scoregraph.write(stylesheet.format("ffff00"))
|
|
||||||
scoregraph.write(framerect)
|
scoregraph.write(framerect)
|
||||||
scoredivs, scoremax = ylimits(max(scorecounts))
|
scoredivs, scoremax = ylimits(max([ pt[1] for pt in scoredata ]))
|
||||||
scale = 500 / scoremax
|
scale = 500 / scoremax
|
||||||
for block, count in zip(scoreblocks, scorecounts):
|
for block, count in scoredata:
|
||||||
barx = block * 75 + 100
|
n = block // scorewidth
|
||||||
|
barx = n * 75 + 100
|
||||||
barh = round(scale * count)
|
barh = round(scale * count)
|
||||||
bary = 550 - barh
|
bary = 550 - barh
|
||||||
scoregraph.write(barstr.format(75, barh, barx, bary))
|
scoregraph.write(barstr.format(75, barh, barx, bary))
|
||||||
scoregraph.write(xllabel.format(barx, block * scorewidth))
|
scoregraph.write(xllabel.format(barx, block))
|
||||||
for yl in range(scoredivs + 1):
|
for yl in range(scoredivs + 1):
|
||||||
labeln = int(scoremax * yl / scoredivs)
|
labeln = int(scoremax * yl / scoredivs)
|
||||||
labelh = 550 + 8 - 500 * yl / scoredivs
|
labelh = 550 + 8 - 500 * yl / scoredivs
|
||||||
scoregraph.write(ylabel.format(labelh, labeln))
|
scoregraph.write(ylabel.format(labelh, labeln))
|
||||||
scoregraph.write(xlabelf.format("Score"))
|
scoregraph.write(xlabelf.format("Score"))
|
||||||
scoregraph.write(ylabelf.format("# of games"))
|
scoregraph.write(ylabelf.format("# of games"))
|
||||||
scoregraph.write(ltitle.format(sitename))
|
scoregraph.write(titles(sitename, game.name, timestr))
|
||||||
scoregraph.write(ctitle.format(game.name))
|
|
||||||
scoregraph.write(rtitle.format(timestr))
|
|
||||||
scoregraph.write('</svg>\n')
|
|
||||||
scoregraph.close()
|
scoregraph.close()
|
||||||
return
|
return
|
||||||
|
|
||||||
def mkdeepgraph(game, deeps, deepcounts):
|
def mkdeepgraph(game, deepdata):
|
||||||
deepgraph = open("{0}/deep-{1}.svg".format(svgpath, game.uname), "w")
|
deepgraph = SVGChart("{0}/deep-{1}.svg".format(svgpath, game.uname))
|
||||||
deepgraph.write(dochead)
|
deepgraph.style("808000")
|
||||||
deepgraph.write(stylesheet.format("808000"))
|
|
||||||
deepgraph.write(framerect)
|
deepgraph.write(framerect)
|
||||||
deepdivs, deepmax = ylimits(max(deepcounts))
|
deepdivs, deepmax = ylimits(max([ pt[1] for pt in deepdata ]))
|
||||||
scale = 500 / deepmax
|
scale = 500 / deepmax
|
||||||
for lev, count in zip(deeps, deepcounts):
|
for lev, count in deepdata:
|
||||||
barx = lev * 25 + 75
|
barx = lev * 25 + 75
|
||||||
barh = round(scale * count)
|
barh = round(scale * count)
|
||||||
bary = 550 - barh
|
bary = 550 - barh
|
||||||
|
|
@ -147,48 +154,20 @@ def mkdeepgraph(game, deeps, deepcounts):
|
||||||
deepgraph.write(ylabel.format(labelh, labeln))
|
deepgraph.write(ylabel.format(labelh, labeln))
|
||||||
deepgraph.write(xlabelf.format("Deepest dungeon level"))
|
deepgraph.write(xlabelf.format("Deepest dungeon level"))
|
||||||
deepgraph.write(ylabelf.format("# of games"))
|
deepgraph.write(ylabelf.format("# of games"))
|
||||||
deepgraph.write(ltitle.format(sitename))
|
deepgraph.write(titles(sitename, game.name, timestr))
|
||||||
deepgraph.write(ctitle.format(game.name))
|
|
||||||
deepgraph.write(rtitle.format(timestr))
|
|
||||||
deepgraph.write('</svg>\n')
|
|
||||||
deepgraph.close()
|
deepgraph.close()
|
||||||
return
|
return
|
||||||
|
|
||||||
con = psycopg2.connect("dbname=rlg")
|
|
||||||
cur = con.cursor()
|
|
||||||
|
|
||||||
for game in rlgall.gamelist:
|
for game in rlgall.gamelist:
|
||||||
xlq = "SELECT count(*) FROM {0} WHERE xl = %s;".format(game.uname)
|
xldata = game.getXLCounts(15)
|
||||||
scrq = "SELECT count(*) FROM {0} WHERE score >= %s AND score < %s;".format(game.uname)
|
deepdata = game.getDepthCounts(30)
|
||||||
deepq = "SELECT count(*) FROM {0} WHERE maxdepth = %s;".format(game.uname)
|
|
||||||
xls = range(1, 16)
|
|
||||||
scoreblocks = range(10)
|
|
||||||
deeps = range(1, 31)
|
|
||||||
xlcounts = []
|
|
||||||
scorecounts = []
|
|
||||||
deepcounts = []
|
|
||||||
if isinstance(game, rlgall.ARogueGame):
|
if isinstance(game, rlgall.ARogueGame):
|
||||||
scorewidth = 1500
|
scorewidth = 1500
|
||||||
else:
|
else:
|
||||||
scorewidth = 1000
|
scorewidth = 1000
|
||||||
for xl in xls:
|
scoredata = game.getScoreCounts(10, scorewidth)
|
||||||
cur.execute(xlq, [xl])
|
mkxlgraph(game, xldata)
|
||||||
xlcounts.append(cur.fetchone()[0])
|
mkscoregraph(game, scoredata)
|
||||||
for sn in scoreblocks:
|
mkdeepgraph(game, deepdata)
|
||||||
lscore = sn * scorewidth
|
|
||||||
if sn == 9:
|
|
||||||
hscore = scorewidth * 32
|
|
||||||
else:
|
|
||||||
hscore = (sn + 1) * scorewidth
|
|
||||||
cur.execute(scrq, (lscore, hscore))
|
|
||||||
scorecounts.append(cur.fetchone()[0])
|
|
||||||
for lev in deeps:
|
|
||||||
cur.execute(deepq, [lev])
|
|
||||||
deepcounts.append(cur.fetchone()[0])
|
|
||||||
mkxlgraph(game, xls, xlcounts)
|
|
||||||
mkscoregraph(game, scoreblocks, scorecounts)
|
|
||||||
mkdeepgraph(game, deeps, deepcounts)
|
|
||||||
|
|
||||||
cur.close()
|
|
||||||
con.close()
|
|
||||||
exit()
|
exit()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue