Subversion Repositories programming

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
380 ira 1
#!/usr/bin/env python
2
 
3
__author__    = "Ira W. Snyder (devel@irasnyder.com)"
4
__copyright__ = "Copyright (c) 2006 Ira W. Snyder (devel@irasnyder.com)"
5
__license__   = "GNU GPL v2 (or, at your option, any later version)"
6
 
7
# 1) Put the start node N0 on OPEN. Create G with just this node
8
# 2) Create the list CLOSED which is empty
9
#
10
# LOOP:
11
#
12
# 3) If OPEN is empty, exit with FAILURE
13
# 4) Select the first node from OPEN, put it on CLOSED. Call this N
14
# 5) If N is a goal node, exit successfully with the solution in G
15
# 6) Generate M from the children of N
16
# 7) Add anything not in M not in (CLOSED union OPEN) to OPEN
17
# 8) Reorder OPEN appropriately
18
# 9) goto LOOP
19
 
387 ira 20
from PuzzlePiece import PuzzlePiece
380 ira 21
from Graph import Graph
22
import yapgvb
23
 
387 ira 24
class PuzzleSearch (object):
380 ira 25
	"""Implements a graph search"""
26
 
387 ira 27
	def __init__ (self, start_node, goal_nodes):
380 ira 28
		"""Constructor.
387 ira 29
		start_node: the node to start at (must have a get_children() function)
380 ira 30
		goal_nodes: a list of nodes to end at"""
31
 
32
		self.__start_node = start_node
33
		self.__goal_nodes = goal_nodes
34
		self.__ordering_func = list.sort
35
 
36
	def set_ordering_func (self, func):
37
		"""Set the ordering function to use."""
38
		self.__ordering_func = func
39
 
40
	def __find_nearest_child (self, children, already_visited):
41
		"""Find the child that we came from. This necessitates that
42
		the list already_visited be sorted in the order of nodes visited"""
43
		for n in reversed(already_visited):
44
			if n in children:
45
				return n
46
 
47
		# This should never happen
48
		raise ValueError
49
 
391 ira 50
	def search (self, add_function, MAX_NODES_CREATED=100):
380 ira 51
 
52
		# Create the result graph
53
		result = Graph ()
54
		firsttime = True
55
		counter = 0
56
 
57
		OPEN = [self.__start_node]
58
		CLOSED = []
59
 
60
		while OPEN:
61
			N = OPEN.pop(0)
62
			CLOSED.append (N)
63
 
64
			# Find all possible next paths
387 ira 65
			M = N.get_children()
380 ira 66
 
387 ira 67
			###############################################################
380 ira 68
			# Add the current place to the result graph
387 ira 69
			result.add_vertex (str(N))
392 ira 70
 
380 ira 71
			if not firsttime:
387 ira 72
				v1 = str(N)
73
				v2 = str(self.__find_nearest_child (M, CLOSED))
380 ira 74
 
75
				result.add_edge (v1, v2)
76
				result.set_edge_color (v1, v2, yapgvb.colors.red)
77
				result.set_edge_label (v1, v2, str(counter))
78
 
392 ira 79
				result.set_vertex_value (str(N), result.get_vertex_value(v2)+1)
80
 
380 ira 81
			else:
391 ira 82
				# Set start node shape to be a double circle
83
				result.set_vertex_shape (str(N), yapgvb.shapes.doublecircle)
392 ira 84
				result.set_vertex_value (str(N), 0) # set depth
380 ira 85
				firsttime = False
387 ira 86
			###############################################################
380 ira 87
 
88
			# Check if we've reached the goal
89
			if N in self.__goal_nodes:
392 ira 90
				print '%s nodes created' % (len(OPEN) + len(CLOSED))
91
				print 'searched to depth: %s' % result.get_vertex_value (str(N))
391 ira 92
				# Set the goal node's shape to be a diamond
93
				result.set_vertex_shape (str(N), yapgvb.shapes.diamond)
387 ira 94
				return result
380 ira 95
 
388 ira 96
			# Add the children of N (aka M) to OPEN
97
			OPEN = add_function (M, OPEN, CLOSED)
380 ira 98
 
99
			counter += 1
100
 
388 ira 101
			# Check to make sure we don't loop for too long
391 ira 102
			if (len(OPEN) + len(CLOSED)) > MAX_NODES_CREATED:
388 ira 103
				return 'FAILURE'
104
 
380 ira 105
		return 'FAILURE'
106
 
107
def add_bfs (M, OPEN, CLOSED):
108
	for node in M:
109
		if (node not in OPEN) and (node not in CLOSED):
110
			OPEN.append (node)
111
 
382 ira 112
	return OPEN
113
 
380 ira 114
def add_dfs (M, OPEN, CLOSED):
115
	for node in M:
116
		if (node not in OPEN) and (node not in CLOSED):
117
			OPEN.insert (0, node) # insert node at beginning
118
 
382 ira 119
	return OPEN
380 ira 120
 
382 ira 121
 
380 ira 122
from Graph import Graph
123
from DrawGraph import DrawGraph
387 ira 124
import random
380 ira 125
 
387 ira 126
def get_nth_child (start, n):
127
	child = start
128
	for i in xrange(n):
129
		child = random.choice(child.get_children())
130
 
131
	return child
132
 
380 ira 133
def main ():
387 ira 134
	initial = [1, 2, 3, 4, 'E', 5, 6, 7, 8]
380 ira 135
 
387 ira 136
	start = PuzzlePiece (initial)
388 ira 137
	goal = get_nth_child (start, 10)
380 ira 138
 
387 ira 139
	s = PuzzleSearch (start, (goal, ))
388 ira 140
	result = s.search (add_bfs, 1000)
380 ira 141
 
142
	if result != 'FAILURE':
387 ira 143
		DrawGraph ('result', result).render_graph ('res.svg', yapgvb.engines.dot)
388 ira 144
	else:
145
		print result
380 ira 146
 
147
 
148
if __name__ == '__main__':
149
	main ()