#! /usr/bin/env python
import sys, time
class arginfo:
def __init__(self):
self.file = sys.stdin
self.html = False
self.showuid = False
self.holeshotidx = 1
args = arginfo()
class raceinfo:
def __init__(self):
# array of tuples like this: (number, bike, laps, totaltime, bestlap, besttime)
self.info = []
# time each gate was hit. 3d array where indices are times[entrant][lap][gate]
self.times = []
self.vars = []
def timetostring(seconds):
ms = int(seconds * 1000)
sec = int(ms / 1000)
min = int(sec / 60)
ms = ms - sec * 1000
sec = sec - min * 60
return "%3d:%02d.%03d" % (min, sec, ms)
def readtimes(f, n):
c = -1
while c < 0:
s = f.readline()
if s == "":
return None
try:
c = int(s)
except:
c = -1
t = []
while c > 0:
s = f.readline()
s = s.split()
s = map(float, s)
c -= len(s)
t.append(map(float, s))
return t
def readvars(f):
vars = f.readline().split("|");
d = { }
for s in vars:
v = s.split("=", 1)
if len(v) == 2:
d[v[0]] = v[1]
return d
def readresults(f):
ri = raceinfo()
ri.vars = readvars(f)
# discard table headings
f.readline()
while True:
s = f.readline()
if not s:
return None
s = s.split("|")
if len(s) < 6:
break
number = s[0].strip()
bike = s[1].strip()
laps = s[2].strip()
totaltime = s[3].strip()
bestlap = s[4].strip()
besttime = s[5].strip()
if len(s) >= 7:
uid = s[6].strip()
else:
uid = "0"
if len(s) >= 8:
name = s[7].strip()
else:
name = ""
ri.info.append((number, bike, laps, totaltime, bestlap, besttime, uid, name))
for i in xrange(len(ri.info)):
ri.times.append(readtimes(f, len(ri.info)))
return ri
def timeandlapstring(ri):
t = None
if "Time" in ri.vars:
t = float(ri.vars["Time"]) / 60
l = None
if "Laps" in ri.vars:
l = int(ri.vars["Laps"])
if t and l:
return "%.0f Minutes + %d Laps" % (t, l)
elif t:
return "%.0f Minutes" % t
elif l:
return "%d Laps" % l
return ""
def printheader(ri):
if args.html:
print "
"
if "Date" in ri.vars:
print time.ctime(float(ri.vars["Date"]))
if args.html:
print "
"
print timeandlapstring(ri)
if args.html:
print "
"
else:
print
def results(ri):
i = 1
if args.html:
print "Results
"
print ""
if args.showuid:
print "Pos. | UID | No. | Bike | Laps | "
else:
print "
---|
Pos. | No. | Bike | Laps | "
print "Total Time | Best Lap | Best Time | Name |
"
else:
print "\nResults:\n"
if args.showuid:
print "Pos. UID No. Bike Laps Total Time BLap Best Time Name"
else:
print "Pos. No. Bike Laps Total Time BLap Best Time Name"
for (number, bike, laps, totaltime, bestlap, besttime, uid, name) in ri.info:
if args.html:
if args.showuid:
uidstr = "%s | " % uid
else:
uidstr = ""
print "%d | %s%s | %s | %s | %s | %s | %s | %s |
" \
% (i, uidstr, number, bike, laps, totaltime, bestlap, besttime, name)
else:
if args.showuid:
uidstr = " %7s" % uid
else:
uidstr = ""
print "%4d%s %4s %-16s %4s %10s %4s %10s %s" \
% (i, uidstr, number, bike, laps, totaltime, bestlap, besttime, name)
i = i + 1
if args.html:
print "
"
def printchartascii(ri, p):
print "\nLap Chart:\n"
s = " "
for lap in xrange(len(p)):
s = s + "%4s " % ("L%d" % (lap + 1))
print s
for pos in xrange(len(p[0])):
s = "%3s: " % ("P%d" % (pos + 1))
for lap in xrange(len(p)):
try:
s = s + ("%4s " % p[lap][pos][1])
except:
None
print s
def printcharthtml(ri, p):
print "Lap Chart
"
print ""
s = " | "
for lap in xrange(len(p)):
s = s + "%s | " % ("L%d" % (lap + 1))
print "" + s + "
"
for pos in xrange(len(p[0])):
s = "%s | " % ("P%d" % (pos + 1))
for lap in xrange(len(p)):
try:
s = s + ("%s | " % p[lap][pos][1])
except:
None
print "" + s + "
"
print "
"
def lapchart(ri):
p = []
for lap in xrange(len(ri.times[0])):
tn = []
for i in xrange(len(ri.times)):
try:
tn.append((ri.times[i][lap][-1], ri.info[i][0]))
except:
None
tn.sort()
p.append(tn)
if len(p) == 0:
return
if args.html:
printcharthtml(ri, p)
else:
printchartascii(ri, p)
def laptimes(ri):
l = []
for i in xrange(len(ri.times)):
times = ri.times[i]
info = ri.info[i]
for lap in xrange(1, len(times)):
cut = False
for gt in times[lap]:
if gt < 0.0:
cut = True
if not cut:
laptime = times[lap][-1] - times[lap - 1][-1]
l.append((laptime, lap, info))
l.sort()
if args.html:
print "Sorted lap times
"
print ""
print "Time | Lap | Number | Bike |
"
else:
print "\nSorted lap times:\n"
print "Lap Time Lap No. Bike"
for (laptime, lap, info) in l:
if args.html:
print "%s | %3d | %4s | %s |
" % \
(timetostring(laptime), lap + 1, info[0], info[1])
else:
print "%s %-3d %-4s %s" % (timetostring(laptime), lap + 1, info[0], info[1])
if args.html:
print "
"
def nextvalidtime(ri, i, l, g):
while True:
t = ri.times[i][l][g]
if t > 0:
return t;
g = g + 1
if g >= len(ri.times[i][l]):
g = 0
l = l + 1
if l >= len(ri.times[i]):
return -1
def addevents(ri, e, i, l, g):
if l == 0 and g <= args.holeshotidx:
return
pl = l
pg = g - 1
if pg < 0:
pl = pl - 1
if pl < 0:
return
try:
i0 = ri.times[i][pl][pg]
i1 = ri.times[i][l][g]
except:
return
if i1 < 0 and i0 >= 0:
e.append((nextvalidtime(ri, i, l, g), i0, i, -1, l, g))
if i0 < 0 or i1 < 0:
return
for j in xrange(len(ri.times)):
try:
j0 = ri.times[j][pl][pg]
j1 = ri.times[j][l][g]
if j0 >= 0 and j1 >= 0 and j0 < i0 and j1 >= i1:
e.append((i1, i0, i, j, l, g))
except:
None
def bikelisttostring(ri, bl):
if len(bl) == 1:
return ri.info[bl[0]][0]
s = ""
for i in bl[0:-2]:
s = s + ri.info[i][0] + ", "
return s + ri.info[bl[-2]][0] + " and " + ri.info[bl[-1]][0]
def getposition(ri, i, l, g):
try:
t = ri.times[i][l][g]
except:
t = 1000000000.0
p = 1
for x in ri.times:
try:
t2 = x[l][g]
except:
t2 = 1000000000.0
if t2 >= 0.0 and t2 < t:
p = p + 1
return p
def getpositionstring(ri, i, l, g):
p = getposition(ri, i, l, g)
if p == 1:
return "the lead"
if p / 10 % 10 == 1:
return "%dth" % (p)
suffix = [ "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" ]
return "%d%s" % (p, suffix[p % 10])
def getorderatposition(ri, l, g):
a = []
for i in xrange(len(ri.times)):
try:
t = ri.times[i][l][g]
if t >= 0.0:
a.append((t, i))
except:
None
a.sort()
n = []
for (t, i) in a:
n.append(ri.info[i][0])
return n
def printinitialpositions(ri):
a = getorderatposition(ri, 0, args.holeshotidx)
if len(a) < 2:
return
if len(a) == 2:
print "%s gets the holeshot followed by %s" % (a[0], a[1])
return
s = "%s gets the holeshot followed by " % (a[0])
s = s + ", ".join(a[1:-1])
s = s + " and " + a[-1]
print s
def events(ri):
e = []
for i in xrange(len(ri.times)):
for l in xrange(len(ri.times[i])):
for g in xrange(len(ri.times[i][l])):
addevents(ri, e, i, l, g)
e.sort()
c = []
for (t1, t0, i, j, l, g) in e:
if c and c[-1][0] == t0 and c[-1][1] == t1 and c[-1][2] == i and c[-1][3][0] != -1:
c[-1][3].append(j)
else:
c.append((t0, t1, i, [j], l, g))
e = c
if args.html:
print "Play by play
"
else:
print "\nPlay by play:\n"
printinitialpositions(ri)
for (t0, t1, i, j, l, g) in e:
ts0 = timetostring(t0).strip()
ts1 = timetostring(t1).strip()
if j[0] == -1:
print "%s-%s: %s went off the track" % (ts0, ts1, ri.info[i][0])
else:
print "%s-%s: %s passed %s for %s" % (ts0, ts1, ri.info[i][0], bikelisttostring(ri, j), \
getpositionstring(ri, i, l, g))
if args.html:
print "
"
def parseargs(a):
usage = "usage: lapchart.py [--html] "
while len(a) > 0:
s = a.pop(0)
if s == "--help":
return usage
if s == "--html":
args.html = True
elif s == "--showuid":
args.showuid = True
elif s[0] == "-":
return "invalid option '" + s + "'"
elif args.file == sys.stdin:
args.file = file(s, "rb")
else:
return "Too many input files"
return None
errormsg = parseargs(sys.argv[1:])
if errormsg:
sys.stderr.write(errormsg + "\n")
sys.exit(1)
ri = readresults(args.file)
printheader(ri)
results(ri)
lapchart(ri)
laptimes(ri)
events(ri)