|
|
|
|
@ -1,5 +1,10 @@
|
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
|
|
import api
|
|
|
|
|
import functools
|
|
|
|
|
import json
|
|
|
|
|
import os.path
|
|
|
|
|
import sys
|
|
|
|
|
from collections import defaultdict
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -42,6 +47,7 @@ class Path:
|
|
|
|
|
else:
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Explore:
|
|
|
|
|
def __init__(self, problem):
|
|
|
|
|
self.problem = problem
|
|
|
|
|
@ -131,78 +137,53 @@ class Explore:
|
|
|
|
|
raise ExploreError(f"room '{path2}' not explored")
|
|
|
|
|
|
|
|
|
|
if self.rooms[path1] != self.rooms[path2]:
|
|
|
|
|
raise ExploreError(
|
|
|
|
|
f"ids of '{path1}'({self.rooms[path1]}) and '{path2}'({self.rooms[path2]}) do not match"
|
|
|
|
|
)
|
|
|
|
|
raise ExploreError(f"ids of '{path1}'({self.rooms[path1]}) and '{path2}'({self.rooms[path2]}) do not match")
|
|
|
|
|
|
|
|
|
|
path = min(path1, path2)
|
|
|
|
|
pmerge = max(path1, path2)
|
|
|
|
|
room_id = self.rooms[path]
|
|
|
|
|
|
|
|
|
|
rooms = self.rooms.copy()
|
|
|
|
|
room_ids = self.room_ids.copy()
|
|
|
|
|
neighbors = self.neighbors.copy()
|
|
|
|
|
unifications = self.unifications.copy()
|
|
|
|
|
unification_id = self.unification_id.copy()
|
|
|
|
|
|
|
|
|
|
merged_neighbors = []
|
|
|
|
|
for n, ((p, rid), (pm, rmid)) in enumerate(
|
|
|
|
|
zip(neighbors[path], neighbors[pmerge])
|
|
|
|
|
):
|
|
|
|
|
for n, ((p, rid), (pm, rmid)) in enumerate(zip(self.neighbors[path], self.neighbors[pmerge])):
|
|
|
|
|
if rid and rmid and rid != rmid:
|
|
|
|
|
raise ExploreError(
|
|
|
|
|
f"neighbor {n} of '{path}'({rid}) and '{pmerge}'({rmid}) do not match"
|
|
|
|
|
)
|
|
|
|
|
raise ExploreError(f"neighbor {n} of '{path}'({rid}) and '{pmerge}'({rmid}) do not match")
|
|
|
|
|
merged_neighbors.append((p.shorten(path, pmerge), rid or rmid))
|
|
|
|
|
|
|
|
|
|
# unify paths
|
|
|
|
|
unification_id[pmerge] = path
|
|
|
|
|
for p in unifications[pmerge]:
|
|
|
|
|
unification_id[p] = path
|
|
|
|
|
self.unification_id[pmerge] = path
|
|
|
|
|
for p in self.unifications[pmerge]:
|
|
|
|
|
self.unification_id[p] = path
|
|
|
|
|
|
|
|
|
|
unifications[path] = unifications[path1] | unifications[path2] | {pmerge}
|
|
|
|
|
if pmerge in unifications:
|
|
|
|
|
del unifications[pmerge]
|
|
|
|
|
self.unifications[path] = self.unifications[path1] | self.unifications[path2] | {pmerge}
|
|
|
|
|
if pmerge in self.unifications:
|
|
|
|
|
del self.unifications[pmerge]
|
|
|
|
|
|
|
|
|
|
# fix rooms
|
|
|
|
|
del rooms[pmerge]
|
|
|
|
|
del self.rooms[pmerge]
|
|
|
|
|
|
|
|
|
|
room_ids[room_id] = {p for p in room_ids[room_id] if p != pmerge}
|
|
|
|
|
self.room_ids[room_id] = {p for p in self.room_ids[room_id] if p != pmerge}
|
|
|
|
|
|
|
|
|
|
neighbors[path] = merged_neighbors
|
|
|
|
|
del neighbors[pmerge]
|
|
|
|
|
for p, ns in neighbors.items():
|
|
|
|
|
self.neighbors[path] = merged_neighbors
|
|
|
|
|
del self.neighbors[pmerge]
|
|
|
|
|
for p, ns in self.neighbors.items():
|
|
|
|
|
new = []
|
|
|
|
|
for np, rid in ns:
|
|
|
|
|
np = np.shorten(path, pmerge)
|
|
|
|
|
new.append((np, rid))
|
|
|
|
|
if rid:
|
|
|
|
|
assert np in rooms, f"path {np} of {(p,ns)} not in rooms"
|
|
|
|
|
neighbors[p] = new
|
|
|
|
|
|
|
|
|
|
unified = self.__class__(self.problem)
|
|
|
|
|
unified.rooms = rooms
|
|
|
|
|
unified.room_ids = room_ids
|
|
|
|
|
unified.neighbors = neighbors
|
|
|
|
|
unified.unifications = unifications
|
|
|
|
|
unified.unification_id = unification_id
|
|
|
|
|
|
|
|
|
|
return unified
|
|
|
|
|
assert np in self.rooms, f"path {np} of {(p, ns)} not in rooms"
|
|
|
|
|
self.neighbors[p] = new
|
|
|
|
|
|
|
|
|
|
def unify_all(self):
|
|
|
|
|
unified = self
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
for rid, paths in unified.room_ids.items():
|
|
|
|
|
for rid, paths in self.room_ids.items():
|
|
|
|
|
if len(paths) > 1:
|
|
|
|
|
paths = list(paths)
|
|
|
|
|
print("unify", paths[0], paths[1])
|
|
|
|
|
unified = unified.unify(paths[0], paths[1])
|
|
|
|
|
self.unify(paths[0], paths[1])
|
|
|
|
|
break
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
return unified
|
|
|
|
|
|
|
|
|
|
def unexplored(self):
|
|
|
|
|
for path, ns in self.neighbors.items():
|
|
|
|
|
for p, rid in ns:
|
|
|
|
|
@ -210,9 +191,7 @@ class Explore:
|
|
|
|
|
yield p
|
|
|
|
|
|
|
|
|
|
def is_explored(self):
|
|
|
|
|
return next(self.unexplored(), None) is None and all(
|
|
|
|
|
len(p) == 1 for p in self.room_ids.values()
|
|
|
|
|
)
|
|
|
|
|
return next(self.unexplored(), None) is None and all(len(p) == 1 for p in self.room_ids.values())
|
|
|
|
|
|
|
|
|
|
def guess(self):
|
|
|
|
|
ids = {}
|
|
|
|
|
@ -225,11 +204,7 @@ class Explore:
|
|
|
|
|
src_id = self.rooms[path]
|
|
|
|
|
for src_door, (trg_path, trg_id) in enumerate(ns):
|
|
|
|
|
src = (src_id, src_door)
|
|
|
|
|
trg_door = next(
|
|
|
|
|
j
|
|
|
|
|
for j, (p, rid) in enumerate(self.neighbors[trg_path])
|
|
|
|
|
if rid == src_id
|
|
|
|
|
)
|
|
|
|
|
trg_door = next(j for j, (p, rid) in enumerate(self.neighbors[trg_path]) if rid == src_id)
|
|
|
|
|
trg = (trg_id, trg_door)
|
|
|
|
|
|
|
|
|
|
if (src, trg) in connected or (trg, src) in connected:
|
|
|
|
|
@ -268,7 +243,7 @@ def solve(problem):
|
|
|
|
|
ex.dump()
|
|
|
|
|
|
|
|
|
|
print("unify")
|
|
|
|
|
ex = ex.unify_all()
|
|
|
|
|
ex.unify_all()
|
|
|
|
|
ex.dump()
|
|
|
|
|
|
|
|
|
|
print("explored", ex.is_explored())
|
|
|
|
|
@ -279,5 +254,14 @@ def solve(problem):
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
# with open("test.rooms") as h:
|
|
|
|
|
# obj = ast.literal_eval(h.read())
|
|
|
|
|
problem = sys.argv[1]
|
|
|
|
|
|
|
|
|
|
with open(os.path.join("..", "problems.json")) as h:
|
|
|
|
|
problems = json.loads(h.read())
|
|
|
|
|
|
|
|
|
|
problems = {p["problem"]: {"size": p["size"]} for p in problems}
|
|
|
|
|
|
|
|
|
|
if problem not in problems:
|
|
|
|
|
raise ExploreError(f"unknown problem {problem}")
|
|
|
|
|
|
|
|
|
|
solve("primus")
|
|
|
|
|
solve(problem)
|
|
|
|
|
|