Created
February 26, 2024 00:54
-
-
Save OrangeChannel/e75c30dce00007ced79c4b6d996844d0 to your computer and use it in GitHub Desktop.
battlesort
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
import math | |
from random import random | |
from abc import ABC | |
__all__ = [ | |
'Thing', 'battle' | |
] | |
class Thing(ABC): | |
def __init__(self, name: str) -> None: | |
self.name = name | |
self.id = random() | |
self.ties = set() | |
def __repr__(self) -> str: | |
return self.name | |
__str__ = __repr__ | |
def __eq__(self, other) -> bool: | |
if not isinstance(other, Thing): | |
return NotImplemented | |
return self.id in other.ties or other.id in self.ties | |
def battlesort(m: list[Thing]) -> list[Thing]: | |
if len(m) <= 1: | |
return m | |
midpoint = math.ceil(len(m) / 2) | |
left, right = m[:midpoint], m[midpoint:] | |
left = battlesort(left) | |
right = battlesort(right) | |
return merge(left, right) | |
def merge(left: list[Thing], right: list[Thing]) -> list[Thing]: | |
result = [] | |
while left and right: | |
l_ = '<' # for str formatting | |
t_ = '=' | |
r_ = '>' | |
if left[0] == right[0]: # if already tied skip (don't think this is possible usually unless from resume data) | |
ans = '=' | |
else: | |
print(f"{str(left[0]):^25} or {str(right[0]):^25}\n" # user input prompt | |
f"{l_:^25}{t_:^4}{r_:^25}") | |
ans = input() | |
while ans not in '<=>': # prevent user input error | |
print(f"{l_:^25}{t_:^4}{r_:^25}") | |
ans = input() | |
match ans: | |
case '<': | |
result.append(temp := left.pop(0)) # add left to merge list | |
try: | |
while left[0] == temp: # while next element is tied, keep adding them (skip user input) | |
result.append(temp := left.pop(0)) | |
if len(left) == 0: # prevent index error from closing the while loop | |
break | |
except IndexError: # if right was already exhausted skip the while loop entirely | |
pass | |
case '>': | |
result.append(temp := right.pop(0)) | |
try: | |
while right[0] == temp: | |
result.append(temp := right.pop(0)) | |
if len(right) == 0: | |
break | |
except IndexError: | |
pass | |
case '=': | |
left[0].ties.add(right[0].id) | |
right[0].ties.add(left[0].id) | |
for item in left[1:]: # add right id to existing ties on the left | |
if item == left[0]: | |
item.ties.add(right[0].id) | |
for item in right[1:]: | |
if item == right[0]: | |
item.ties.add(left[0].id) | |
result.append(temp := left.pop(0)) | |
try: | |
while left[0] == temp: | |
result.append(temp := left.pop(0)) | |
if len(left) == 0: | |
break | |
except IndexError: | |
pass | |
result.append(temp := right.pop(0)) | |
try: | |
while right[0] == temp: | |
result.append(temp := right.pop(0)) | |
if len(right) == 0: | |
break | |
except IndexError: | |
pass | |
while left: # if right is exhasuted, keep adding from left | |
result.append(left.pop(0)) | |
while right: | |
result.append(right.pop(0)) | |
return result | |
def fancy_print(m: list[Thing]) -> None: | |
x = 1 | |
nxt = m.pop(0) | |
print(f'{x:<4}| {str(nxt):^25}') | |
while len(m) > 0: | |
while m[0] == nxt: | |
nxt = m.pop(0) | |
print(f' | {str(nxt):^25}') | |
if len(m) == 0: | |
break | |
if len(m) == 0: | |
break | |
print('-' * 31) | |
x += 1 | |
nxt = m.pop(0) | |
print(f'{x:<4}| {str(nxt):^25}') | |
print('-' * 31) | |
def battle(m: list[Thing]) -> None: | |
fancy_print(battlesort(m)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example script for movies:
Example sorting output with ties (~60 compares for 34 items).