Subversion Repositories programming

Rev

Rev 424 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
423 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
from PyCompat import *
8
from Actions import *
424 ira 9
from Menu import Menu
423 ira 10
import sys
424 ira 11
import copy
429 ira 12
import random
423 ira 13
 
14
(WALK, PUSH, CLIMB, GRAB) = ('Walk', 'Push', 'Climb', 'Grab')
15
 
429 ira 16
class Possible:
17
	def __init__ (self, action, arg1=None, arg2=None):
18
		self.action = action
19
		self.arg1 = arg1
20
		self.arg2 = arg2
423 ira 21
 
429 ira 22
	def takeAction (self):
23
		pass
423 ira 24
 
429 ira 25
	def __eq__ (self, rhs):
26
		return (self.action == rhs.action) and (self.arg1 == rhs.arg1) \
27
				and (self.arg2 == rhs.arg2)
28
 
29
	def __repr__ (self):
30
		s = '(%s' % self.action
31
		if self.arg1:
32
			s += ', %s' % self.arg1
33
 
34
		if self.arg2:
35
			s += ', %s' % self.arg2
36
 
37
		return '%s)' % s
38
 
39
def generatePossibleMoves (State):
40
	moves = []
41
 
42
	# Grab, Priority 1
423 ira 43
	if Grab(State).meetsPreconditions():
429 ira 44
		moves.append ((1, Possible(GRAB)))
423 ira 45
 
429 ira 46
	# Push, Priority 2
47
	for f in LOCATIONS:
48
		for t in LOCATIONS:
49
			if Push(State, f, t).meetsPreconditions():
50
				moves.append ((2, Possible(PUSH, f, t)))
423 ira 51
 
429 ira 52
	# Climb, Priority 2
53
	for d in BOX_LOC:
54
		if Climb(State, d).meetsPreconditions():
55
			moves.append ((2, Possible(CLIMB, d)))
423 ira 56
 
429 ira 57
	# Walk, Priority 3
58
	for f in LOCATIONS:
59
		for t in LOCATIONS:
60
			if Walk(State, f, t).meetsPreconditions():
61
				moves.append ((3, Possible(WALK, f, t)))
423 ira 62
 
429 ira 63
	return moves
423 ira 64
 
429 ira 65
def chooseMove (moves, priority=None):
66
	possible = []
67
 
68
	# If priority was not set, choose something from the highest
69
	# priority that is available
70
	if not priority:
71
		if len(moves) > 0:
72
			moves.sort()
73
			priority = moves[0][0]
74
 
75
	for e in moves:
76
		if e[0] == priority:
77
			possible.append (e[1])
78
 
79
	# Make sure the list is not empty
80
	if len(possible) < 1:
81
		return False
82
 
83
	# Return a random choice from the possible moves of this priority
84
	return random.choice (possible)
85
 
86
# Return (loop_length, first_instruction_in_loop)
87
def loopDetector (plan_param):
88
	plan = copy.deepcopy (plan_param)
89
	plan.reverse()
90
 
91
	isloop = False
92
 
93
	for i in xrange(len(plan)):
94
		cur = plan[:i]
95
		rest= plan[i:]
96
 
97
		for i in xrange(len(cur)):
98
			isloop = True
99
			if cur[i] != rest[i]:
100
				isloop = False
101
				break
102
 
103
		if isloop:
104
			return (len(cur), cur[0])
105
 
106
	return False
107
 
108
 
109
def findNextMove (State):
110
	"""Prioritized Search for the best next move"""
111
 
112
	poss_moves = generatePossibleMoves(State)
113
	chose_move = chooseMove (poss_moves)
114
	#print 'POSSIBLE MOVES: ', poss_moves
115
	#print 'CHOOSE MOVE: ', chose_move
116
 
117
	return chose_move
118
 
423 ira 119
def isValidInitialState (State):
120
	monkeyPos = Action(State).findMonkeyPosition()
121
	boxPos = Action(State).findBoxPosition()
122
	onBox = Action(State).monkeyOnBox()
123
 
124
	if onBox and (monkeyPos != boxPos):
125
		return False
126
 
127
	return True
128
 
424 ira 129
def enter_initial_state ():
130
	State = set([])
