first explorer

main
Harald Holtmann 2025-09-05 19:25:51 +02:00
parent fe70efb1f3
commit 10a976fc70
4 changed files with 198 additions and 0 deletions

3
.gitignore vendored

@ -0,0 +1,3 @@
**/venv
**/*.pyc
**/__pycache__

@ -0,0 +1,37 @@
import os.path
from argparse import Namespace
from typing import List
import requests
config = {}
with open(os.path.join(os.path.dirname(__file__), "..", "config")) as h:
for line in h.readlines():
parts = line.strip().split("=")
config[parts[0].lower()] = parts[1].replace('"', "")
config = Namespace(**config)
class APIError(Exception):
pass
def select_problem(problem: str):
response = requests.post(config.contest_url + "/select", json={"problemName": problem, "id": config.id})
if not response.ok:
raise APIError(response.text)
data = response.json()
return data["problemName"]
def explore(plans: List[str]):
response = requests.post(
config.contest_url + "/explore",
json={"plans": plans, "id": config.id},
)
if not response.ok:
raise APIError(response.text)
return response.json()

@ -0,0 +1,157 @@
import api
from collections import defaultdict
class ExploreError(Exception):
pass
class Explore:
def __init__(self, problem):
self.problem = problem
self.rooms = {}
self.room_ids = defaultdict(lambda: set())
self.neighbors = {}
self.unification_id = {}
self.unifications = defaultdict(lambda: set())
def _path(self, path):
return self.unification_id.get(path, path)
def id_room(self, path):
path = self._path(path)
if path in self.room_ids:
return self.r
paths = [path + str(i) for i in range(6)]
self.neighbors[path] = [(p, None) for p in paths]
results = api.explore(paths)["results"]
# print("id", path, results)
label = results[0][-2]
neighbors = [r[-1] for r in results]
room_id = str(label) + "".join(str(n) for n in neighbors)
self.rooms[path] = room_id
self.room_ids[room_id].add(path)
# update pen-ultimate room
if path:
p, rid = self.neighbors[path[:-1]][int(path[-1])]
self.neighbors[path[:-1]][int(path[-1])] = (p, room_id)
return room_id
def dump(self):
print(self.problem + " rooms:")
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()
def unify(self, path1, path2):
"""
try to unify rooms at paths p1, p2
return unified rooms
"""
path1 = self._path(path1)
path2 = self._path(path2)
if path1 == path2:
return
if path1 not in self.rooms:
raise ExploreError(f"room '{path1}' not explored")
if path2 not in self.rooms:
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")
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])):
if rid and rmid and rid != rmid:
raise ExploreError(f"neighbor {n} of '{path}'({rid}) and '{pmerge}'({rmid}) do not match")
merged_neighbors.append((p, rid or rmid))
# unify paths
unification_id[pmerge] = path
for p in unifications[pmerge]:
unification_id[p] = path
unifications[path] = unifications[path1] | unifications[path2] | {pmerge}
if pmerge in unifications:
del unifications[pmerge]
# fix rooms
del rooms[pmerge]
room_ids[room_id] = {p for p in room_ids[room_id] if p != pmerge}
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))
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
def test():
ex = Explore("probatio")
ex.rooms = {
"": "0101112",
"0": "1002001",
"1": "0101112",
"2": "1002001",
"3": "1002001",
"4": "1002001",
"5": "2212022",
}
ex.room_ids = {"0101112": {"", "1"}, "1002001": {"0", "2", "3", "4"}, "2212022": {"5"}}
ex.neighbors = {
"": [
("0", "1002001"),
("1", "0101112"),
("2", "1002001"),
("3", "1002001"),
("4", "1002001"),
("5", "2212022"),
],
"0": [("00", None), ("01", None), ("02", None), ("03", None), ("04", None), ("05", None)],
"1": [("10", None), ("11", None), ("12", None), ("13", None), ("14", None), ("15", None)],
"2": [("20", None), ("21", None), ("22", None), ("23", None), ("24", None), ("25", None)],
"3": [("30", None), ("31", None), ("32", None), ("33", None), ("34", None), ("35", None)],
"4": [("40", None), ("41", None), ("42", None), ("43", None), ("44", None), ("45", None)],
"5": [("50", None), ("51", None), ("52", None), ("53", None), ("54", None), ("55", None)],
}
return ex