Skip to content

Instantly share code, notes, and snippets.

@piskvorky
Last active August 6, 2021 13:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save piskvorky/ce48a4292fdf878f42495d027949ac45 to your computer and use it in GitHub Desktop.
Save piskvorky/ce48a4292fdf878f42495d027949ac45 to your computer and use it in GitHub Desktop.
#!/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