icfp25/michael/libraryexplorer.py

210 lines
6.9 KiB
Python

from icfprequests import LibRequests
import json
import os.path
import sys
import random
class ExploreError(Exception):
pass
class LibraryMap:
def __init__(self, problemName:str, no_of_rooms:int, startRoom):
self.no_of_rooms = no_of_rooms
self.problemName = problemName
self.rooms = [ startRoom ]
self.startRoom = startRoom
self.candidateRooms = []
def addRoom(self,room):
if len(self.rooms)<self.no_of_rooms:
self.rooms.append(room)
class Room:
def __init__(self, room_id, isStart=False):
self.isStart = isStart
self.id = room_id
self.reachedby_id = None
self.doors = [None for _ in range(6)]
def completed(self):
for door in self.doors:
if door is None:
return False
if self.id is None:
return False
return True
def setRoomForDoor(self,door:int,room):
self.doors[door]=room
def createRoomForDoor(self,door, id):
self.doors[door]=Room(id)
class RoomPath:
def __init__(self, from_id, from_door, room_id, to_door, to_id ):
self.from_id = from_id
self.from_door = from_door
self.room_id = room_id
self.to_door = to_door
self.to_id = to_id
def getFromId(self):
return self.from_id + str(self.from_door) + self.room_id
def getToId(self):
return self.room_id + str(self.to_door)+ self.to_id
def getFullId(self):
return str(self.from_id) + str(self.from_door) + str(self.room_id) + str(self.to_door)+ str(self.to_id)
def __str__(self):
return self.getFullId()
def __repr__(self):
return self.getFullId()
class LibMapper:
def __init__(self, problemName:str, no_of_rooms:int, processmode:str):
self.no_of_rooms = no_of_rooms
self.problemName = problemName
self.processmode = processmode
self.requester = LibRequests()
self.libmap = None
def start(self):
response = self.requester.select(self.problemName)
if self.problemName != response:
print("Select Request failed")
else:
self.explore_map()
self.submit_guess()
def createRandomPlan(self,direction):
plan = str(direction)
# planzero = str(direction)+"[0]"
for x in range(6*self.no_of_rooms-1):
randdir = str(random.randint(0,5))
plan += randdir
return plan
def createAllDoorPlan(self):
return "024135" * self.no_of_rooms
def createZeroedPlan(self, plan):
zeroed_plan = ""
for direction in plan:
zeroed_plan += direction + "[0]"
return zeroed_plan
def createinvertedPlans(self, plan_base, result_base):
print(str(len(plan_base))+ " : "+str(len(result_base)))
if len(plan_base) == len(result_base):
inverted_plans = []
for i in range(len(plan_base)):
iplan = "[" + str(result_base[i][0]^3) + "]"
for j in range(len(plan_base[i])):
iplan += plan_base[i][j] + "[" + str(result_base[i][j+1]^3) + "]"
inverted_plans.append(iplan)
return inverted_plans
else:
print("Incompatible Input Array Dimensions")
def acquireExploreData(self):
# acquire data
print("Acquire")
startdirections = [random.randint(0, 5)]
plan_base = [self.createAllDoorPlan()]
# [self.createRandomPlan(direction) for direction in startdirections]
# plan_zero_base = [self.createZeroedPlan(plan) for plan in plan_base]
plans = plan_base # + plan_zero_base
print("Plans: " + str(plans))
result = self.requester.explore(plans)
print(result)
result_base = result["results"][0:1]
#startRoomId = result_base[0][0]
print(result_base)
# create inverted plan (every id will be xored with 3 and set as current Room Id)
plan_inverted_base = self.createinvertedPlans(plan_base, result_base)
print(plan_inverted_base)
result_inverted = self.requester.explore(plan_inverted_base)
print(result_inverted)
result_inverted_base = result_inverted["results"][0:1]
print(result_inverted_base)
return result_base[0], result_inverted_base[0], plan_inverted_base[0]
def explore_map(self):
result_base, result_inverted_base = [] , []
plan_inverted_base = ""
if self.processmode != "cache":
result_base, result_inverted_base, plan_inverted_base = self.acquireExploreData()
if self.processmode == "store":
self.storeResult(result_base, result_inverted_base, plan_inverted_base)
if self.processmode == "cache":
print("loading Data ...")
result_base, result_inverted_base , plan_inverted_base= self.loadResults()
print(result_base)
print(result_inverted_base)
print(plan_inverted_base)
# calculate map
print("Caluclate")
print("-- Preperations")
plan_base, inversions = self.splitInvertedPlan(plan_inverted_base)
print(plan_base)
print(inversions)
room_pathes_base = self.createBaseRoomPathes(result_base,plan_base)
print(room_pathes_base)
#room_pathes_inverted = self.createRoomPathes(result_inverted_base, plan_base)
#print(room_pathes_inverted)
def createBaseRoomPathes(self, result, plan):
spliced = str(result[0])
roompathes =[]
for i in range(0, len(plan)):
spliced += plan[i] + str(result[i+1])
print(spliced + " : " + str(len(spliced)))
for i in range(0,len(spliced)-4,2):
roompathes.append(RoomPath(spliced[i],spliced[i+1],spliced[i+2],spliced[i+3],spliced[i+4]))
return roompathes
def splitInvertedPlan(self, plan_inverted_base):
return plan_inverted_base[3::4], plan_inverted_base[1::4]
def submit_guess(self):
pass
def storeResult(self, result_base, result_inverted_base,plan_inverted_base):
dump = [ result_base , result_inverted_base , plan_inverted_base ]
with open("result_dump.json", "w") as h:
h.write(json.dumps(dump))
def loadResults(self):
dump = {}
try:
with open("result_dump.json") as h:
dump = json.loads(h.read())
except OSError:
pass
return dump[0], dump[1], dump[2]
if __name__ == '__main__':
problem = sys.argv[1]
processmode = sys.argv[2] # normal (webcall), store (Store Callresult), cache (skip Webcall and load stored data)
with open(os.path.join("..", "problems.json")) as h:
problems = json.loads(h.read())
problems = {p["problem"]: {"size": p["size"]} for p in problems}
if problem not in problems:
raise ExploreError(f"unknown problem {problem}")
mapper = LibMapper(problem,problems[problem]["size"], processmode)
mapper.start()