Commit my code

This commit is contained in:
Pyrex 2024-03-09 22:30:03 -08:00
commit 28424bf0fd
3 changed files with 115 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
input.txt
venv

1
README.md Normal file
View File

@ -0,0 +1 @@
Concurrent, user-directed mergesort. See https://git.chromaticdragon.app/kistaro/manual-sort .

112
main.py Normal file
View File

@ -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()