import asyncio import contextlib import random TRUTHY = "y yes 1 t true aye left up top first p".split() FALSEY = "n no 0 2 f false nay right down bottom second nil".split() def sort(options): loop = asyncio.new_event_loop() postponed_questions = [] # counter for how many threads can still resume # if it's 0, then we need to ask some questions or else we're deadlocked n_active = 0 @contextlib.asynccontextmanager async def semaphore(amt): nonlocal n_active n_active += amt yield n_active -= amt def deadlocked(): return n_active == 0 async def ask(x, y): async with semaphore(-1): future = loop.create_future() def ask_question(): if random.choice([False, True]): yes_result = True a, b = x, y else: yes_result = False a, b = y, x while True: choice = input(f"Is {a} better than {b}? ") if choice in TRUTHY: future.set_result(yes_result) return if choice in FALSEY: future.set_result(not yes_result) return print(f"Huh? I didn't understand {choice}. Answer \"y\" or \"n\".") postponed_questions.append(ask_question) if deadlocked(): await ask_questions() return await future async def merge(xs, ys): async with semaphore(1): xs = xs[:] ys = ys[:] out = [] while len(xs) > 0 and len(ys) > 0: if await ask(xs[0], ys[0]): out.append(xs.pop(0)) else: out.append(ys.pop(0)) out.extend(xs) out.extend(ys) return out async def merge_sort(xs): if len(xs) < 2: return xs[:] half = len(xs) // 2 fst_half, snd_half = await asyncio.gather( merge_sort(xs[:half]), merge_sort(xs[half:]) ) return await merge(fst_half, snd_half) async def ask_questions(): ppq = postponed_questions[:] postponed_questions.clear() random.shuffle(ppq) for q in ppq: q() result_future = merge_sort(options) result = loop.run_until_complete(result_future) return result def main(): with open("input.txt", "rt") as f_in: lines_in = [i.strip() for i in f_in.split("\n") if i.strip()] results = sort(lines_in) with open("output.txt", "wt") as f_out: f_out.writelines(results) if __name__ == '__main__': main()