From 5bb035c73ac5d9f6cd3bcc828629bef494bc1f13 Mon Sep 17 00:00:00 2001 From: Harald Holtmann Date: Sun, 7 Sep 2025 00:50:05 +0200 Subject: [PATCH] mark_solver --- harald/api.py | 22 +++++--- harald/explore.py | 128 +++++++++++++++++++++++++++++++++++++++++----- harald/graph.py | 4 +- 3 files changed, 133 insertions(+), 21 deletions(-) diff --git a/harald/api.py b/harald/api.py index 2bc962d..b879417 100644 --- a/harald/api.py +++ b/harald/api.py @@ -30,13 +30,18 @@ def select(problem: str): return response.json()["problemName"] -explore_cache = {"seed": random.getrandbits(30)} -try: - with open("explore_cache.json") as h: - explore_cache = json.loads(h.read()) -except OSError: - pass -random.seed(explore_cache["seed"]) +explore_cache = {} + + +def init_explore_cache(): + global explore_cache + explore_cache = {"seed": random.getrandbits(30)} + try: + with open("explore_cache.json") as h: + explore_cache = json.loads(h.read()) + except OSError: + pass + random.seed(explore_cache["seed"]) def write_explore_cache(): @@ -51,6 +56,9 @@ def clean_explore_cache(): pass +init_explore_cache() + + def explore(plans: List[str]): cache_key = ",".join(plans) if cache_key in explore_cache: diff --git a/harald/explore.py b/harald/explore.py index 8e12fe6..29e6ac0 100755 --- a/harald/explore.py +++ b/harald/explore.py @@ -87,11 +87,14 @@ class Explore: return path - def explore(self, path=Path(), probes=None): + def explore(self, path=Path(), probes=None, mark=Path()): probes = probes or self.probes path = self._path(path) - paths = [path + probe for probe in probes] + paths = [mark + path + probe for probe in probes] + + num_marks = mark.path.count("[") + prefix_len = len(mark) - 2 * num_marks + len(path) print("explore", paths) response = api.explore([p.path for p in paths]) @@ -99,7 +102,7 @@ class Explore: self.score = response["queryCount"] print("id", path, results) - return [res[len(path) :] for res in results] + return [res[prefix_len:] for res in results] def _add_room(self, path, results): label = results[0][0] @@ -161,9 +164,9 @@ class Explore: for r, rid in self.rooms.items(): print(f" {r:<10}: {rid} {self.neighbors[r]}") print() - for rid, paths in self.room_ids.items(): - print(f" {rid}: {paths}") - print() + # for rid, paths in self.room_ids.items(): + # print(f" {rid}: {paths}") + # print() # for p, pu in self.unification_id.items(): # print(f" {p}: {pu}") @@ -262,7 +265,7 @@ class Explore: len(p) == 1 for p in self.room_ids.values() ) - def guess(self): + def guess(self, orig=None): aedi = graph.Aedificium(self.problem) ids = {} @@ -302,23 +305,45 @@ class Explore: ) aedi.add_edge(src[0], src[1], trg[0], trg[1]) + if orig: + rooms = orig + else: + rooms = {} + for path, rid in self.rooms.items(): + rooms[path] = rid[0] + layout = { - "rooms": [int(self.rooms[p][0]) for p in ids.keys()], + "rooms": [int(rooms[p]) for p in ids.keys()], "startingRoom": ids[Path()], "connections": connections, } - # print(layout) aedi.render() return api.guess(layout) + def returnfrom(self, path): + queue = [(path, Path())] + while queue: + p, ret = queue.pop(0) + if p == Path(): + return ret + + for d, (q, _) in enumerate(self.neighbors[p]): + queue.append((q, Path([d]))) + + assert False, "return path not found" + + def walk(self, path): + here = Path() + 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]]) - print(ex.probes) api.select(ex.problem) res = ex.explore(Path()) - ex.update(Path(), res) ex.dump() @@ -342,6 +367,77 @@ def room_solve(problem, nrooms, plen): print("score", ex.score) +def get_mark(rid): + return Path("[" + str(int(rid[0]) ^ 3) + "]") + + +def mark_solve(problem, nrooms, plen): + ex0 = Explore(problem, [d + d + d + d + d + d for d in DOORS[:plen]]) + api.select(ex0.problem) + res = ex0.explore(Path()) + + ex0.update(Path(), res) + ex0.dump() + + while True: + door, unexplored = next(ex0.unexplored(), (None, None)) + if unexplored is None: + break + + print("explore", door, unexplored) + path = unexplored + Path([door]) + res = ex0.explore(path) + ex0.update(path, res) + ex0.dump() + + ex0.unify_all() + ex0.dump() + + print("found all rooms") + mark = Path() + for p, rid in ex0.rooms.items(): + q = ex0.returnfrom(p) + mark = mark + p + get_mark(rid) + q + + print("marked", mark) + + ex1 = Explore(problem, [d + d + d + d + d + d for d in DOORS[:plen]]) + res = ex1.explore(Path(), mark=mark) + ex1.update(Path(), res) + ex1.dump() + + while True: + door, unexplored = next(ex1.unexplored(), (None, None)) + if unexplored is None: + break + + print("explore", door, unexplored) + path = unexplored + Path([door]) + res = ex1.explore(path, mark=mark) + ex1.update(path, res) + ex1.dump() + + ex1.unify_all() + ex1.dump() + + print("explored", ex1.is_explored()) + if ex1.is_explored(): + # get old markings + orig = {} + for path in ex1.rooms.keys(): + p = ex0.walk(path) + rid = ex0.rooms[p] + orig[path] = rid[0] + print(path, p, rid) + + ex0.dump() + ex1.dump() + print(orig) + print("guess", ex1.guess(orig=orig)) + print("score", ex0.score + ex1.score) + assert False + + def path_solve(problem, nrooms, plen): maxlen = 18 * nrooms probe = Path([random.randrange(6) for _ in range(plen)]) @@ -402,13 +498,19 @@ if __name__ == "__main__": with open(os.path.join("..", "problems.json")) as h: problems = json.loads(h.read()) - problems = {p["problem"]: {"size": p["size"]} for p in problems} + problems = { + p["problem"]: {"size": p["size"], "idx": i} for i, p in enumerate(problems) + } if problem not in problems: raise ExploreError(f"unknown problem {problem}") try: - room_solve(problem, problems[problem]["size"], int(sys.argv[2])) + if problems[problem]["idx"] < 6: + room_solve(problem, problems[problem]["size"], int(sys.argv[2])) + else: + mark_solve(problem, problems[problem]["size"], int(sys.argv[2])) + api.clean_explore_cache() # except ExploreError as exc: # api.clean_explore_cache() diff --git a/harald/graph.py b/harald/graph.py index 4c3658c..cd3e27e 100644 --- a/harald/graph.py +++ b/harald/graph.py @@ -12,7 +12,9 @@ class Aedificium: 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):