view py/stats2.py @ 67:5b6211e2e36f

Update some static pages. The front page has been reorganized. Links and information on the downloads page are now current.
author John "Elwin" Edwards
date Sat, 21 Nov 2015 20:01:41 -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()