423 ira 131
 
424 ira 132
	# Get Monkey Position
133
	m = Menu(autorun=True, name='Enter Monkey Position')
429 ira 134
	m.add_entry ('1', 'Window', lambda: WINDOW)
135
	m.add_entry ('2', 'Door', lambda: DOOR)
136
	m.add_entry ('3', 'Middle', lambda: MIDDLE)
424 ira 137
	m.add_entry ('Q', 'Quit', sys.exit)
138
 
139
	pos = m.run_menu()[1]
140
	State.add ('At(Monkey,%s)' % pos)
141
 
142
	# Get Box Position
143
	m = Menu(autorun=True, name='Enter Box Position')
429 ira 144
	m.add_entry ('1', 'Window', lambda: WINDOW)
145
	m.add_entry ('2', 'Door', lambda: DOOR)
146
	m.add_entry ('3', 'Middle', lambda: MIDDLE)
424 ira 147
	m.add_entry ('Q', 'Quit', sys.exit)
148
 
149
	pos = m.run_menu()[1]
150
	State.add ('At(Box,%s)' % pos)
151
 
152
	# Get Monkey Status
153
	m = Menu(autorun=True, name='Enter Monkey Height Status')
154
	m.add_entry ('1', 'Monkey on Box', lambda: 'OnBox()')
155
	m.add_entry ('2', 'Monkey on Floor', lambda: 'OnFloor()')
156
	m.add_entry ('Q', 'Quit', sys.exit)
157
 
158
	State.add (m.run_menu()[1])
159
 
160
	# Get Banana Status
161
	m = Menu(autorun=True, name='Enter Banana Status')
162
	m.add_entry ('1', 'Monkey has Banana', lambda: 'HasBanana()')
163
	m.add_entry ('2', 'Monkey does not have Banana', lambda: 'NoBanana()')
164
	m.add_entry ('Q', 'Quit', sys.exit)
165
 
166
	State.add (m.run_menu()[1])
167
 
168
	return State
169
 
170
def find_plan (State):
423 ira 171
	if not isValidInitialState (State):
424 ira 172
		print 'Bad initial state\n'
173
		return
423 ira 174
 
424 ira 175
	if Action(State).isGoal():
176
		print 'Initial State is already a goal state\n'
177
		return
178
 
179
	print 'Plan:'
423 ira 180
	while not Action(State).isGoal():
181
 
182
		next = findNextMove (State)
429 ira 183
		action = next.action
184
		arg1 = next.arg1
185
		arg2 = next.arg2
423 ira 186
 
187
		if action == WALK:
429 ira 188
			print '%s from %s to %s' % (action, arg1, arg2)
189
			State = Walk(State, arg1, arg2).takeAction()
423 ira 190
		elif action == PUSH:
429 ira 191
			print '%s Box from %s to %s' % (action, arg1, arg2)
192
			State = Push(State, arg1, arg2).takeAction ()
423 ira 193
		elif action == CLIMB:
429 ira 194
			print '%s %s' % (action, arg1)
195
			State = Climb(State, arg1).takeAction()
423 ira 196
		elif action == GRAB:
429 ira 197
			print '%s Banana' % action
423 ira 198
			State = Grab(State).takeAction()
199
		else:
200
			print 'BAD STATE'
424 ira 201
			return
423 ira 202
 
424 ira 203
	print
423 ira 204
 
424 ira 205
 
206
def main ():
207
 
208
	# Create the main menu
209
	m = Menu (name='Main Menu')
210
	m.add_entry ('1', 'Enter Initial State', enter_initial_state)
211
	m.add_entry ('2', 'Find Plan', find_plan)
212
	m.add_entry ('Q', 'Quit', sys.exit)
213
	m.hide_entry ('2')
214
 
215
	# Run the menu
216
	while True:
217
		(num, func) = m.run_menu ()
218
 
219
		if num == '1':
220
			State = func()
221
			m.unhide_entry ('2')
222
		elif num == '2':
223
			func(copy.deepcopy(State))
224
		else:
225
			func()
226
 
423 ira 227
if __name__ == '__main__':
228
	main ()
229
 
230
# vim: set ts=4 sts=4 sw=4:
231