Last active
April 7, 2026 00:41
-
-
Save elibroftw/50c0a82da1ce9fd7982d3c85699a81c4 to your computer and use it in GitHub Desktop.
An easy way to rank items of your choosing, such as movies, tv shows, food/dishes.
This file contains hidden or 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
| import os | |
| import itertools | |
| import csv | |
| MOVIES = '/media/elijah/Big Dipper/Videos/Movies' | |
| TV_SHOWS = '/media/elijah/Big Dipper/Videos/TV Shows' | |
| SELECTION = MOVIES | |
| def get_dir_items(directory): | |
| """Return all top-level file names (without extension) and folder names in a directory.""" | |
| items = [] | |
| try: | |
| for entry in os.listdir(directory): | |
| full_path = os.path.join(directory, entry) | |
| if entry.startswith('.'): | |
| continue | |
| if os.path.isdir(full_path): | |
| items.append(entry) | |
| else: | |
| name, _ = os.path.splitext(entry) | |
| items.append(name) | |
| except FileNotFoundError: | |
| print(f"Error: Directory '{directory}' not found.") | |
| except PermissionError: | |
| print(f"Error: Permission denied for '{directory}'.") | |
| return items | |
| def get_items(): | |
| items = get_dir_items(SELECTION) | |
| if items: | |
| print(f"\nFound {len(items)} item(s) in '{os.path.dirname(SELECTION)}':") | |
| for i, item in enumerate(items, 1): | |
| print(f" {i}. {item}") | |
| else: | |
| print("No items found.") | |
| return items | |
| def _elo_update(winner_rating, loser_rating, k=32): | |
| """Return updated (winner_rating, loser_rating) after one match.""" | |
| expected_winner = 1 / (1 + 10 ** ((loser_rating - winner_rating) / 400)) | |
| expected_loser = 1 - expected_winner | |
| new_winner = winner_rating + k * (1 - expected_winner) | |
| new_loser = loser_rating + k * (0 - expected_loser) | |
| return new_winner, new_loser | |
| def top_10(arr): | |
| """ | |
| Compare every pair from arr via user input, rank using Elo, and print the top 10. | |
| Returns the full ranked list as [(item, elo_score), ...]. | |
| """ | |
| if len(arr) < 2: | |
| print("Need at least 2 items to compare.") | |
| return [] | |
| # Initialise Elo ratings and loss counters | |
| ratings = {item: 1000.0 for item in arr} | |
| losses = {item: 0 for item in arr} | |
| results = [] # store (winner, loser) tuples | |
| AUTO_LOSS_THRESHOLD = 10 | |
| pairs = list(itertools.combinations(arr, 2)) | |
| total = len(pairs) | |
| print(f"\nYou will be asked to choose the winner of {total} pair(s).\n") | |
| for idx, (a, b) in enumerate(pairs, 1): | |
| a_eliminated = losses[a] >= AUTO_LOSS_THRESHOLD | |
| b_eliminated = losses[b] >= AUTO_LOSS_THRESHOLD | |
| if a_eliminated and b_eliminated: | |
| # Both are eliminated — award win to whoever has fewer losses (arbitrary tiebreak) | |
| winner, loser = (a, b) if losses[a] <= losses[b] else (b, a) | |
| print(f"[{idx}/{total}] Auto-loss (both eliminated): {loser} loses to {winner}") | |
| elif a_eliminated: | |
| winner, loser = b, a | |
| print(f"[{idx}/{total}] Auto-loss ({a} has {losses[a]} losses): {winner} wins over {loser}") | |
| elif b_eliminated: | |
| winner, loser = a, b | |
| print(f"[{idx}/{total}] Auto-loss ({b} has {losses[b]} losses): {winner} wins over {loser}") | |
| else: | |
| print(f"[{idx}/{total}] Which is better?") | |
| print(f" 1. {a}") | |
| print(f" 2. {b}") | |
| while True: | |
| choice = input("Enter 1 or 2: ").strip() | |
| if choice == "1": | |
| winner, loser = a, b | |
| break | |
| elif choice == "2": | |
| winner, loser = b, a | |
| break | |
| else: | |
| print(" Please enter 1 or 2.") | |
| losses[loser] += 1 | |
| results.append((winner, loser)) | |
| ratings[winner], ratings[loser] = _elo_update(ratings[winner], ratings[loser]) | |
| print() | |
| # Sort by Elo descending | |
| ranked = sorted(ratings.items(), key=lambda x: x[1], reverse=True) | |
| print("=" * 40) | |
| print(" TOP 10 RESULTS") | |
| print("=" * 40) | |
| for rank, (item, score) in enumerate(ranked[:10], 1): | |
| print(f" {rank:>2}. {item} (Elo: {score:.1f})") | |
| print("=" * 40) | |
| # Save full ranking to results.csv | |
| with open(f"results-{os.path.dirname(SELECTION)}.csv", "w", newline="", encoding="utf-8") as f: | |
| writer = csv.writer(f) | |
| writer.writerow(["Rank", "Item", "Elo"]) | |
| for rank, (item, score) in enumerate(ranked, 1): | |
| writer.writerow([rank, item, f"{score:.1f}"]) | |
| print("Results saved to results.csv") | |
| return ranked | |
| if __name__ == "__main__": | |
| items = get_items() | |
| if items: | |
| top_10(items) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment