# Creation du probleme complet : navigation dans un labyrinthe
# Instance NON TRIVIALE : 15 locations en reseau avec impasses (dead-ends).
# Les dead-ends (L3, L6, L9, L12, L14) sont des branches sans issue : une recherche
# aveugle (BFS/DFS pur) y perd du temps, tandis qu'un solveur heuristique (h^FF,
# landmarks) les elimine vite. C'est ce diferencia que unified-planning met en valeur.
problem = Problem('robot_navigation')
# Ajout des fluents au probleme
problem.add_fluent(robot_at, default_initial_value=False)
problem.add_fluent(connected, default_initial_value=False)
problem.add_fluent(visited, default_initial_value=False)
# Ajout de l'action
problem.add_action(move)
# Creation des objets : 15 locations + 1 robot
locations = [Object(f'L{i}', Location) for i in range(15)]
robot = Object('robot1', Robot)
for loc in locations:
problem.add_object(loc)
problem.add_object(robot)
# Graphe du labyrinthe (connexions orientees bidirectionnelles) :
# Chemin principal (corridor) : L0 - L1 - L2 - L4 - L7 - L10 - L13
# Branches secondaires menant au but : L10 - L11, L13 - L11 (le but L11 est atteignable)
# Impasses (dead-ends) : L3 (depuis L1), L5 (depuis L4), L6 (depuis L2),
# L8 (depuis L7), L9 (depuis L2), L12 (depuis L10), L14 (depuis L13)
# L'objectif : rejoindre L11 depuis L0. Chemin court : L0-L1-L2-L4-L7-L10-L11 (6 moves),
# chemin long via L13 : L0-...-L10-L13-L11 (7 moves). 7 impasses penchant la recherche aveugle.
connections = [
# Chemin principal L0 -> L1 -> L2 -> L4 -> L7 -> L10 -> L13
(0, 1), (1, 0),
(1, 2), (2, 1),
(2, 4), (4, 2),
(4, 7), (7, 4),
(7, 10), (10, 7),
(10, 13), (13, 10),
# Acces au but L11 (depuis L10 ET L13 : deux routes vers le but)
(10, 11), (11, 10),
(13, 11), (11, 13),
# Dead-ends (branches sans issue) : pieges pour la recherche aveugle
(1, 3), (3, 1), # impasse L3
(4, 5), (5, 4), # impasse L5
(2, 6), (6, 2), # impasse L6
(7, 8), (8, 7), # impasse L8
(2, 9), (9, 2), # impasse L9
(10, 12), (12, 10), # impasse L12
(13, 14), (14, 13), # impasse L14
]
for i, j in connections:
problem.set_initial_value(connected(locations[i], locations[j]), True)
# Etat initial : robot a L0 (entree du labyrinthe)
problem.set_initial_value(robot_at(robot, locations[0]), True)
problem.set_initial_value(visited(locations[0]), True)
# But : atteindre L11 (sortie du labyrinthe)
problem.add_goal(robot_at(robot, locations[11]))
print(f"Probleme '{problem.name}' cree")
print(f" Objets : {len(locations)} locations, 1 robot")
print(f" Connexions : {len(connections)} aretes")
print(f" Etat initial : robot a L0 (entree)")
print(f" But : atteindre L11 (sortie)")
print(f" 7 impasses (dead-ends) : L3, L5, L6, L8, L9, L12, L14 -- pieges pour la recherche aveugle")
print(f" Chemin optimal attendu : ~6 moves (L0-L1-L2-L4-L7-L10-L11, route courte)")