PyScore

001: # -*- python -*-
002: ###### casual.py ###### python package PyScore.tabulate module casual ######
003: 
004: # PyScore
005: # a race scoring programme
006: # written by Matt Draisey
007: # 2004 April 6
008: 
009: reloadables=[]
010: 
011: ###### casual.py ###### python package PyScore.tabulate module casual ######
012: 
013: import sys,math
014: from relational import base
015: #from standing import eventstat
016: from tabulate import scoresheet
017: from utility.verbose import vv,vvv,vvvv,debug
018: 
019: ######## ######## some actual working code ######## ########
020: 
021: def startcompleted(start):
022:     """
023:     Races are assumed to be completed for any race with startsheet entries
024:     even if there are no handicapsheet entries in this start; however,
025:     racesheet entries by themselves do not imply a corresponding start
026:     in all or any divisions.
027: 
028:     An explicit "abandoned" attribute in either the racesheet or startsheet
029:     is required if the existence of a startsheet entry is to be overruled.
030:     """
031: 
032:     try: start.abandoned
033:     except AttributeError:
034:         try: start.race.abandoned
035:         except AttributeError: pass
036:         else: raise AttributeError
037:     else: raise AttributeError
038:     return start
039: 
040: def tabulate_casual(
041:     racesheetvalues,startsheetvalues,handicapsheet,rcsheet,
042:     casual,midfleetscorenew,midfleetscoretab
043: ):
044:     print>>vv,"TABULATING CASUAL RESULTS"
045: 
046:     racelist=scoresheet.ScoreList(
047:         racesheetvalues.converse_sort(["abandoned"]) # could be heap
048:     )
049: 
050:     startlist=scoresheet.ScoreList(
051:         startsheetvalues.obverse_sort( # could be heap
052:             [("race",lambda s,r: startcompleted(s))]
053:         )
054:     )
055: 
056:     handicaplist=scoresheet.ScoreList(
057:         handicapsheet.obverse_sort([ # could be heap
058:             "starter",
059:             # ("fleet",lambda entry,fleet: fleet.inseries),
060:             ("start",lambda e,s: startcompleted(s))
061:         ])
062:     )
063: 
064:     rclist=scoresheet.ScoreList(rcsheet)
065: 
066:     infer_registration(handicaplist,midfleetscorenew)
067:     collect_casual(racelist,handicaplist,rclist,casual,midfleetscoretab)
068: 
069: def infer_registration(handicapsheet,scorenew):
070:     """
071:     Register any boat that has ever raced casually.
072:     """
073: 
074:     print>>vvv,"  INFER REGISTRATION"
075: 
076:     #handicapsheet.obverse_filter([("fleet",enumstat.FleetEnum.CASUAL)])
077: 
078:     for (boat,entries) in base.adjoin_hierarchy(
079:         handicapsheet,
080:         ["boat"]
081:     ):
082:         scorenew(boat)
083: 
084: def collect_casual(racesheet,handicapsheet,rcsheet,casual,scoretab):
085:     """
086:     Work on casually registered boats.
087:     """
088: 
089:     print>>vvv,"  COLLECT RESULTS"
090: 
091:     casual.races=racesheet
092:     casualindex=dict([(r,i) for (i,r) in enumerate(racesheet)])
093: 
094:     completed=len(racesheet)
095:     excluded=casual.casualname.exclusions[completed]
096:     included=completed-excluded
097:     casual.completed=completed
098:     casual.excluded=excluded
099:     casual.included=included
100: 
101:     casual.numberofentrants=len(scoretab)
102: 
103:     for (boat,[scores,entries,rcs]) in base.adjoin_polyhierarchy(
104:         scoretab,handicapsheet,rcsheet,["boat"]
105:     ):
106:         try:
107:             boatscore=scores.next()
108:         except StopIteration:
109:             continue
110:         
111:         entrylist=scoresheet.ScoreList(entries)
112: 
113:         boatscore.handicaps=[None]*completed
114:         boatscore.displays=[None]*completed
115:         boatscore.dweights=[None]*completed
116:         boatscore.copoints=[None]*completed
117: 
118:         for (start,entry) in base.adjoin_filter(entrylist,["start"]):
119:             i=casualindex[start.race]
120:             boatscore.handicaps[i]=entry
121: 
122:             if isinstance(entry.casualpoints,str):
123:                 points=entry.casualpoints.upper()
124:             else:
125:                 points=entry.casualpoints
126:             try:
127:                 weight=entry.casualweight
128:             except AttributeError:
129:                 weight=start.casualweight
130: 
131:             try:
132:                 racez=points/math.sqrt(weight)
133:             except ValueError:
134:                 boatscore.displays[i]=points
135:                 boatscore.dweights[i]=""
136:                 boatscore.copoints[i]=((1,),0,0)
137:             except ZeroDivisionError:
138:                 boatscore.displays[i]="%+i"%points
139:                 boatscore.dweights[i]=""
140:                 if points>0:
141:                     boatscore.copoints[i]=((1,),points,0)
142:                 else:
143:                     boatscore.copoints[i]=((0,0.000),0,0)
144:             else:
145:                 racez=round(racez,3)
146:                 boatscore.displays[i]="%+i"%points
147:                 boatscore.dweights[i]="%i"%weight
148:                 boatscore.copoints[i]=((0,racez),points,weight)
149: 
150:         rclist=scoresheet.ScoreList(rcs)
151: 
152:         for (race,entry) in base.adjoin_filter(rclist,["race"]):
153:             i=casualindex[race]
154:             boatscore.handicaps[i]=entry
155: 
156:             boatscore.displays[i]=""
157:             boatscore.dweights[i]=""
158:             boatscore.copoints[i]=((0,0.000),0,0)
159: 
160:         for (i,d) in enumerate(boatscore.displays):
161:             if d==None:
162:                 boatscore.displays[i]="DNC" # DNC
163:                 boatscore.dweights[i]=""
164:                 boatscore.copoints[i]=((1,),+2,0)
165:                 # you sailed in a fleet of one --- and lost
166: 
167:     total_scores(casual,scoretab)
168: 
169: def total_scores(seriesdivision,scoretab):
170:     """
171:     Sum all included races and provide sufficient information
172:     to rank boats according to rule A8.
173:     """
174: 
175:     for score in scoretab:
176:         sorted=[(z,-i,p,w) for (i,(z,p,w)) in enumerate(score.copoints)]
177:         sorted.sort()
178: 
179:         score.excluded=[False]*seriesdivision.completed
180:         for (z,j,p,w) in sorted[seriesdivision.included:]:
181:             score.excluded[-j]=True
182: 
183:         del sorted[seriesdivision.included:]
184:         score.totalpoints=sum([p for (z,j,p,w) in sorted])
185:         score.totalweight=sum([w for (z,j,p,w) in sorted])
186:         sorted=[z for (z,j,p,w) in sorted]
187: 
188:         reversed=[(z,-w) for (z,p,w) in score.copoints]
189:         reversed.reverse()
190: 
191:         try:
192:             scorez=score.totalpoints/math.sqrt(score.totalweight)
193:         except ZeroDivisionError:
194:             if score.totalpoints>0:
195:                 score.displayz="      +"
196:                 score.total=((1,),sorted,reversed)
197:             else:
198:                 score.displayz="  0.000"
199:                 score.total=((0,0.000),sorted,reversed)
200:         else:
201:             scorez=round(scorez,3)
202:             score.displayz="%+6.3f"%scorez
203:             score.total=((0,scorez),sorted,reversed)
204: 
205:     rank=1
206:     for (total,scoreentries) in scoretab.adjoin_hierarchy(["total"]):
207:         sharedrank=rank
208:         sharedtotals=[e for e in scoreentries]
209:         for seriesscore in sharedtotals:
210:             seriesscore.ranking=sharedrank
211:             rank+=1
212: 
213: ###### casual.py ###### python package PyScore.tabulate module casual ######