diff --git a/harald/explore.py b/harald/explore.py old mode 100644 new mode 100755 index 7b7bb3a..3d9e112 --- a/harald/explore.py +++ b/harald/explore.py @@ -1,5 +1,10 @@ +#!/usr/bin/env python3 + import api import functools +import json +import os.path +import sys from collections import defaultdict @@ -13,7 +18,7 @@ class Path: self.path = path def __repr__(self): - return "." +self.path if self.path else "." + return "." + self.path if self.path else "." def __bool__(self): return bool(self.path) @@ -38,10 +43,11 @@ class Path: def shorten(self, path, pmerge): if self.path.startswith(pmerge.path): - return Path(path.path + self.path[len(pmerge.path):]) + return Path(path.path + self.path[len(pmerge.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) diff --git a/Prob.json b/problems.json similarity index 100% rename from Prob.json rename to problems.json