Subversion Repositories programming

Rev

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

#!/usr/bin/env python

__author__    = "Ira W. Snyder (devel@irasnyder.com)"
__copyright__ = "Copyright (c) 2006, Ira W. Snyder (devel@irasnyder.com)"
__license__   = "GNU GPL v2 (or, at your option, any later version)"

from PyCompat import *
from Actions import *
from Menu import Menu
import sys
import copy
import random

(WALK, PUSH, CLIMB, GRAB) = ('Walk', 'Push', 'Climb', 'Grab')

class Possible:
        def __init__ (self, action, arg1=None, arg2=None):
                self.action = action
                self.arg1 = arg1
                self.arg2 = arg2

        def takeAction (self):
                pass

        def __eq__ (self, rhs):
                return (self.action == rhs.action) and (self.arg1 == rhs.arg1) \
                                and (self.arg2 == rhs.arg2)

        def __repr__ (self):
                s = '(%s' % self.action
                if self.arg1:
                        s += ', %s' % self.arg1

                if self.arg2:
                        s += ', %s' % self.arg2

                return '%s)' % s

def generatePossibleMoves (State):
        moves = []

        # Grab, Priority 1
        if Grab(State).meetsPreconditions():
                moves.append ((1, Possible(GRAB)))

        # Push, Priority 2
        for f in LOCATIONS:
                for t in LOCATIONS:
                        if Push(State, f, t).meetsPreconditions():
                                moves.append ((2, Possible(PUSH, f, t)))

        # Climb, Priority 2
        for d in BOX_LOC:
                if Climb(State, d).meetsPreconditions():
                        moves.append ((2, Possible(CLIMB, d)))

        # Walk, Priority 3
        for f in LOCATIONS:
                for t in LOCATIONS:
                        if Walk(State, f, t).meetsPreconditions():
                                moves.append ((3, Possible(WALK, f, t)))

        return moves

def chooseMove (moves, priority=None):
        possible = []

        # If priority was not set, choose something from the highest
        # priority that is available
        if not priority:
                if len(moves) > 0:
                        moves.sort()
                        priority = moves[0][0]

        for e in moves:
                if e[0] == priority:
                        possible.append (e[1])

        # Make sure the list is not empty
        if len(possible) < 1:
                return False

        # Return a random choice from the possible moves of this priority
        return random.choice (possible)

# Return (loop_length, first_instruction_in_loop)
def loopDetector (plan_param):
        plan = copy.deepcopy (plan_param)
        plan.reverse()

        isloop = False

        for i in xrange(len(plan)):
                cur = plan[:i]
                rest= plan[i:]

                for i in xrange(len(cur)):
                        isloop = True
                        if cur[i] != rest[i]:
                                isloop = False
                                break

                if isloop:
                        return (len(cur), cur[0])

        return False
        

def findNextMove (State):
        """Prioritized Search for the best next move"""

        poss_moves = generatePossibleMoves(State)
        chose_move = chooseMove (poss_moves)
        #print 'POSSIBLE MOVES: ', poss_moves
        #print 'CHOOSE MOVE: ', chose_move

        return chose_move

def isValidInitialState (State):
        monkeyPos = Action(State).findMonkeyPosition()
        boxPos = Action(State).findBoxPosition()
        onBox = Action(State).monkeyOnBox()

        if onBox and (monkeyPos != boxPos):
                return False

        return True

def enter_initial_state ():
        State = set([])

        # Get Monkey Position
        m = Menu(autorun=True, name='Enter Monkey Position')
        m.add_entry ('1', 'Window', lambda: WINDOW)
        m.add_entry ('2', 'Door', lambda: DOOR)
        m.add_entry ('3', 'Middle', lambda: MIDDLE)
        m.add_entry ('Q', 'Quit', sys.exit)

        pos = m.run_menu()[1]
        State.add ('At(Monkey,%s)' % pos)

        # Get Box Position
        m = Menu(autorun=True, name='Enter Box Position')
        m.add_entry ('1', 'Window', lambda: WINDOW)
        m.add_entry ('2', 'Door', lambda: DOOR)
        m.add_entry ('3', 'Middle', lambda: MIDDLE)
        m.add_entry ('Q', 'Quit', sys.exit)

        pos = m.run_menu()[1]
        State.add ('At(Box,%s)' % pos)

        # Get Monkey Status
        m = Menu(autorun=True, name='Enter Monkey Height Status')
        m.add_entry ('1', 'Monkey on Box', lambda: 'OnBox()')
        m.add_entry ('2', 'Monkey on Floor', lambda: 'OnFloor()')
        m.add_entry ('Q', 'Quit', sys.exit)

        State.add (m.run_menu()[1])

        # Get Banana Status
        m = Menu(autorun=True, name='Enter Banana Status')
        m.add_entry ('1', 'Monkey has Banana', lambda: 'HasBanana()')
        m.add_entry ('2', 'Monkey does not have Banana', lambda: 'NoBanana()')
        m.add_entry ('Q', 'Quit', sys.exit)

        State.add (m.run_menu()[1])

        return State

def find_plan (State):
        if not isValidInitialState (State):
                print 'Bad initial state\n'
                return

        if Action(State).isGoal():
                print 'Initial State is already a goal state\n'
                return

        print 'Plan:'
        while not Action(State).isGoal():

                next = findNextMove (State)
                action = next.action
                arg1 = next.arg1
                arg2 = next.arg2

                if action == WALK:
                        print '%s from %s to %s' % (action, arg1, arg2)
                        State = Walk(State, arg1, arg2).takeAction()
                elif action == PUSH:
                        print '%s Box from %s to %s' % (action, arg1, arg2)
                        State = Push(State, arg1, arg2).takeAction ()
                elif action == CLIMB:
                        print '%s %s' % (action, arg1)
                        State = Climb(State, arg1).takeAction()
                elif action == GRAB:
                        print '%s Banana' % action
                        State = Grab(State).takeAction()
                else:
                        print 'BAD STATE'
                        return

        print


def main ():

        # Create the main menu
        m = Menu (name='Main Menu')
        m.add_entry ('1', 'Enter Initial State', enter_initial_state)
        m.add_entry ('2', 'Find Plan', find_plan)
        m.add_entry ('Q', 'Quit', sys.exit)
        m.hide_entry ('2')

        # Run the menu
        while True:
                (num, func) = m.run_menu ()

                if num == '1':
                        State = func()
                        m.unhide_entry ('2')
                elif num == '2':
                        func(copy.deepcopy(State))
                else:
                        func()

if __name__ == '__main__':
        main ()

# vim: set ts=4 sts=4 sw=4: