PyScore

001: # -*- python -*-
002: #### printsheet.py #### python package PyScore.tabulate module printsheet ####
003: 
004: # PyScore
005: # a race scoring programme
006: # written by Matt Draisey
007: # 2004 April 6
008: 
009: reloadables=[]
010: 
011: #### printsheet.py #### python package PyScore.tabulate module printsheet ####
012: 
013: import sys
014: from relational import base
015: from standing import enumstat,eventstat
016: from tabulate import enumcond,racesheet,scoresheet
017: 
018: ######## ######## print raw timesheet data ######## ########
019: 
020: def print_timesheet(race,timesheet,out=sys.stdout):
021:     assert isinstance(race,racesheet.RaceSheetEntry)
022:     print>>out,"Raw Timesheet for",race.racename
023:     print>>out
024: 
025:     for (en,bs,bn,fc,ft,cd,cf,cr,ps) in timesheet:
026:         print>>out,"%3i  %8s:%-18s  %3s %8s  %7s %-13s %3s  %5s"%(
027:             en,bs,bn,fc,ft,cd,cf,cr,ps[:5]
028:         )
029:     print>>out
030: 
031: def print_override_scoresheet(race,scoresheet,out=sys.stdout):
032:     assert isinstance(race,racesheet.RaceSheetEntry)
033:     print>>out,"Raw Override Scoresheet for",race.racename
034:     print>>out
035: 
036:     for (en,bs,bn,cd,cf,sf,ss,sc,sw,ps) in scoresheet:
037:         try:
038:             series="%4.1f"%float(ss)
039:         except ValueError:
040:             series=""
041:         try:
042:             casual="%+3i"%int(sc)+"/%i"%int(sw)
043:         except ValueError:
044:             casual=""
045:         print>>out,"%3i  %8s:%-18s  %7s %-13s  %3s %4s %6s  %5s"%(
046:             en,bs,bn,cd,cf,sf,series,casual,ps[:5]
047:         )
048:     print>>out
049: 
050: ######## ######## print handicap sheets ######## ########
051: 
052: UNKNOWN=eventstat.DivisionName.UNKNOWN
053: 
054: def print_scratches(race,handicapsheet,out=sys.stdout):
055:     assert isinstance(race,racesheet.RaceSheetEntry)
056:     print>>out,"Race %s"%str(race.racename)
057:     print>>out,"Scratch Sheets:"
058:     try:
059:         distance=race.distance
060:         print>>out,"Corrections on %4.2f mile course:"%distance
061:     except AttributeError:
062:         distance=0.0
063:     print>>out
064: 
065:     for (
066:         start,fleets
067:     ) in base.adjoin_hierarchy(
068:         handicapsheet.adjoin_filter(["ziprating"]),
069:         [("start",None,racesheet.StartSheetEntry(race,UNKNOWN)),"fleet"]
070:     ):
071: 
072:         print>>out,start.divisionname,"Class Scratch Sheets:"
073:         try:
074:             if start.distance<>distance:
075:                 print>>out,"Corrections on "\
076:                 "%4.2f mile course:"%start.distance
077:         except AttributeError:
078:             pass
079:         for (fleet,entries) in fleets:
080:             flt=abbrev(fleet)
081:             if flt:
082:                 print>>out," ",flt,"Fleet"
083:             for entry in entries:
084:                 boat=entry.boat
085:                 (bs,bn)=(boat.sailnumber,boat.boatname)
086:                 try:
087:                     rating=entry.rating
088:                 except AttributeError:
089:                     rating="?"
090:                 try:
091:                     (hm,ss)=divmod(entry.relativeco,60)
092:                     (hh,mm)=divmod(hm,60)
093:                     assert hh==0 or hh==-1
094:                     relco="%02i:%02i"%(mm,ss)
095:                 except AttributeError:
096:                     relco=".. .."
097:                 print>>out,"  %8s:%-18s  %3s  %5s"%(
098:                     bs,bn,rating,relco
099:                 )
100:         print>>out
101: 
102:     print>>out
103: 
104: def abbrev(entry):
105:     try:
106:         return str(entry.abbrev)
107:     except AttributeError:
108:         return str(entry)
109: 
110: def finish_fields(entry):
111:     (bs,bn)=(entry.boat.sailnumber,entry.boat.boatname)
112:     flt=abbrev(entry.fleet)
113:     try:
114:         rating=entry.rating
115:     except AttributeError:
116:         rating="?"
117:     fc=entry.finishcondition
118:     try:
119:         ft="%02i:%02i:%02i"%entry.finishhms
120:     except AttributeError:
121:         ft=""
122:     try:
123:         (hm,ss)=divmod(entry.relativeco,60)
124:         (hh,mm)=divmod(hm,60)
125:         assert hh==0 or hh==-1
126:         relco="%02i:%02i"%(mm,ss)
127:     except AttributeError:
128:         relco=".. .."
129:     try:
130:         ftco="%02i:%02i:%02i"%entry.correctedhms
131:     except AttributeError:
132:         ftco=""
133:     return (bs,bn,flt,rating,fc,ft,relco,ftco)
134: 
135: def print_unscored_handicapsheet(race,handicapsheet,out=sys.stdout):
136:     assert isinstance(race,racesheet.RaceSheetEntry)
137: 
138:     def print_result_line(rk,entry):
139:         (bs,bn,fleet,rating,fc,ft,relco,ftco)=finish_fields(entry)
140:         print>>out," %2s  %8s:%-18s   %-6s  %3s   %3s  %8s  %5s  %8s"%(
141:             rk,bs,bn,fleet,rating,fc,ft,relco,ftco
142:         )
143:     print>>out,"Race Results for %s"%str(race.racename)
144:     print>>out
145: 
146:     for (
147:         start,[entries,failedentries]
148:     ) in base.adjoin_polyhierarchy(
149:         handicapsheet.adjoin_filter(["ranking"]),
150:         handicapsheet.converse_filter(["ranking"]),
151:         [("start",None,racesheet.StartSheetEntry(race,UNKNOWN))],
152:     ):
153: 
154:         print>>out," Results for %-7s               Fleet  PHRF"\
155:             "        Finish  Correction  Final"%\
156:             str(start.divisionname)
157:         print>>out," --  "+"-"*27+"   "+"-"*11+"   "+"-"*30
158:         for entry in entries:
159:             print_result_line(str(entry.ranking),entry)
160:         print>>out
161:         for entry in failedentries:
162:             print_result_line("",entry)
163:         print>>out
164: 
165:     print>>out
166: 
167: def print_handicapsheet(race,handicapsheet,out=sys.stdout):
168:     assert isinstance(race,racesheet.RaceSheetEntry)
169: 
170:     def print_result_line(rk,entry,pt):
171:         (bs,bn,fleet,rating,fc,ft,relco,ftco)=finish_fields(entry)
172:         print>>out," %2s  %8s:%-18s  %-6s %3s  %3s %8s %5s %8s  %4s"%(
173:             rk,bs,bn,fleet,rating,fc,ft,relco,ftco,pt
174:         )
175:     print>>out,"Race Results for %s:"%str(race.racename),
176:     try:
177:         distance=race.distance
178:         print>>out,"Corrections on %4.2fmi course:"%distance
179:     except AttributeError:
180:         distance=0.0
181:         print>>out
182:     print>>out
183: 
184:     for (
185:         start,[entries,failedentries]
186:     ) in base.adjoin_polyhierarchy(
187:         handicapsheet.adjoin_filter(["ranking"]),
188:         handicapsheet.converse_filter(["ranking"]),
189:         [("start",None,racesheet.StartSheetEntry(race,UNKNOWN))],
190:     ):
191: 
192:         print>>out," Results for %-7s"%str(start.divisionname),
193:         try:
194:             if start.distance<>distance:
195:                 print>>out,"     %4.2fmi "%start.distance,
196:             else:
197:                 print>>out,"            ",
198:         except AttributeError:
199:             print>>out,"            ",
200:         print>>out,"Fleet/PHRF      Finish/Correction/Final   Pts"
201:         print>>out," --  "+"-"*27+"  "+"-"*10+"  "+"-"*27+"  ----"
202: 
203:         interspacer=False
204:         for entry in entries:
205:             try:
206:                 pts="%4.1f"%entry.seriespoints
207:             except AttributeError:
208:                 pts=""
209:             print_result_line(str(entry.ranking),entry,str(pts))
210:             interspacer=True
211: 
212:         for entry in failedentries:
213:             if interspacer: print>>out
214:             try:
215:                 entry.fleet.inseries
216:             except AttributeError:
217:                 print_result_line("",entry,"")
218:             else:
219:                 if entry.finishcondition==\
220:                 enumcond.FinishCondEnum.DNC:
221:                     print_result_line("",entry,"DNC")
222:                 else:
223:                     print_result_line("",entry,"?")
224:             interspacer=False
225:         print>>out
226: 
227: def print_casual_handicapsheet(race,handicapsheet,out=sys.stdout):
228:     assert isinstance(race,racesheet.RaceSheetEntry)
229: 
230:     def print_result_line(rk,entry,pt,cpw):
231:         (bs,bn,fleet,rating,fc,ft,relco,ftco)=finish_fields(entry)
232:         print>>out," %2s %8s:%-18s %-6s %3s %3s %8s %5s %8s %4s %3s"%(
233:             rk,bs,bn,fleet,rating,fc,ft,relco,ftco,pt,cpw
234:         )
235: 
236:     def print_level_racing_result_line(rk,entry,pt,cpw):
237:         (bs,bn,fleet,rating,fc,ft,relco,ftco)=finish_fields(entry)
238:         print>>out," %2s %8s:%-18s %-6s %3s %3s                %8s %4s %3s"%(
239:             rk,bs,bn,fleet,rating,fc,ftco,pt,cpw
240:         )
241: 
242:     print>>out,"Race Results for %s:"%str(race.racename),
243:     try:
244:         distance=race.distance
245:         print>>out,"Corrections on %4.2fmi course:"%distance
246:     except AttributeError:
247:         distance=0.0
248:         print>>out
249:     print>>out
250: 
251:     for (start,[entries,failedentries]) in base.adjoin_polyhierarchy(
252:         handicapsheet.adjoin_filter(["ranking"]),
253:         handicapsheet.converse_filter(["ranking"]),
254:         [("start",None,racesheet.StartSheetEntry(race,UNKNOWN))],
255:     ):
256:         print>>out," Results for %-7s"%str(start.divisionname),
257:         try:
258:             if start.distance<>distance:
259:                 print>>out,"    %4.2fmi"%start.distance,
260:             else:
261:                 print>>out,"          ",
262:         except AttributeError:
263:             print>>out,"          ",
264:         try:
265:             start.divisionname.levelracing
266:             print>>out,"Fleet/PHRF                      Finish  Pts",
267:         except:
268:             print>>out,"Fleet/PHRF     Finish/Correction/Final  Pts",
269:         try:
270:             print "/%2i"%start.casualweight
271:         except AttributeError:
272:             print "Mid"
273:         print>>out," -- "+"-"*27+" "+"-"*10+" "+"-"*27+" ---- ---"
274: 
275:         try:
276:             start.divisionname.levelracing
277:             lineprinter=print_level_racing_result_line
278:         except:
279:             lineprinter=print_result_line
280: 
281:         interspacer=False
282:         for entry in entries:
283:             try:
284:                 pts="%4.1f"%entry.seriespoints
285:             except AttributeError:
286:                 pts=""
287:             try:
288:                 cpt="%+3i"%entry.casualpoints
289:             except AttributeError:
290:                 cpt=""
291:             lineprinter(str(entry.ranking),entry,pts,cpt)
292:             interspacer=True
293: 
294:         for entry in failedentries:
295:             if interspacer: print>>out
296:             try:
297:                 entry.fleet.inseries
298:             except AttributeError:
299:                 print_result_line("",entry,"","")
300:             else:
301:                 if entry.finishcondition==enumcond.FinishCondEnum.DNC:
302:                     lineprinter("",entry,"DNC","")
303:                 else:
304:                     lineprinter("",entry,"?","")
305:             interspacer=False
306:         print>>out
307: 
308: def print_handicapsheet_weirdness(race,handicapsheet,out=sys.stdout):
309:     assert isinstance(race,racesheet.RaceSheetEntry)
310: 
311:     def print_weird_title(title):
312:         print>>out," %-27s  Division  Fleet/PHRF      "\
313:             "Finish/Correction/Final"%str(title)
314:         print>>out," "+"-"*27+"  --------  "+"-"*10+"  "+"-"*27
315: 
316:     def print_weird(division,entry):
317:         (bs,bn,fleet,rating,fc,ft,relco,ftco)=finish_fields(entry)
318:         print>>out," %8s:%-18s   %7s  %-6s %3s  %3s %8s %5s %8s"%(
319:             bs,bn,division,fleet,rating,fc,ft,relco,ftco
320:         )
321: 
322:     duplicatelist=handicapsheet.adjoin_list(["duplicates"])
323:     if duplicatelist: print_weird_title("Duplicate Entries")
324:     for (boat,boatentries) in base.adjoin_hierarchy(duplicatelist,
325:         ["boat",("start",None,racesheet.StartSheetEntry(race,UNKNOWN))]
326:     ):
327:         for (start,weirdentries) in boatentries:
328:             for entry in weirdentries:
329:                 print_weird(start.divisionname,entry)
330:         print>>out
331: 
332:     peculiarlist=handicapsheet.adjoin_list(["peculiar"])
333:     if peculiarlist: print_weird_title("Peculiar Finish Entries")
334:     for (boat,boatentries) in base.adjoin_hierarchy(peculiarlist,
335:         ["boat",("start",None,racesheet.StartSheetEntry(race,UNKNOWN))]
336:     ):
337:         for (start,weirdentries) in boatentries:
338:             for entry in weirdentries:
339:                 print_weird(start.divisionname,entry)
340:     if peculiarlist: print>>out
341: 
342:     unregisteredlist=handicapsheet.adjoin_list(
343:         [("fleet",enumstat.FleetEnum.UNREGISTERED)]
344:     )
345:     if unregisteredlist: print_weird_title("Unregistered Boat Entries")
346:     for (boat,boatentries) in base.adjoin_hierarchy(unregisteredlist,
347:         ["boat",("start",None,racesheet.StartSheetEntry(race,UNKNOWN))]
348:     ):
349:         for (start,weirdentries) in boatentries:
350:             for entry in weirdentries:
351:                 print_weird(start.divisionname,entry)
352:     if unregisteredlist: print>>out
353: 
354: ######## ######## print race rc sheets ######## ########
355: 
356: def rc_fields(entry):
357:     (bs,bn)=(entry.boat.sailnumber,entry.boat.boatname)
358:     try:
359:         div=str(entry.seriesdivision.divisionname)
360:         pts="AVG"
361:     except AttributeError:
362:         div=""
363:         pts=""
364:     return (bs,bn,div,pts)
365: 
366: def print_rc(race,rcsheet,out=sys.stdout):
367:     assert isinstance(race,racesheet.RaceSheetEntry)
368: 
369:     print>>out,"Race Committee for %s"%str(race.racename)
370:     print>>out
371: 
372:     if rcsheet:
373:         print>>out," Race Committee Automatic Series Redress  "+\
374:         " "*13+"Division"+" "*12+" Pts"
375:         print>>out," --"+" "*12+"-"*27+" "*13+"--------"+" "*12+"-"*4
376:     for entry in rcsheet:
377:         boat=entry.boat
378:         print>>out,(
379:             " RC"+" "*12+"%8s:%-18s"+" "*13+" %7s"+" "*12+"%4s"
380:         )%rc_fields(entry)
381:     if rcsheet: print>>out
382: 
383: ######## ######## print series score sheets ######## ########
384: 
385: def print_series_scoresheet_in_fleet(series,scoretab,out=sys.stdout):
386:     assert isinstance(series,scoresheet.SeriesEntry)
387: 
388:     def raceinseries(racename,seriesname):
389:         if seriesname==series.seriesname:
390:             return racename
391:         else:
392:             raise AttributeError
393:     racelist=eventstat.RACENAMES.obverse_list([("seriesname",raceinseries)])
394:     raceabbrev=" ".join(["%5s"%r.abbrev for r in racelist])
395: 
396:     def prefigure_format_line(seriesdivision):
397:         f=[]
398:         starts=seriesdivision.starts[:]
399:         for racename in racelist:
400:             if starts and racename==starts[0].race.racename:
401:                 f.append("%5s")
402:                 del starts[0]
403:             else:
404:                 f.append("     ")
405:         assert starts==[]
406:         return " ".join(f)
407: 
408:     def print_result_line(fo,rk,score):
409:         (bs,bn)=score.boat.sailnumber,score.boat.boatname
410:         displays=[
411:             [" ","*"][score.excluded[i]]+display
412:             for (i,display) in enumerate(score.displays)
413:         ]
414:         tts=fo%tuple(displays)
415:         pts="%5.1f"%score.totalpoints
416: 
417:         print>>out," %2s  %8s:%-18s   %35s    %5s"%(rk,bs,bn,tts,pts)
418: 
419:     print>>out,"Series Results for %s"%str(series.seriesname)
420:     print>>out
421: 
422:     for (seriesdivision,fleets) in scoretab.adjoin_hierarchy(
423:         ["seriesdivision","fleet","fleetranking"]
424:     ):
425:         print>>out," Results for %-7s    %4.1f=DNC   %35s    Total"%(
426:             seriesdivision.divisionname,
427:             seriesdivision.dnc,
428:             raceabbrev,
429:         )
430:         print>>out," --  "+"-"*27+"   "+"-"*35+"   "+"-"*6
431: 
432:         for (fleet,ranklevels) in fleets:
433:             flt=abbrev(fleet)
434:             if flt:
435:                 print>>out," %-6s Fleet"%flt
436:                 print>>out," --  "+"-"*27+"   "+\
437:                     "-"*35+"   "+"-"*6
438: 
439:             fo=prefigure_format_line(seriesdivision)
440:             for ranking,scoreentries in ranklevels:
441:                 for score in scoreentries:
442:                     print_result_line(
443:                         fo,str(score.ranking),score
444:                     )
445:             print>>out
446:         print>>out
447: 
448:     for (
449:         seriesdivision,duplicatescores
450:     ) in base.adjoin_hierarchy(
451:         scoretab.adjoin_sort(["duplicates"]),["seriesdivision"] # could be heap
452:     ):
453:         print>>out," Boats with Irreconcileable Duplicate"\
454:         " Registration within %-7s"%str(seriesdivision.divisionname)
455:         print>>out," --  "+"-"*27+"  "+"-"*45
456:         for score in duplicatescores:
457:             print>>out,"     %8s:%-18s"%(
458:                 score.boat.sailnumber,score.boat.boatname
459:             )
460:         print>>out
461: 
462:     print>>out
463: 
464: def print_championship_scoresheet_in_fleet(
465:     championship,scoretab,out=sys.stdout
466: ):
467:     assert isinstance(championship,scoresheet.ChampionshipEntry)
468: 
469:     racelist=[r.racename for r in championship.races]
470:     raceabbrev=" ".join(["%5s"%r.abbrev for r in racelist])
471:     ttlen=len(raceabbrev)
472: 
473:     def prefigure_format_line(champdivision):
474:         f=[]
475:         starts=champdivision.starts[:]
476:         for racename in racelist:
477:             if starts and racename==starts[0].race.racename:
478:                 f.append("%5s")
479:                 del starts[0]
480:             else:
481:                 f.append("     ")
482:         assert starts==[]
483:         return " ".join(f)
484: 
485:     def print_result_line(fo,rk,score):
486:         (bs,bn)=score.boat.sailnumber,score.boat.boatname
487:         displays=[
488:             [" ","*"][score.excluded[i]]+"%3.1f"%points
489:             for (i,points) in enumerate(score.points)
490:         ]
491:         pts="%5.1f"%score.totalpoints
492: 
493:         print>>out," %2s  %8s:%-18s  "%(
494:             rk,bs,bn
495:         )+fo%tuple(displays)+"   %5s"%(
496:             pts
497:         )
498: 
499:     print>>out,"Championship Results for the Year"
500:     print>>out
501: 
502:     for (champdivision,fleets) in scoretab.adjoin_hierarchy(
503:         ["championshipdivision","fleet","fleetranking"]
504:     ):
505:         print>>out," Results for %-7s              "%(
506:             champdivision.divisionname,
507:         )+raceabbrev+"   Total"
508:         print>>out," --  "+"-"*27+"  "+"-"*ttlen+"  "+"-"*6
509: 
510:         for (fleet,ranklevels) in fleets:
511:             flt=abbrev(fleet)
512:             if flt:
513:                 print>>out," %-6s Fleet"%flt
514:                 print>>out," --  "+"-"*27+"  "+"-"*ttlen+"  "+"-"*6
515: 
516:             fo=prefigure_format_line(champdivision)
517:             for ranking,scoreentries in ranklevels:
518:                 for score in scoreentries:
519:                     print_result_line(
520:                         fo,str(score.ranking),score
521:                     )
522:             print>>out
523:         print>>out
524:     print>>out
525: 
526: ######## ######## print casual score sheets ######## ########
527: 
528: def print_midfleet_scoresheet(casual,scoretab,out=sys.stdout):
529:     assert isinstance(casual,scoresheet.CasualEntry)
530: 
531:     formatline=" ".join(["%4s"]*casual.completed)
532:     raceabbrev=formatline%tuple([r.racename.abbrev for r in casual.races])
533: 
534:     print>>out,"Casual Results for the Year Using the Mid-Fleet Formula"
535:     print>>out
536: 
537:     print>>out," Combined Results       +2/0=DNC  "\
538:         +raceabbrev+"  Total  Score"
539:     print>>out," --  "+"-"*27+"  "+"-"*len(raceabbrev)+"  "+"-"*12
540: 
541:     for ranking,score in scoretab.adjoin_sort(["ranking"]): # could be heap
542:         print>>out," %2s  %8s:%-18s  "%(
543:             ranking,score.boat.sailnumber,score.boat.boatname
544:         )+formatline%tuple(
545:             score.displays
546:         )+"  %+4i %7s"%(
547:             score.totalpoints,score.displayz
548:         )
549:         dweights=[
550:             ["/","*"][score.excluded[i]]+display
551:             for (i,display) in enumerate(score.dweights)
552:         ]
553:         print>>out," "*34+formatline%tuple(
554:             dweights
555:         )+"  %4i"%(
556:             score.totalweight
557:         )
558:         print>>out
559: 
560:     print>>out
561: 
562: #### printsheet.py #### python package PyScore.tabulate module printsheet ####