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
 
50
	def search (self):
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
 
387 ira 86
			# FIXME
382 ira 87
			OPEN = add_bfs (M, OPEN, CLOSED)
380 ira 88
 
89
			counter += 1
90
 
91
		return 'FAILURE'
92
 
93
def add_bfs (M, OPEN, CLOSED):
94
	for node in M:
95
		if (node not in OPEN) and (node not in CLOSED):
96
			OPEN.append (node)
97
 
382 ira 98
	return OPEN
99
 
380 ira 100
def add_dfs (M, OPEN, CLOSED):
101
	for node in M:
102
		if (node not in OPEN) and (node not in CLOSED):
103
			OPEN.insert (0, node) # insert node at beginning
104
 
382 ira 105
	return OPEN
380 ira 106
 
382 ira 107
 
380 ira 108
from Graph import Graph
109
from DrawGraph import DrawGraph
387 ira 110
import random
380 ira 111
 
387 ira 112
def get_nth_child (start, n):
113
	child = start
114
	for i in xrange(n):
115
		child = random.choice(child.get_children())
116
 
117
	return child
118
 
380 ira 119
def main ():
387 ira 120
	initial = [1, 2, 3, 4, 'E', 5, 6, 7, 8]
380 ira 121
 
387 ira 122
	start = PuzzlePiece (initial)
123
	goal = get_nth_child (start, 2)
380 ira 124
 
387 ira 125
	s = PuzzleSearch (start, (goal, ))
380 ira 126
	result = s.search ()
127
 
128
	if result != 'FAILURE':
387 ira 129
		DrawGraph ('result', result).render_graph ('res.svg', yapgvb.engines.dot)
380 ira 130
 
131
 
132
if __name__ == '__main__':
133
	main ()