view py/stats2.py @ 55:e421ea2519ec

dgamelaunch: define user/group by name instead of UID/GID. The user and group might not be created with the UID and GID expected, so it is better to use names. They can be changed to numeric values after installation.
author John "Elwin" Edwards
date Sun, 11 May 2014 08:32:31 -0700
parents 0f4163dbbafc
children 5cf88bd4e556
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;
}}
</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}" 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>
"""

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:
        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)
  xldivs, xlmax = ylimits(max([ pt[1] for pt in xldata ]))
  scale = 500 / xlmax
  for xl, count in xldata:
    barx = xl * 50 + 60
    barh = round(scale * count)
    bary = 550 - barh
    xlgraph.write(barstr.format(30, barh, barx, bary))
    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 = 1500
  else:
    scorewidth = 1000
  scoregraph = SVGChart("{0}/score-{1}.svg".format(svgpath, game.uname))
  scoregraph.style("ffff00")
  scoregraph.write(framerect)
  scoredivs, scoremax = ylimits(max([ pt[1] for pt in scoredata ]))
  scale = 500 / scoremax
  for block, count in scoredata:
    n = block // scorewidth
    barx = n * 75 + 100
    barh = round(scale * count)
    bary = 550 - barh
    scoregraph.write(barstr.format(75, barh, barx, bary))
    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)
  deepdivs, deepmax = ylimits(max([ pt[1] for pt in deepdata ]))
  scale = 500 / deepmax
  for lev, count in deepdata:
    barx = lev * 25 + 75
    barh = round(scale * count)
    bary = 550 - barh
    deepgraph.write(barstr.format(25, barh, barx, bary))
    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 = 1500
  else:
    scorewidth = 1000
  scoredata = game.getScoreCounts(10, scorewidth)
  mkxlgraph(game, xldata)
  mkscoregraph(game, scoredata)
  mkdeepgraph(game, deepdata)

exit()