From 6c5536f01cec2a25318aaf699fb0ba3a29b4a0b2 Mon Sep 17 00:00:00 2001 From: Harald Holtmann Date: Sat, 6 Sep 2025 01:31:10 +0200 Subject: [PATCH] primus ok --- harald/api.py | 1 + harald/explore.py | 88 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 63 insertions(+), 26 deletions(-) diff --git a/harald/api.py b/harald/api.py index 48230d6..b039b3c 100644 --- a/harald/api.py +++ b/harald/api.py @@ -1,4 +1,5 @@ import json +import logging import os.path from argparse import Namespace from typing import List diff --git a/harald/explore.py b/harald/explore.py index 8ea667f..7b7bb3a 100644 --- a/harald/explore.py +++ b/harald/explore.py @@ -1,5 +1,5 @@ import api -import ast +import functools from collections import defaultdict @@ -7,6 +7,41 @@ class ExploreError(Exception): pass +@functools.total_ordering +class Path: + def __init__(self, path=""): + self.path = path + + def __repr__(self): + return "." +self.path if self.path else "." + + def __bool__(self): + return bool(self.path) + + def __eq__(self, other): + return self.path == other.path + + def __lt__(self, other): + return (len(self.path), self.path) < (len(other.path), other.path) + + def __hash__(self): + return self.path.__hash__() + + def __format__(self, spec): + return str(self).__format__(spec) + + def extend(self, door): + return Path(self.path + str(door)) + + def last(self): + return Path(self.path[:-1]), int(self.path[-1]) + + def shorten(self, path, pmerge): + if self.path.startswith(pmerge.path): + return Path(path.path + self.path[len(pmerge.path):]) + else: + return self + class Explore: def __init__(self, problem): self.problem = problem @@ -41,15 +76,16 @@ class Explore: new.unifications.update(obj["unifications"]) return new - def explore(self, path): + def explore(self, path=Path()): path = self._path(path) - if path in self.room_ids: - return self.r + if path in self.rooms: + return self.rooms[path] - paths = [path + str(i) for i in range(6)] + paths = [path.extend(i) for i in range(6)] self.neighbors[path] = [(p, None) for p in paths] - results = api.explore(paths)["results"] + print("explore", paths) + results = api.explore([p.path for p in paths])["results"] print("id", path, results) label = results[0][-2] @@ -61,8 +97,9 @@ class Explore: # update pen-ultimate room if path: - p, _ = self.neighbors[path[:-1]][int(path[-1])] - self.neighbors[path[:-1]][int(path[-1])] = (p, room_id) + pl, dl = path.last() + p, _ = self.neighbors[pl][dl] + self.neighbors[pl][dl] = (p, room_id) return room_id @@ -116,7 +153,7 @@ class Explore: raise ExploreError( f"neighbor {n} of '{path}'({rid}) and '{pmerge}'({rmid}) do not match" ) - merged_neighbors.append((p, rid or rmid)) + merged_neighbors.append((p.shorten(path, pmerge), rid or rmid)) # unify paths unification_id[pmerge] = path @@ -134,14 +171,13 @@ class Explore: neighbors[path] = merged_neighbors del neighbors[pmerge] - for p, ns in neighbors.items(): new = [] for np, rid in ns: - if np.startswith(pmerge): - new.append((path + np[len(pmerge) :], rid)) - else: - new.append((np, rid)) + 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) @@ -160,6 +196,7 @@ class Explore: for rid, paths in unified.room_ids.items(): if len(paths) > 1: paths = list(paths) + print("unify", paths[0], paths[1]) unified = unified.unify(paths[0], paths[1]) break break @@ -187,37 +224,38 @@ class Explore: for path, ns in self.neighbors.items(): src_id = self.rooms[path] for src_door, (trg_path, trg_id) in enumerate(ns): - src = (ids[src_id], src_door) + src = (src_id, src_door) trg_door = next( j for j, (p, rid) in enumerate(self.neighbors[trg_path]) if rid == src_id ) - trg = (ids[trg_id], trg_door) + trg = (trg_id, trg_door) if (src, trg) in connected or (trg, src) in connected: continue + print(src, trg) connected.add((src, trg)) connections.append( { - "from": {"room": src[0], "door": src[1]}, - "to": {"room": trg[0], "door": trg[1]}, + "from": {"room": ids[src[0]], "door": src[1]}, + "to": {"room": ids[trg[0]], "door": trg[1]}, } ) layout = { - "rooms": list(ids.values()), - "startingRoom": ids[self.rooms[""]], + "rooms": [int(rid[0]) for rid in ids.keys()], + "startingRoom": ids[self.rooms[Path()]], "connections": connections, } # print(layout) return api.guess(layout) -def test(): - ex = Explore("probatio") +def solve(problem): + ex = Explore(problem) api.select(ex.problem) - ex.explore("") + ex.explore() ex.dump() while True: @@ -234,8 +272,6 @@ def test(): ex.dump() print("explored", ex.is_explored()) - # with open("test.rooms","w") as h: - # h.write(str(ex.save())) if ex.is_explored(): print("guess", ex.guess()) @@ -244,4 +280,4 @@ if __name__ == "__main__": # with open("test.rooms") as h: # obj = ast.literal_eval(h.read()) - test() + solve("primus")