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
 
388 ira 50
	def search (self, add_function, MAX_ITERATIONS=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))
380 ira 70
			if not firsttime:
387 ira 71
				v1 = str(N)
72
				v2 = str(self.__find_nearest_child (M, CLOSED))
380 ira 73
 
74
				result.add_edge (v1, v2)
75
				result.set_edge_color (v1, v2, yapgvb.colors.red)
76
				result.set_edge_label (v1, v2, str(counter))
77
 
78
			else:
79
				firsttime = False
387 ira 80
			###############################################################
380 ira 81
 
82
			# Check if we've reached the goal
83
			if N in self.__goal_nodes:
387 ira 84
				return result
380 ira 85
 
388 ira 86
			# Add the children of N (aka M) to OPEN
87
			OPEN = add_function (M, OPEN, CLOSED)
380 ira 88
 
89
			counter += 1
90
 
388 ira 91
			# Check to make sure we don't loop for too long
92
			if counter > MAX_ITERATIONS:
93
				return 'FAILURE'
94
 
380 ira 95
		return 'FAILURE'
96
 
97
def add_bfs (M, OPEN, CLOSED):
98
	for node in M:
99
		if (node not in OPEN) and (node not in CLOSED):
100
			OPEN.append (node)
101
 
382 ira 102
	return OPEN
103
 
380 ira 104
def add_dfs (M, OPEN, CLOSED):
105
	for node in M:
106
		if (node not in OPEN) and (node not in CLOSED):
107
			OPEN.insert (0, node) # insert node at beginning
108
 
382 ira 109
	return OPEN
380 ira 110
 
382 ira 111
 
380 ira 112
from Graph import Graph
113
from DrawGraph import DrawGraph
387 ira 114
import random
380 ira 115
 
387 ira 116
def get_nth_child (start, n):
117
	child = start
118
	for i in xrange(n):
119
		child = random.choice(child.get_children())
120
 
121
	return child
122
 
380 ira 123
def main ():
387 ira 124
	initial = [1, 2, 3, 4, 'E', 5, 6, 7, 8]
380 ira 125
 
387 ira 126
	start = PuzzlePiece (initial)
388 ira 127
	goal = get_nth_child (start, 10)
380 ira 128
 
387 ira 129
	s = PuzzleSearch (start, (goal, ))
388 ira 130
	result = s.search (add_bfs, 1000)
380 ira 131
 
132
	if result != 'FAILURE':
387 ira 133
		DrawGraph ('result', result).render_graph ('res.svg', yapgvb.engines.dot)
388 ira 134
	else:
135
		print result
380 ira 136
 
137
 
138
if __name__ == '__main__':
139
	main ()