From 839b7197e79809d11870c5e5a50403733c944d96 Mon Sep 17 00:00:00 2001 From: Harald Holtmann Date: Sun, 7 Sep 2025 15:07:38 +0200 Subject: [PATCH] changes for veh --- harald/api.py | 1 + harald/explore.py | 89 +++++++++++++++++++++++++---------------------- harald/graph.py | 6 ++-- 3 files changed, 50 insertions(+), 46 deletions(-) diff --git a/harald/api.py b/harald/api.py index 4fd7044..5316603 100644 --- a/harald/api.py +++ b/harald/api.py @@ -43,6 +43,7 @@ def init_explore_cache(): def write_explore_cache(): + return with open("explore_cache.json", "w") as h: h.write(json.dumps(explore_cache)) diff --git a/harald/explore.py b/harald/explore.py index 0be60e8..68c44b6 100755 --- a/harald/explore.py +++ b/harald/explore.py @@ -167,7 +167,6 @@ class Explore: # print() # for p, pu in self.unification_id.items(): # print(f" {p}: {pu}") - # print() def unify(self, path1, path2): @@ -195,10 +194,7 @@ class Explore: 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") - if rmid: - merged_neighbors.append((self._path(pm), rmid)) - else: - merged_neighbors.append((self._path(p), rid)) + merged_neighbors.append((self._path(p), rid or rmid)) # fix rooms del self.rooms[pmerge] @@ -253,7 +249,7 @@ class Explore: def is_explored(self): return next(self.unexplored(), None) is None and all(len(p) == 1 for p in self.room_ids.values()) - def guess(self, orig=None, start=Path()): + def layout(self, orig=None, start=Path()): aedi = graph.Aedificium(self.problem) ids = {} @@ -263,6 +259,7 @@ class Explore: connected = set() connections = [] + connect_errors = [] for path, ns in self.neighbors.items(): src_path = path for src_door, (trg_path, _) in enumerate(ns): @@ -272,7 +269,10 @@ class Explore: None, ) if trg_door is None: - raise ExploreError(f"backlink not found: {(src, trg_path, self.neighbors[trg_path])}") + # raise Exception(f"backlink not found: {(src, trg_path, self.neighbors[trg_path])}") + print(f"backlink not found: {(src, trg_path, self.neighbors[trg_path])}") + connect_errors.append((src[0], src[1], trg_path)) + trg_door = 0 trg = (trg_path, trg_door) if (src, trg) in connected or (trg, src) in connected: @@ -286,6 +286,21 @@ class Explore: ) aedi.add_edge(src[0], src[1], trg[0], trg[1]) + if connect_errors: + # try to fix connection issues + updated = False + src = {src_path: (trg_path, src_door) for src_path, src_door, trg_path in connect_errors} + trg = {trg_path: (src_path, src_door) for src_path, src_door, trg_path in connect_errors} + + for trg_path, (src_path, src_door) in trg.items(): + if trg_path in src: + self.neighbors[trg_path][src_door] = (src_path, "**FIXED**") + updated = True + + assert updated, "could not fix connections" + self.dump() + return self.layout(orig=orig, start=start) + if orig: rooms = orig else: @@ -300,7 +315,7 @@ class Explore: } aedi.render() - return api.guess(layout) + return layout def returnfrom(self, path): queue = [(path, Path())] @@ -314,40 +329,13 @@ class Explore: assert False, "return path not found" - def walk(self, path): - here = Path() + def walk(self, path, start=Path()): + here = start for d in map(int, path.path): here = self.neighbors[here][d][0] return here -def room_solve(problem, nrooms, plen): - ex = Explore(problem, [d + d + d + d + d + d for d in DOORS[:plen]]) - api.select(ex.problem) - res = ex.explore(Path()) - ex.update(Path(), res) - ex.dump() - - while True: - door, unexplored = next(ex.unexplored(), (None, None)) - if unexplored is None: - break - - print("explore", door, unexplored) - path = unexplored + Path([door]) - res = ex.explore(path) - ex.update(path, res) - ex.dump() - - ex.unify_all() - ex.dump() - - print("explored", ex.is_explored()) - if ex.is_explored(): - print("guess", ex.guess()) - print("score", ex.score) - - def get_mark(rid, mask): return Path("[" + str(int(rid[0]) ^ mask) + "]") @@ -398,6 +386,7 @@ def mark_solve(problem, nrooms): assert ex.is_explored(), "not fully explored" if nrooms % len(ex.rooms) != 0: raise ExploreError(f"not all rooms could be identifed {len(ex.rooms)}/{nrooms}") + if len(ex.rooms) == nrooms: print("found all rooms") break @@ -415,6 +404,7 @@ def mark_solve(problem, nrooms): orig[path] = rid[0] print(path, p, rid) print(orig) + # try to identify original start start = apply_mask(exs[0].rooms[Path()], mask) starts = [] @@ -426,9 +416,21 @@ def mark_solve(problem, nrooms): starts.append(p) print("start", start, starts, all_masked) assert len(starts) > 0 - - print("guess", ex.guess(orig=orig, start=starts[0])) + # try to reach . from there + start = None + for s in starts: + t = ex.walk(loop, start=s) + print(f"walk {s} => {t}") + if t == Path(): + start = s + print("use as start", start) + assert start + + layout = ex.layout(orig=orig, start=starts[0]) + guess_ok = api.guess(layout) + print("guess", guess_ok) print("score", sum(e.score for e in exs)) + return guess_ok def path_solve(problem, nrooms, plen): @@ -496,12 +498,15 @@ if __name__ == "__main__": if problem not in problems: raise ExploreError(f"unknown problem {problem}") + ok = False try: - mark_solve(problem, problems[problem]["size"]) + ok = mark_solve(problem, problems[problem]["size"]) api.clean_explore_cache() except ExploreError as exc: api.clean_explore_cache() - raise exc + print(exc) except Exception as exc: api.write_explore_cache() - raise exc + print(exc) + + sys.exit(0 if ok else 1) diff --git a/harald/graph.py b/harald/graph.py index cd3e27e..1ed117e 100644 --- a/harald/graph.py +++ b/harald/graph.py @@ -5,16 +5,14 @@ class Aedificium: PORTS = ["n", "ne", "se", "s", "sw", "nw"] def __init__(self, problem): - self.graph = pydot.Dot(problem, graph_type="graph") + self.graph = pydot.Dot(problem, graph_type="graph", rankdir="LR") def add_node(self, name): self.graph.add_node(pydot.Node(name, label=name, shape="hexagon")) def add_edge(self, scr, src_d, trg, trg_d): self.graph.add_edge( - pydot.Edge( - scr, trg - ) # , headport=self.PORTS[src_d], tailport=self.PORTS[trg_d]) + pydot.Edge(scr, trg) # , headport=self.PORTS[src_d], tailport=self.PORTS[trg_d]) ) def render(self):