394 |
ira |
1 |
#!/usr/bin/env python
|
|
|
2 |
|
395 |
ira |
3 |
# Fix for the lame version of python on the school's computers (v2.1)
|
|
|
4 |
try:
|
|
|
5 |
(True, False)
|
|
|
6 |
except NameError:
|
|
|
7 |
(True, False) = (1, 0)
|
|
|
8 |
|
394 |
ira |
9 |
from Menu import Menu
|
|
|
10 |
from PuzzlePiece import PuzzlePiece
|
|
|
11 |
import PuzzleSearch
|
|
|
12 |
import sys
|
|
|
13 |
|
|
|
14 |
################################################################################
|
|
|
15 |
### Search Algorithms
|
|
|
16 |
################################################################################
|
|
|
17 |
|
|
|
18 |
DEFAULT_MAX_ITERATIONS=1000
|
|
|
19 |
|
|
|
20 |
def m_search_generic (name, start, goals, add_algorithm, MAX_ITERATIONS=DEFAULT_MAX_ITERATIONS):
|
|
|
21 |
s = PuzzleSearch.PuzzleSearch (start, goals)
|
|
|
22 |
|
|
|
23 |
# Run the search
|
|
|
24 |
result = s.search (add_algorithm, MAX_ITERATIONS)
|
|
|
25 |
result.set_search_name (name)
|
|
|
26 |
print result
|
|
|
27 |
print
|
|
|
28 |
|
|
|
29 |
return result
|
|
|
30 |
|
|
|
31 |
def m_bfs (start_node, goal_node):
|
|
|
32 |
return m_search_generic ('Breadth First Search', start_node,
|
|
|
33 |
(goal_node, ), PuzzleSearch.add_bfs)
|
|
|
34 |
|
|
|
35 |
def m_dfs (start_node, goal_node):
|
|
|
36 |
return m_search_generic ('Depth First Search', start_node,
|
|
|
37 |
(goal_node, ), PuzzleSearch.add_dfs)
|
|
|
38 |
|
|
|
39 |
def m_bfs_h1 (start_node, goal_node):
|
|
|
40 |
return m_search_generic ('Best First Search: Heuristic 1', start_node,
|
|
|
41 |
(goal_node, ), PuzzleSearch.bfs_oop)
|
|
|
42 |
|
|
|
43 |
def m_bfs_h2 (start_node, goal_node):
|
|
|
44 |
return m_search_generic ('Best First Search: Heuristic 2', start_node,
|
|
|
45 |
(goal_node, ), PuzzleSearch.bfs_dfc)
|
|
|
46 |
|
|
|
47 |
def m_asearch_h1 (start_node, goal_node):
|
|
|
48 |
return m_search_generic ('A*-Search: Heuristic 1', start_node,
|
|
|
49 |
(goal_node, ), PuzzleSearch.astar_oop)
|
|
|
50 |
|
|
|
51 |
def m_asearch_h2 (start_node, goal_node):
|
|
|
52 |
return m_search_generic ('A*-Search: Heuristic 2', start_node,
|
|
|
53 |
(goal_node, ), PuzzleSearch.astar_dfc)
|
|
|
54 |
|
|
|
55 |
################################################################################
|
|
|
56 |
|
|
|
57 |
def m_render_graph (result):
|
|
|
58 |
try:
|
395 |
ira |
59 |
no_graphviz = False
|
394 |
ira |
60 |
import yapgvb
|
395 |
ira |
61 |
except ImportError:
|
|
|
62 |
no_graphviz = True
|
394 |
ira |
63 |
|
395 |
ira |
64 |
from DrawGraph import DrawGraph
|
394 |
ira |
65 |
|
395 |
ira |
66 |
if no_graphviz:
|
|
|
67 |
dg = DrawGraph (result.search_name, result.result_graph)
|
|
|
68 |
dg.render_stupid ('generated_by')
|
396 |
ira |
69 |
print
|
395 |
ira |
70 |
|
394 |
ira |
71 |
# Try to render the graph, nicely
|
395 |
ira |
72 |
elif result.result_graph != None:
|
394 |
ira |
73 |
fname = raw_input('Enter filename (press ENTER for \'res.svg\'): ')
|
|
|
74 |
print
|
|
|
75 |
|
|
|
76 |
if fname == '':
|
|
|
77 |
fname = 'res.svg'
|
|
|
78 |
|
|
|
79 |
# Actually draw the graph
|
|
|
80 |
dg = DrawGraph (result.search_name, result.result_graph)
|
395 |
ira |
81 |
dg.render_graphviz (fname, yapgvb.engines.dot)
|
394 |
ira |
82 |
else:
|
|
|
83 |
print 'The search failed, therefore I cannot render the graph!'
|
|
|
84 |
|
|
|
85 |
def gen_start_state (goal_node):
|
|
|
86 |
DEPTH=12
|
|
|
87 |
result = PuzzleSearch.get_nth_child (goal_node, DEPTH)
|
|
|
88 |
|
|
|
89 |
# "Fix" the node given back to us
|
|
|
90 |
result.depth = 0
|
|
|
91 |
result.goal = goal_node
|
|
|
92 |
return result
|
|
|
93 |
|
|
|
94 |
def getstr (prompt):
|
|
|
95 |
return raw_input (prompt + ': ')
|
|
|
96 |
|
|
|
97 |
def input_start_state ():
|
|
|
98 |
state = []
|
|
|
99 |
valid_inputs = ('1', '2', '3', '4', '5', '6', '7', '8', 'E')
|
|
|
100 |
|
|
|
101 |
print 'Input start state, one row at a time, space seperated:'
|
|
|
102 |
state += getstr ('Row 1').split()
|
|
|
103 |
state += getstr ('Row 2').split()
|
|
|
104 |
state += getstr ('Row 3').split()
|
|
|
105 |
|
|
|
106 |
# Check and make sure its ok
|
|
|
107 |
if len(state) != 9:
|
|
|
108 |
print 'Too many states, try again!\n'
|
|
|
109 |
return input_start_state ()
|
|
|
110 |
|
|
|
111 |
for el in state:
|
|
|
112 |
if el not in valid_inputs:
|
|
|
113 |
print '"%s" is not valid, try again!' % el
|
|
|
114 |
return input_start_state ()
|
|
|
115 |
|
|
|
116 |
return state
|
|
|
117 |
|
|
|
118 |
|
|
|
119 |
def main ():
|
|
|
120 |
|
|
|
121 |
# Very important start state information
|
|
|
122 |
goal_config = ['1', '2', '3', '8', 'E', '4', '7', '6', '5']
|
|
|
123 |
goal_node = PuzzlePiece (goal_config)
|
|
|
124 |
|
|
|
125 |
m = Menu ()
|
|
|
126 |
m.add_entry ('1', 'Enter start state', input_start_state)
|
|
|
127 |
m.add_entry ('2', 'Generate Reachable Start State', gen_start_state)
|
|
|
128 |
m.add_entry ('3', 'Quit', sys.exit)
|
|
|
129 |
(entry, callback) = m.run_menu ()
|
|
|
130 |
|
|
|
131 |
# Must be from #1
|
|
|
132 |
if entry == '1':
|
|
|
133 |
start_node = PuzzlePiece (callback(), 0, goal_node)
|
|
|
134 |
elif entry == '2':
|
|
|
135 |
start_node = callback(goal_node)
|
|
|
136 |
|
|
|
137 |
# Get set up for the next menu
|
|
|
138 |
search_result = None
|
|
|
139 |
|
|
|
140 |
# Set up the final menu
|
|
|
141 |
m = Menu ()
|
|
|
142 |
m.add_entry ('1', 'Breadth First Search', m_bfs)
|
|
|
143 |
m.add_entry ('2', 'Depth First Search', m_dfs)
|
|
|
144 |
m.add_entry ('3', 'Best First Search: Heuristic 1', m_bfs_h1)
|
|
|
145 |
m.add_entry ('4', 'Best First Search: Heuristic 2', m_bfs_h2)
|
|
|
146 |
m.add_entry ('5', 'A*-Search: Heuristic 1', m_asearch_h1)
|
|
|
147 |
m.add_entry ('6', 'A*-Search: Heuristic 2', m_asearch_h2)
|
|
|
148 |
m.add_entry ('7', 'Change Start State', input_start_state)
|
|
|
149 |
m.add_entry ('8', 'Generate Reachable Start State', gen_start_state)
|
|
|
150 |
m.add_entry ('9', 'Render Graph of last result', m_render_graph)
|
|
|
151 |
m.add_entry ('q', 'Quit', sys.exit)
|
|
|
152 |
m.hide_entry ('9')
|
|
|
153 |
|
|
|
154 |
while True:
|
|
|
155 |
# Add support for graph rendering
|
|
|
156 |
m.hide_entry ('9')
|
|
|
157 |
if search_result:
|
|
|
158 |
if search_result.completed:
|
|
|
159 |
m.unhide_entry ('9')
|
|
|
160 |
|
|
|
161 |
(entry, callback) = m.run_menu ()
|
|
|
162 |
|
|
|
163 |
# Check if we need to change the start node
|
|
|
164 |
if entry == '7':
|
|
|
165 |
start_node = PuzzlePiece (callback(), 0, goal_node)
|
|
|
166 |
elif entry == '8':
|
|
|
167 |
search_result = False
|
|
|
168 |
start_node = callback (goal_node)
|
|
|
169 |
elif entry == '9':
|
|
|
170 |
callback (search_result)
|
|
|
171 |
# Check if we need to quit
|
|
|
172 |
elif entry == 'q':
|
|
|
173 |
callback ()
|
|
|
174 |
else:
|
|
|
175 |
# Must be one of the search functions, so call them!
|
|
|
176 |
search_result = callback (start_node, goal_node)
|
|
|
177 |
|
|
|
178 |
if __name__ == '__main__':
|
|
|
179 |
main ()
|
|
|
180 |
|