From 28424bf0fdb6fca6e10b885780f0d0682d9ebf9d Mon Sep 17 00:00:00 2001 From: Nyeogmi Date: Sat, 9 Mar 2024 22:30:03 -0800 Subject: [PATCH] Commit my code --- .gitignore | 2 + README.md | 1 + main.py | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 main.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0883e77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +input.txt +venv \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3380b61 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Concurrent, user-directed mergesort. See https://git.chromaticdragon.app/kistaro/manual-sort . \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..6fb1b4e --- /dev/null +++ b/main.py @@ -0,0 +1,112 @@ +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()