diff --git a/bin/p-score b/bin/p-score new file mode 100755 index 0000000000000000000000000000000000000000..cd15d5ce30ccbfe08726e41bccd0042252b8a116 --- /dev/null +++ b/bin/p-score @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 +# Generátor výsledkové listiny pro MO-P + +import argparse +from sqlalchemy.orm import joinedload + +import mo.db as db +from mo.score import Score +from mo.util import die, init_standalone + +parser = argparse.ArgumentParser(description='Vygeneruje výsledkovou listinu MO-P') +parser.add_argument('year', type=int) +parser.add_argument('seq', type=int) + +args = parser.parse_args() +init_standalone() +sess = db.get_session() + + +def get_results(round, contests): + results = {} + for contest in contests: + place_code = contest.place.get_code() + print(f"Počítám oblast {place_code}") + + score = Score(round, contest) + results[place_code] = score.get_sorted_results() + + for msg in score.get_messages(): + if msg[0] != 'info': + print(f'\t{msg[0].upper()}: {msg[1]}') + + return results + + +def write_tex(round, tasks, contests, results): + with open('final.tex', 'w') as out: + out.write(r'\def\HranicePostupu{%s}' % (round.score_winner_limit,) + "\n") + out.write(r'\def\HraniceUspesnychResitelu{%s}' % (round.score_successful_limit,) + "\n") + out.write('\n') + for c in contests: + res = results[c.place.get_code()] + if round.seq == 2: + out.write(r'\kraj{%s}' % c.place.name + '\n') + if not res: + out.write(r'\nobody' + '\n') + out.write(r'\endkraj' + '\n\n') + continue + + out.write(r'\begintable' + '\n') + prev_typ = "" + + for r in res: + if r.winner: + typ = 'v' + elif r.successful: + typ = 'u' + else: + typ = 'n' + if typ != prev_typ: + if prev_typ: + out.write(r'\sep%s' % typ) + prev_typ = typ + out.write(r'\%s' % typ) + + cols = [] + o = r.order + if not r.successful or o.continuation: + cols.append("") + elif o.span > 1: + cols.append(f'{o.place}.--{o.place + o.span - 1}.') + else: + cols.append(f'{o.place}.') + + cols.append(r.user.full_name()) + cols.append(r.pant.school_place.name) + cols.append(r.pant.grade) + + sol_map = r.get_sols_map() + for t in tasks: + s = sol_map.get(t.task_id) + if s is not None: + cols.append(s.points) + else: + cols.append('--') + + cols.append(r.get_total_points()) + + out.write("".join(['{' + str(col) + '}' for col in cols]) + '\n') + + out.write(r'\endtable' + '\n') + if round.seq == 2: + out.write(r'\endkraj' + '\n\n') + + +def write_html(round, tasks, contests, results): + num_cols = 4 + len(tasks) + 1 + with open('final.html', 'w') as out: + for c in contests: + out.write(f'<tr><th colspan={num_cols}>{c.place.name}\n') + + res = results[c.place.get_code()] + if not res: + out.write(f'<tr class=nobody><td colspan={num_cols}>Nikdo se nezúčastnil.\n') + out.write(f'<tr><td colspan={num_cols}>\n\n') + continue + + for r in res: + if r.winner: + out.write('<tr class=marked>') + elif r.successful: + out.write('<tr class=success>') + else: + out.write('<tr>') + + cols = [] + o = r.order + if not r.successful or o.continuation: + cols.append("") + elif o.span > 1: + cols.append(f'{o.place}.–{o.place + o.span - 1}.') + else: + cols.append(f'{o.place}.') + + cols.append(r.user.full_name()) + cols.append(r.pant.school_place.name) + cols.append(r.pant.grade) + + sol_map = r.get_sols_map() + for t in tasks: + s = sol_map.get(t.task_id) + if s is not None: + cols.append(s.points) + else: + cols.append('–') + + cols.append(r.get_total_points()) + + out.write("".join(['<td>' + str(col) for col in cols]) + '\n') + + out.write(f'<tr><td colspan={num_cols}>\n\n') + + +round = sess.query(db.Round).filter_by(year=args.year, category='P', seq=args.seq).one() +print(f"Kolo {round.round_code()}") + +tasks = sess.query(db.Task).filter_by(round=round).order_by(db.Task.code).all() + +contests = (sess.query(db.Contest) + .filter_by(round=round) + .options(joinedload(db.Contest.place)) + .all()) +assert contests +contests.sort(key=lambda c: c.place.get_code()) + +results = get_results(round, contests) +write_tex(round, tasks, contests, results) +write_html(round, tasks, contests, results)