from pyiofload import * from merge_races import do_merge_races from trophyPDF import TrophyPdf import os # http://www.fiso.emr.it/wp0/wp-content/uploads/2022/06/TrofeoEMR_parz_2022_20220615.pdf # https://www.fiso.emr.it/wp0/trofeoemr_parz_2022_20220615/ SPRINT_RACES = { 2024149, # Parma 2024157, # Piacenza 2024151, # Bologna 2024999, # Busseto } DOUBLE_POINTS = {2024999, } yeartodo = '2024' outfile = f'TrofeoEMR_f_{yeartodo}.pdf' # source_dir = 'E:/O/Trofeo_GPeroni_' + yeartodo source_dir = 'xmls' source_ext = '.xml' class_renames = {'W18': 'W15-18', 'M18': 'M15-18', # 'M 13/14': 'M14', # 'W 13/14': 'W14', # 'M 17/18': 'M15-18', # 'W 17/18': 'W15-18' } to_be_merged = ( # (nome, file1, file2) ('Parma', 'Parma1_2024149.xml', 'Parma2_2024150.xml', 2024149), ('Bologna', 'Bologna1_2024151.xml', 'Bologna2_2024152.xml', 2024151), ('Piacenza', 'Piacenza1_2024157.xml', 'Piacenza2_2024163.xml', 2024157), # ('Piacenza', 'Piacenza1_2023224.xml', 'Piacenza2_2023225.xml', 2023224), # ('Cesena', 'Cesena1_2023232.xml', 'Cesena2_2023233.xml', 2023232), ) EMR_Clubs = ('0098', '0206', '0221', '0255', '0275', '0610', '0738', '0746', '0761', '0769', '0793', '0794', '0821', '0840') class TrophyRunner: """A runner ranking in the Championship.""" def __init__(self, id_=None, clubid=None, club=None, classid=None, fullname=None, original_id=None, name=None, family=None, championship=None): self.id_ = id_ self.original_id = original_id self.fullname = fullname self.name = name self.family = family self.clubid = clubid self.club = club self.class_ = classid self.total_score = 0.0 self.net_score = 0.0 self.races = {} # A dictionry in the form of {race_id: score} self.discarded = [] # A list of the discarded races self.championship = championship self.rank = None # def __str__(self): # return f'{self.fullname} {self.discarded=}' def get_a_race_score(self, race_id): return self.races.get(race_id, 0.0) # if race_id in self.races: # return self.races[race_id] # else: # return 0.0 def add_a_race(self, raceid=None, score=0.0): if raceid is not None: self.races[raceid] = score self.total_score += score def compute_scarti(self, trophy, scarti=0, sprint_to_discard=1): self.net_score = self.total_score self.discarded = [] # Clear the list of the discarded races sprint_races = [race for race in trophy.races if trophy.is_sprint(race)] sprint_sorted_list = sorted(sprint_races, key=self.get_a_race_score) self.discarded = sprint_sorted_list[:sprint_to_discard] # Le sprint da scartare di sicuro remaining_races = [race_id for race_id in trophy.races if race_id not in self.discarded] to_discard = scarti - len(self.discarded) # if self.name == 'Olmo': # print(f'------------- {self.fullname=} {scarti=}') # print(f'------------- {sprint_races=}') # print(f'------------- {sprint_sorted_list=}') # print(f'------------- {self.discarded=}') # print(f'------------- {remaining_races=}') # print(f'------------- {to_discard=}') if to_discard >= 1: # do create a list of races, sorted by their scores sl = sorted(remaining_races, key=self.get_a_race_score) self.discarded.extend(sl[0:to_discard]) # Now do adj the net score for dis in self.discarded: self.net_score -= self.get_a_race_score(dis) def __str__(self): rstr = f'{self.id_:13s} {self.fullname:25s} {self.class_:3.3s} rank:{self.rank:2} pti: {self.net_score:6.2f} ({self.total_score:6.2f})' for race_id in self.races: race_name = self.championship.races[race_id].name rstr += ' [{}{}{:6.2f}]'.format(race_name, ' ' if race_id not in self.discarded else '-', self.races[race_id]) return rstr def to_str_list(self, races): clubname = self.club.replace('A.S.D.', '').replace('POLISPORTIVA', 'Pol').replace( 'ISTITUTO COMPRENSIVO', 'IC').replace('ATLETICA', 'Atl.').replace( 'ORIENTEERING', 'Or').replace('Orienteering', 'Or') rt = [self.fullname, '{:4s} {:17.17s}'.format(self.clubid, clubname.replace('A.S.D.', '').strip()), '{:7.2f}'.format(self.net_score), '{:7.2f}'.format(self.total_score) ] for race in races: if race in self.races: if race in self.discarded: rt.append('_{:6.2f}_'.format(self.races[race])) else: rt.append('{:6.2f}'.format(self.races[race])) else: rt.append(' ') return rt class TrophyClass: """A Class that is part of a Championship""" def __init__(self, id_=None): self.id_ = id_ self.runners = [] # A list of the runner'id(s) belonging to this class. class Championship: """A class representing a Championship composed by many races""" def __init__(self, filename_=None, classes=None): self.races = {} # Key = race_id, Values = the Race itself. self.classes = {} # Key = classes_id, Values = the TrophyClass itself. self.runners = {} # Key = runner_id, Values = the TrophyRunner itself. self.clubs = {} # Key = club_id, Values = the Club itself. self.trophy_classes = classes # A list/tuple of the classes involved in the Championship. if filename_ is not None: self.add_a_race(filename_or_race=filename_) def is_sprint(self, raceid) -> bool: fiso_code = self.races[raceid].fiso_code sprint = fiso_code in SPRINT_RACES # print(f'IS SPRINT {sprint} {raceid} {fiso_code}') return sprint def add_a_race(self, filename_or_race=None, name=None, class_remap=None, clubs_ko=None, k_factor=1.0, fiso_code=0): """It adds a Race starting from an iof xml file""" if filename_or_race is None: return # print(filename_or_race, type(filename_or_race)) # print('#' * 80) if type(filename_or_race) is str: race = Race(fiso_code=int(fiso_code)) race.load_from_iofxml(filename_=filename_or_race, class_remap=class_remap, clubs_ko=clubs_ko, avoid_unk=True) else: race = filename_or_race[0] if name is not None: race.name = name raceid = 'Race{:02d}'.format(1 + len(self.races)) print('{} {} ({}) {}'.format(raceid, race.name, filename_or_race, race.date)) strclasses = '' for cl in sorted(race.classes.keys()): strclasses += ' {}'.format(cl) print(strclasses) race.adj_scores(k_factor=k_factor) self.races[raceid] = race # Beware of duplicates!!! @TODO print('Race_id:', raceid) # print('#' * 80) # if 'Race07' == raceid: # for rr, r in race.runners.items(): # print(rr, r) for cl_ in race.classes: if cl_ in self.trophy_classes and (cl_ not in self.classes): new_trophy_class = TrophyClass(id_=cl_) self.classes[cl_] = new_trophy_class for rn in race.runners: dbg = False # if rn == 'TO1637': # dbg = True # else: # dbg = False # Do keep up to date the organization dictionary orgid = race.runners[rn].clubid if orgid not in self.clubs: self.clubs[orgid] = race.clubs[orgid] runner_class = race.runners[rn].class_ runner_clubid = race.runners[rn].clubid trophy_runner_id = '{}-{}'.format(rn, runner_class) # if runner_class in self.trophy_classes and runner_clubid in EMR_Clubs: if runner_class in self.trophy_classes: # Add her/him if is part of a trophy class only if trophy_runner_id not in self.runners: # First time seen! Do add her/him! # print('============== ', race.runners[rn].name) new_trophy_runner = TrophyRunner(id_=trophy_runner_id, original_id=rn, fullname=race.runners[rn].full_name(), clubid=race.runners[rn].clubid, club=race.runners[rn].club, classid=runner_class, name=race.runners[rn].name, family=race.runners[rn].family, championship=self ) self.runners[trophy_runner_id] = new_trophy_runner else: # The runner is already present in the TrophyRunner database if self.runners[trophy_runner_id].class_ != runner_class: print('Runner Class mismatch!! {} prev:{} now:{}'.format( self.runners[trophy_runner_id].fullname, self.runners[trophy_runner_id].class_, runner_class)) self.runners[trophy_runner_id].add_a_race(raceid=raceid, score=race.runners[rn].score) if dbg: print('----------', self.runners[trophy_runner_id]) if trophy_runner_id not in self.classes[runner_class].runners: self.classes[runner_class].runners.append(trophy_runner_id) NSCARTI = 0 def main(): trofy_classes = ('WE', 'ME', 'W15-18', 'M15-18', 'W35', 'M35', 'W14', 'M14', 'W12', 'M12', 'W55', 'M55') # trofy_classes = ('M35', 'W18') to_be_skipped = set() for cr in to_be_merged: to_be_skipped.update(cr[1:]) print(f'TO Be Skipped: {to_be_skipped}') files = [] for (dirpath, dirnames, filenames) in os.walk(source_dir): for f in filenames: # print(f'Filename: {f}') if f.endswith(source_ext) and f not in to_be_skipped: files.append(os.path.join(dirpath, f)) print(f'found: {f}') break # for f in files: # print(os.path.splitext(f)) # print(files) race_list = [] for racename, r1, r2, fiso_code in to_be_merged: ff1 = os.path.join(source_dir, r1) ff2 = os.path.join(source_dir, r2) print(f'loading ---- {racename} {fiso_code}') race_list.append((do_merge_races(ff1, ff2, class_remap=class_renames, fiso_code=fiso_code), racename, class_renames, fiso_code)) print(files) for f in files: parts = os.path.basename(f).rstrip(source_ext).split('_') racename, fiso_code = parts race_list.append((f, racename, class_renames, fiso_code)) # print(race_list) clubs_ko = ('1000', '2055') trofeo20XX = Championship(classes=trofy_classes) # for r in race_list: for r in race_list: racefile, racename, remap, fiso_code = r if int(fiso_code) in DOUBLE_POINTS: kf = 2.0 else: kf = 1.0 print(f'RACENAME= {racename} {fiso_code} KF={kf} {type(fiso_code)}') trofeo20XX.add_a_race(filename_or_race=racefile, name=racename, class_remap=remap, clubs_ko=clubs_ko, k_factor=kf, fiso_code=fiso_code) def get_score(rrr): return trofeo20XX.runners[rrr].net_score # All runner iteration... # for rr in sorted(trofeo20XX.runners, key=get_score_from_runner, reverse=True): # print 'Totale Corridori: {}\n'.format(len(trofeo20XX.runners)) # for rr in trofeo20XX.runners: # print trofeo20XX.runners[rr] # Partecipants = {} # A dictionary with {raceid: participants} print(f'Numero Gare: {len(trofeo20XX.races)}') dup_runners = {} for rnr in trofeo20XX.runners: runner_obj = trofeo20XX.runners[rnr] # print(f'{str(runner_obj)}') if '-' in runner_obj.id_: fiso_id, *_ = runner_obj.id_.split('-') else: fiso_id = runner_obj.id_ if fiso_id in dup_runners: # print(f'MULTI-Class: {str(runner_obj)}') dup_runners[fiso_id].append(runner_obj) else: dup_runners[fiso_id] = [runner_obj,] runner_obj.compute_scarti(trophy=trofeo20XX, scarti=NSCARTI) print('-' * 91) race_columns = sorted(trofeo20XX.races, key=lambda x: trofeo20XX.races[x].date) print(race_columns) print(trofeo20XX.races.keys()) first_row = ['Rank', 'Atleta', 'Società', 'Al netto\ndegli scarti', 'Lordo'] for r in race_columns: race_name_bare = trofeo20XX.races[r].name race_name = race_name_bare if not trofeo20XX.is_sprint(r) else f'*{race_name_bare}' first_row.append('{:10.10s}\n{}'.format(race_name, trofeo20XX.races[r].date.split(' ')[0])) print(first_row) # print first_row[3] pdfreport = TrophyPdf(filename=outfile) result_tables = {} # A dictionary in the form {class_id : result_table} # for cl in trofeo20XX.classes: for cl in trofy_classes: first_row[1] = 'Categoria ({})'.format(cl) newtab = [first_row, ] print('#' * 40, ' {} ha {} partecipanti.'.format(cl, len(trofeo20XX.classes[cl].runners)), '#' * 40) rank = 1 for rnr in sorted(trofeo20XX.classes[cl].runners, key=get_score, reverse=True): # print(rnr) current_runner = trofeo20XX.runners[rnr] current_runner.rank = rank print(current_runner) tabrow = current_runner.to_str_list(race_columns) tabrow.insert(0, '{:d}'.format(rank)) newtab.append(tabrow) # print(tabrow) rank += 1 # for row in newtab: # print(len(row), row) # print(newtab) nrow = len(newtab) lrow = len(newtab[0]) while nrow < 4: newtab.append((' ',) * lrow) nrow += 1 pdfreport.add_table(table=newtab, title='Categoria {}'.format(cl)) # pdfreport.add_table(table=newtab) result_tables[cl] = newtab pdfreport.commit() for multir, runners in dup_runners.items(): if len(runners) > 1: print(' MULTI Categoria ') for runner in runners: shortened = str(runner)[14:] print(shortened) if __name__ == '__main__': main()