Last active
August 6, 2021 13:47
-
-
Save piskvorky/ce48a4292fdf878f42495d027949ac45 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
""" | |
Script to calculate possible final standings for "combined climbing" (Olympics 2020 format) | |
from incomplete in-progress results: | |
BEST-WORST POSSIBLE FINAL STANDINGS | |
=================================== | |
A. Gines Lopez: 1-2 | |
A. Ondra: 1-6 | |
C. Duffy: 5-7 | |
J. Schubert: 3-7 | |
M. Mawem: 5-6 | |
N. Coleman: 2-3 | |
T. Narasaki: 4-4 | |
BEST POSSIBLE RESULT FOR A. Ondra | |
1. A. Ondra: 24.0 (current event 1) | |
2. A. Gines Lopez: 28.0 (current event 4) | |
3. N. Coleman: 30.0 (current event 5) | |
4. T. Narasaki: 36.0 (current event 6) | |
5. M. Mawem: 42.0 (current event 7) | |
6. C. Duffy: 60.0 (current event 3) | |
7. J. Schubert: 70.0 (current event 2) | |
WORST POSSIBLE RESULT FOR A. Ondra | |
1. A. Gines Lopez: 28.0 (current event 4) | |
2. N. Coleman: 30.0 (current event 5) | |
3. J. Schubert: 35.0 (current event 1) | |
4. T. Narasaki: 36.0 (current event 6) | |
5. M. Mawem: 42.0 (current event 7) | |
6. A. Ondra: 48.0 (current event 2) | |
7. C. Duffy: 60.0 (current event 3) | |
Ondra did finish 6th :-( | |
""" | |
from itertools import permutations | |
from collections import namedtuple | |
# Current in-progress results: comma-separated athletes, their points so far, their | |
# points in the current combined event. | |
# | |
# No "current event points" means the athlete is yet to go (unknown result). | |
# So if the current event hasn't started yet, leave the third column all empty. | |
INPUT = """ | |
# ATHLETE NAME, TOTAL POINTS SO FAR, CURRENT POINTS IN THIS EVENT | |
J. Garnbret, 5.00, 1 | |
A. Miroslaw, 8.00, 5 | |
A. Noguchi, 8.00, 2 | |
M. Nonaka, 9.00, | |
A. Jaubert, 12.00, 4 | |
B. Raboutou, 14.00, 3 | |
J. Pilz, 30.00, | |
C. Seo, 56.00, | |
""" | |
# INPUT = """ | |
# ATHLETE NAME, TOTAL POINTS SO FAR, CURRENT POINTS IN THIS EVENT | |
# A. Ondra, 24.00, 1 | |
# J. Schubert, 35.00, | |
# A. Gines Lopez, 7.00, 3 | |
# N. Coleman, 6.00, 4 | |
# M. Mawem, 6.00, 6 | |
# T. Narasaki, 6.00, 5 | |
# C. Duffy, 20.00, 2 | |
# """ | |
Competitor = namedtuple("Competitor", "name score current_event") | |
def print_results(results): | |
for pos, result in enumerate(sorted(results, key=lambda result: result.score), start=1): | |
print(f"{pos}. {result.name}: {result.score} (current event {result.current_event if result.current_event > 0 else 'YET TO GO'})") | |
def load_results(text): | |
result = [] | |
for line in text.splitlines(): | |
line = line.strip().replace('\t', ',') | |
if not line or line.startswith('#'): | |
continue | |
name, score, current_event = line.split(',') | |
if current_event.strip() in ('', '-'): | |
current_event = 0 | |
competitor = Competitor(name=name.strip(), score=float(score), current_event=float(current_event)) | |
result.append(competitor) | |
return result | |
def print_possibilities(best, worst): | |
print("\nBEST-WORST POSSIBLE FINAL STANDINGS") | |
print("===================================") | |
for name in sorted(best): | |
print(f'{name}: {int(best[name][0])}-{int(worst[name][0])}') | |
def show_athlete(name, best, worst): | |
print(f"\nBEST POSSIBLE RESULT FOR {name}") | |
print_results(best[name][1]) | |
print(f"\nWORST POSSIBLE RESULT FOR {name}") | |
print_results(worst[name][1]) | |
competitors = load_results(INPUT) | |
print('\nCURRENT STANDINGS') | |
print('=================') | |
print_results(competitors) | |
best_possible, worst_possible = {}, {} | |
for assumed in permutations(competitors): | |
good, prev = True, 0 | |
for c in assumed: | |
if c.current_event > 0: | |
if c.current_event < prev: | |
good = False | |
prev = c.current_event | |
if not good: | |
continue # this event result does not respect the already-known athlete positions => ignore | |
assumed = [ | |
Competitor(name=c.name, score=c.score * pos_now, current_event=pos_now) | |
for pos_now, c in enumerate(assumed, start=1) | |
] | |
# print_results(assumed) | |
for pos, c in enumerate(sorted(assumed, key=lambda c: c.score), start=1): | |
pos_now = best_possible.get(c.name, (len(assumed) + 1, None))[0] | |
if pos_now > pos: | |
best_possible[c.name] = (pos, assumed) | |
pos_now = worst_possible.get(c.name, (0, None))[0] | |
if pos_now < pos: | |
worst_possible[c.name] = (pos, assumed) | |
print_possibilities(best_possible, worst_possible) | |
show_athlete(competitors[0].name, best_possible, worst_possible) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment