Commit my code
This commit is contained in:
commit
28424bf0fd
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
input.txt
|
||||
venv
|
1
README.md
Normal file
1
README.md
Normal file
@ -0,0 +1 @@
|
||||
Concurrent, user-directed mergesort. See https://git.chromaticdragon.app/kistaro/manual-sort .
|
112
main.py
Normal file
112
main.py
Normal 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()
|
Loading…
Reference in New Issue
Block a user