view py/stats2.py @ 87:1bddd1839831

Update the dgamelaunch patch to work with the most recent changes. Also set the umask, just in case it defaults to 0077.
author John "Elwin" Edwards
date Sat, 24 Nov 2018 16:47:24 -0500
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()