-
Notifications
You must be signed in to change notification settings - Fork 24
/
planner.py
98 lines (86 loc) · 3.5 KB
/
planner.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!/usr/bin/env python
# Four spaces as indentation [no tabs]
# This file is part of PDDL Parser, available at <https://github.com/pucrs-automated-planning/pddl-parser>.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
from .PDDL import PDDL_Parser
class Planner:
# -----------------------------------------------
# Solve
# -----------------------------------------------
def solve(self, domain, problem):
# Parser
parser = PDDL_Parser()
parser.parse_domain(domain)
parser.parse_problem(problem)
# Parsed data
state = parser.state
goal_pos = parser.positive_goals
goal_not = parser.negative_goals
# Do nothing
if self.applicable(state, goal_pos, goal_not):
return []
# Grounding process
ground_actions = []
for action in parser.actions:
for act in action.groundify(parser.objects, parser.types):
ground_actions.append(act)
# Search
visited = set([state])
fringe = [state, None]
while fringe:
state = fringe.pop(0)
plan = fringe.pop(0)
for act in ground_actions:
if self.applicable(state, act.positive_preconditions, act.negative_preconditions):
new_state = self.apply(state, act.add_effects, act.del_effects)
if new_state not in visited:
if self.applicable(new_state, goal_pos, goal_not):
full_plan = [act]
while plan:
act, plan = plan
full_plan.insert(0, act)
return full_plan
visited.add(new_state)
fringe.append(new_state)
fringe.append((act, plan))
return None
# -----------------------------------------------
# Applicable
# -----------------------------------------------
def applicable(self, state, positive, negative):
return positive.issubset(state) and negative.isdisjoint(state)
# -----------------------------------------------
# Apply
# -----------------------------------------------
def apply(self, state, positive, negative):
return state.difference(negative).union(positive)
# -----------------------------------------------
# Main
# -----------------------------------------------
if __name__ == '__main__':
import sys, time
start_time = time.time()
domain = sys.argv[1]
problem = sys.argv[2]
verbose = len(sys.argv) > 3 and sys.argv[3] == '-v'
planner = Planner()
plan = planner.solve(domain, problem)
print('Time: ' + str(time.time() - start_time) + 's')
if plan is not None:
print('plan:')
for act in plan:
print(act if verbose else act.name + ' ' + ' '.join(act.parameters))
else:
sys.exit('No plan was found')