use path probing

main
Harald Holtmann 2025-09-06 08:55:03 +02:00
parent 3f0e979dce
commit 4fdade25dc
1 changed files with 64 additions and 15 deletions

@ -5,6 +5,7 @@ import functools
import json
import os.path
import sys
import random
from collections import defaultdict
@ -15,6 +16,8 @@ class ExploreError(Exception):
@functools.total_ordering
class Path:
def __init__(self, path=""):
if isinstance(path, list):
path = "".join(str(p) for p in path)
self.path = path
def __repr__(self):
@ -35,8 +38,11 @@ class Path:
def __format__(self, spec):
return str(self).__format__(spec)
def extend(self, door):
return Path(self.path + str(door))
def __add__(self, other):
return Path(self.path + other.path)
def __len__(self):
return len(self.path)
def last(self):
return Path(self.path[:-1]), int(self.path[-1])
@ -48,9 +54,13 @@ class Path:
return self
DOORS = [Path(str(i)) for i in range(6)]
class Explore:
def __init__(self, problem):
def __init__(self, problem, probes):
self.problem = problem
self.probes = probes
self.rooms = {}
self.room_ids = defaultdict(lambda: set())
self.neighbors = {}
@ -58,6 +68,8 @@ class Explore:
self.unification_id = {}
self.unifications = defaultdict(lambda: set())
self.score = 0
def _path(self, path):
return self.unification_id.get(path, path)
@ -87,28 +99,36 @@ class Explore:
if path in self.rooms:
return self.rooms[path]
paths = [path.extend(i) for i in range(6)]
self.neighbors[path] = [(p, None) for p in paths]
paths = [path + probe for probe in self.probes]
print("explore", paths)
results = api.explore([p.path for p in paths])["results"]
response = api.explore([p.path for p in paths])
results = response["results"]
self.score = response["queryCount"]
print("id", path, results)
label = results[0][-2]
neighbors = [r[-1] for r in results]
self.update(path, [res[len(path) :] for res in results])
room_id = str(label) + "".join(str(n) for n in neighbors)
def update(self, path, results):
"""
path: path to update
probe: prob result from path.
"""
label = results[0][0]
probe_ids = [r for res in (rs[1:] for rs in results) for r in res]
print(path, results, probe_ids)
room_id = str(label) + "".join(str(p) for p in probe_ids)
self.rooms[path] = room_id
self.room_ids[room_id].add(path)
# update pen-ultimate room
self.neighbors[path] = [(path + d, None) for d in DOORS]
# update penultimate room
if path:
pl, dl = path.last()
p, _ = self.neighbors[pl][dl]
self.neighbors[pl][dl] = (p, room_id)
return room_id
def dump(self):
print(self.problem + " rooms:")
for r, rid in self.rooms.items():
@ -227,8 +247,36 @@ class Explore:
return api.guess(layout)
def solve(problem):
ex = Explore(problem)
def room_solve(problem):
ex = Explore(problem, DOORS)
api.select(ex.problem)
ex.explore()
ex.dump()
while True:
unexplored = next(ex.unexplored(), None)
if not unexplored:
break
print("explore", unexplored)
ex.explore(unexplored)
ex.dump()
print("unify")
ex.unify_all()
ex.dump()
print("explored", ex.is_explored())
if ex.is_explored():
print("guess", ex.guess())
print("score", ex.score)
def path_solve(problem, plen):
probe = [Path([random.randrange(6) for _ in range(plen)])]
print("probe path", probe)
ex = Explore(problem, probe)
api.select(ex.problem)
ex.explore()
ex.dump()
@ -249,6 +297,7 @@ def solve(problem):
print("explored", ex.is_explored())
if ex.is_explored():
print("guess", ex.guess())
print("score", ex.score)
if __name__ == "__main__":
@ -264,4 +313,4 @@ if __name__ == "__main__":
if problem not in problems:
raise ExploreError(f"unknown problem {problem}")
solve(problem)
path_solve(problem, int(sys.argv[2]))