Rewritten without async
This commit is contained in:
parent
71bba236c0
commit
3f505bba71
180
main.py
180
main.py
@ -1,36 +1,107 @@
|
|||||||
import asyncio
|
from functools import partial
|
||||||
import contextlib
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
class Cell(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.is_set = False
|
||||||
|
self.value = None
|
||||||
|
|
||||||
|
def set(self, x):
|
||||||
|
self.is_set = True
|
||||||
|
self.value = x
|
||||||
|
|
||||||
|
|
||||||
|
class Merge(object):
|
||||||
|
def __init__(self, xs, ys, on_complete):
|
||||||
|
self.xs = xs[:]
|
||||||
|
self.ys = ys[:]
|
||||||
|
self.output = []
|
||||||
|
self.on_complete = on_complete
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
self.settle()
|
||||||
|
|
||||||
|
def touch(self):
|
||||||
|
# print(f"Touching: {self}")
|
||||||
|
if ask(self.xs[0], self.ys[0]):
|
||||||
|
self.output.append(self.xs.pop(0))
|
||||||
|
else:
|
||||||
|
self.output.append(self.ys.pop(0))
|
||||||
|
|
||||||
|
self.settle()
|
||||||
|
|
||||||
|
def settle(self):
|
||||||
|
if len(self.xs) == 0:
|
||||||
|
self.output += self.ys
|
||||||
|
self.ys = []
|
||||||
|
self.complete()
|
||||||
|
return
|
||||||
|
|
||||||
|
if len(self.ys) == 0:
|
||||||
|
self.output += self.xs
|
||||||
|
self.xs = []
|
||||||
|
self.complete()
|
||||||
|
return
|
||||||
|
|
||||||
|
def complete(self):
|
||||||
|
self.on_complete(self.output)
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"Merge({self.xs}, {self.ys}, {self.output})"
|
||||||
|
|
||||||
|
|
||||||
|
def _sort(xs, merges, on_complete):
|
||||||
|
if len(xs) < 2:
|
||||||
|
on_complete(xs[:])
|
||||||
|
return
|
||||||
|
|
||||||
|
half = len(xs) // 2
|
||||||
|
fst = xs[:half]
|
||||||
|
snd = xs[half:]
|
||||||
|
sorted_fst = Cell()
|
||||||
|
sorted_snd = Cell()
|
||||||
|
|
||||||
|
def cb(setter, value):
|
||||||
|
setter(value)
|
||||||
|
if sorted_fst.is_set and sorted_snd.is_set:
|
||||||
|
new_merge = Merge(sorted_fst.value, sorted_snd.value, on_complete)
|
||||||
|
merges.append(new_merge)
|
||||||
|
|
||||||
|
_sort(fst, merges, partial(cb, sorted_fst.set))
|
||||||
|
_sort(snd, merges, partial(cb, sorted_snd.set))
|
||||||
|
|
||||||
|
|
||||||
|
def merge_sort(xs):
|
||||||
|
merges = []
|
||||||
|
result = Cell()
|
||||||
|
_sort(xs, merges, result.set)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# replace in place
|
||||||
|
for i in reversed(range(len(merges))):
|
||||||
|
if not merges[i].running:
|
||||||
|
merges.pop(i)
|
||||||
|
|
||||||
|
if len(merges) == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
# print(f"Number of ongoing merges: {merges}")
|
||||||
|
# print(f"Number of ongoing merges: {len(merges)}")
|
||||||
|
random.shuffle(merges)
|
||||||
|
for m in merges[:]:
|
||||||
|
m.touch()
|
||||||
|
|
||||||
|
assert result.is_set
|
||||||
|
return result.value
|
||||||
|
|
||||||
|
|
||||||
TRUTHY = "y yes 1 t true aye left up top first p".split()
|
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()
|
FALSEY = "n no 0 2 f false nay right down bottom second nil".split()
|
||||||
|
|
||||||
|
|
||||||
def sort(options):
|
def ask(x, y):
|
||||||
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]):
|
if random.choice([False, True]):
|
||||||
yes_result = True
|
yes_result = True
|
||||||
a, b = x, y
|
a, b = x, y
|
||||||
@ -41,72 +112,23 @@ def sort(options):
|
|||||||
while True:
|
while True:
|
||||||
choice = input(f"Is {a} better than {b}? ")
|
choice = input(f"Is {a} better than {b}? ")
|
||||||
if choice in TRUTHY:
|
if choice in TRUTHY:
|
||||||
future.set_result(yes_result)
|
return yes_result
|
||||||
return
|
|
||||||
|
|
||||||
if choice in FALSEY:
|
if choice in FALSEY:
|
||||||
future.set_result(not yes_result)
|
return not yes_result
|
||||||
return
|
|
||||||
|
|
||||||
print(f"Huh? I didn't understand {choice}. Answer \"y\" or \"n\".")
|
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():
|
def main():
|
||||||
with open("input.txt", "rt") as f_in:
|
with open("input.txt", "rt") as f_in:
|
||||||
lines_in = [i.strip() for i in f_in.read().split("\n") if i.strip()]
|
lines_in = [i.strip() for i in f_in.read().split("\n") if i.strip()]
|
||||||
|
|
||||||
random.shuffle(lines_in)
|
random.shuffle(lines_in)
|
||||||
results = sort(lines_in)
|
results = merge_sort(lines_in)
|
||||||
|
|
||||||
with open("output.txt", "wt") as f_out:
|
with open("output.txt", "wt") as f_out:
|
||||||
f_out.writelines(results)
|
f_out.write("\n".join(results))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Loading…
Reference in New Issue
Block a user