""" RUR-PLE: Roberge's Used Robot - a Python Learning Environment
cpu.py - "Central Processing Unit" for the robot
Version 0.9.8.5
Author: Andre Roberge Copyright 2005, 2006
andre.roberge@gmail.com
"""
import sys
import wx
import time # for delay in robot movement
import dialogs as rD
import event_manager
from rur_py.translation import _
from robot_factory import Used_robot,New_improved_robot
from world_creation import Visible_world
import rur_py.parser as parser
import test_import
class Singleton(object):
"""From the 2nd edition of the Python cookbook."""
def __new__(cls, *args, **kwargs):
if '_inst' not in vars(cls):
cls._inst = object.__new__(cls, *args, **kwargs)
return cls._inst
class rur_program(Singleton):
def myInit(self, parent, wld, WldDis, ProgEdit, r_dict):
self.parent = parent
self.world = wld
self.WorldDisplay = WldDis
self.ProgramEditor = ProgEdit
self.robot_dict = r_dict
self.isRunning = False
self.isStepped = False
self.isPaused = False
self.stopped_by_user = False
def restart(self, r_dict):
code = self.ProgramEditor.GetText()
no_error, mesg = parser.ParseProgram(code)
if no_error:
self.code = parser.FixLineEnding(code)
self.lines_of_code = self.code.split('\n')
code, flag = test_import.process_file(code)
else:
self.code = ""
rD.rurMessageDialog(mesg, _("Error found in your program."))
self.robot_dict = r_dict
self.isPaused = False
self.stopped_by_user = False
self.execute_program()
def StopProgram(self):
self.isPaused = False
self.isStepped = False
self.isRunning = False
self.stopped_by_user = True
def set_line_number(self, n, name='robot'): # obtained from my_trace
try:
robot = self.robot_dict[name]
except KeyError:
for key in self.robot_dict:
name = key
break
if name == 'robot': # no robot created yet
self.ProgramEditor.highlight(n-1)
return
robot = self.robot_dict[name]
self.ProgramEditor.highlight(n-1)
self.ProgramEditor.Refresh()
self.wait_update_refresh(robot, name)
#--- Robot actions
def turn_off(self, name='robot'):
robot = self.robot_dict[name]
robot.turn_off() # will raise an exception to indicate normal end :-)
def move(self, name='robot'):
robot = self.robot_dict[name]
x0, y0 = robot.getPos()
robot.move() # may raise an exception
x1, y1 = robot.getPos()
orientation = robot._getOrientation()
colour = robot.trace_colour
style = robot.trace_style
robot.line_trace.append( (x0, y0, x1, y1, orientation, style, colour) )
self.update_refresh(robot, name)
def turn_left(self, name='robot'):
robot = self.robot_dict[name]
x, y = robot.getPos()
orientation = robot._getOrientation()
colour = robot.trace_colour
style = robot.trace_style
robot.line_trace.append( (x, y, x, y, orientation, style, colour) )
robot.turn_left() # must occur after line_trace.append
self.update_refresh(robot, name)
def turn_right(self, name='robot'):
robot = self.robot_dict[name]
x, y = robot.getPos()
orientation = robot._getOrientation()
colour = robot.trace_colour
style = robot.trace_style
robot.line_trace.append( (x, y, x, y, orientation, style, colour) )
robot.turn_right() # must occur after line_trace.append
self.update_refresh(robot, name)
def put_beeper(self, name='robot'):
robot = self.robot_dict[name]
robot.put_beeper() # may raise an exception
self.update_refresh(robot, name)
def pick_beeper(self, name='robot'):
robot = self.robot_dict[name]
robot.pick_beeper() # may raise an exception
self.update_refresh(robot, name)
def set_trace_style(self, style=1, colour='sea green', name='robot'):
robot = self.robot_dict[name]
robot.set_trace_style(style, colour)
def set_delay(self, delay, name='robot'):
robot = self.robot_dict[name]
robot.delay = delay
def roll_dice(self, n, name='robot'):
robot = self.robot_dict[name]
return robot.roll_dice(n)
#--- tests
def front_is_clear(self, name='robot'):
robot = self.robot_dict[name]
return robot.front_is_clear()
def left_is_clear(self, name='robot'):
robot = self.robot_dict[name]
return robot.left_is_clear()
def right_is_clear(self, name='robot'):
robot = self.robot_dict[name]
return robot.right_is_clear()
def facing_north(self, name='robot'):
robot = self.robot_dict[name]
return robot.facing_north()
def facing_west(self, name='robot'):
robot = self.robot_dict[name]
return robot.facing_west()
def facing_east(self, name='robot'):
robot = self.robot_dict[name]
return robot.facing_east()
def facing_south(self, name='robot'):
robot = self.robot_dict[name]
return robot.facing_south()
def carries_beepers(self, name='robot'):
robot = self.robot_dict[name]
return robot.any_beepers_in_beeper_bag()
def next_to_a_beeper(self, name='robot'):
robot = self.robot_dict[name]
return robot.next_to_a_beeper()
#--- display controls
def wait_update_refresh(self, robot, name):
wx.Yield()
if self.stopped_by_user:
self.stopped_by_user = False
mesg = _("Hey! You stopped me!")
raise rD.UserStopException(mesg)
return
if self.isStepped:
self.isStepped = False
self.isPaused = True
arg = self.parent.status_bar.running_field, _("Program paused")
event_manager.SendCustomEvent(self.parent, arg)
while self.isPaused:
wx.Yield()
time.sleep(0.01)
wx.Yield()
self.update_refresh(robot, name)
def update_refresh(self, robot, name):
if 'robot' in self.robot_dict:
arg = self.parent.status_bar.beeper_field, self.robot_dict['robot']._beeper_bag
event_manager.SendCustomEvent(self.parent, arg)
time.sleep(robot.delay)
wx.Yield()
self.world.DoDrawing()
self.WorldDisplay.drawImage()
if name:
self.WorldDisplay.scrollWorld(name)
self.WorldDisplay.Refresh()
wx.Yield()
def repeat(self, f, n):
for i in range(n):
f()
def clear_trace(self):
'''Removes the trails left by the robots.'''
for name in self.robot_dict:
self.robot_dict[name].line_trace = []
def setBackgroundColour(self, colour):
self.world.background_colour = wx.Brush(colour)
self.world.background_images_created = False
self.WorldDisplay.SetBackgroundColour(colour)
def inputString(self, text=''):
dlg = wx.TextEntryDialog(self.parent, text, 'Requesting a string', '')
if dlg.ShowModal() == wx.ID_OK:
user_response = dlg.GetValue()
dlg.Destroy()
return user_response
def inputInt(self, text=''):
dlg = wx.TextEntryDialog(self.parent, text, 'requesting an integer', '')
if dlg.ShowModal() == wx.ID_OK:
user_response = dlg.GetValue()
dlg.Destroy()
return int(user_response)
def my_trace(self, frame, event, arg):
if event == "line":
lineno = frame.f_lineno
if str(frame.f_code).find("<string>") != -1:
self.set_line_number(lineno)
return self.my_trace
def execute_program(self):
self.clear_trace()
if self.code=="":
rD.rurMessageDialog(_("All done!"),
_("No instruction to execute."))
return
self.parent.outputWindow.redirect()
if 'robot' in self.parent.world.robot_dict:
time_delay = [5, 1, 0.6, 0.3, 0.1, 0.06, 0.03, 0.01, 0.]
selected = self.parent.slider_speed.GetValue()
self.parent.world.robot_dict['robot'].delay = time_delay[selected]
self.isRunning = True
MyGlobals = {'move': self.move,
'turn_left': self.turn_left,
'pick_beeper': self.pick_beeper,
'put_beeper': self.put_beeper,
'set_trace_style': self.set_trace_style,
'set_delay': self.set_delay,
'RefurbishedRobot': RefurbishedRobot,
'UsedRobot' : UsedRobot,
'turn_off': self.turn_off,
'repeat': self.repeat,
'set_line_number': self.set_line_number,
'front_is_clear': self.front_is_clear,
'left_is_clear': self.left_is_clear,
'right_is_clear': self.right_is_clear,
'on_beeper': self.next_to_a_beeper, # new, as suggested
'next_to_a_beeper': self.next_to_a_beeper, # compatibility with old code
'carries_beepers': self.carries_beepers,
'facing_north': self.facing_north,
'HitWallException': rD.HitWallException,
'setBackgroundColour': self.setBackgroundColour,
'input_int': self.inputInt,
'input_string': self.inputString}
arg = self.parent.status_bar.running_field, _("Program is running")
event_manager.SendCustomEvent(self.parent, arg)
try:
try:
sys.settrace(self.my_trace)
exec self.code in MyGlobals
sys.settrace(None)
self.world.DoDrawing()
self.WorldDisplay.drawImage()
self.WorldDisplay.Refresh()
raise rD.NoTurnOffException(_("You forgot to turn me off!"))
except rD.NoTurnOffException, mesg:
rD.NoTurnOffError(mesg)
except rD.NormalEnd, mesg:
rD.NormalEndDialog(mesg)
except rD.HitWallException, mesg:
rD.DialogHitWallError(mesg)
except rD.PickBeeperException, mesg:
rD.DialogPickBeeperError(mesg)
except rD.PutBeeperException, mesg:
rD.DialogPutBeeperError(mesg)
except rD.UserStopException, mesg:
rD.UserStopError(mesg)
except Exception, info:
# There should be only two remaining possibilities...
if "invalid syntax" in info:
info = _("Error found near line %s.")%info[1][1]
rD.rurMessageDialog(info, _("Execution error"))
else:
rD.rurMessageDialog(
_("%s\nUnrecognized instruction.")%info,
_("Execution error"))
finally:
self.isRunning = False
self.isStepped = False
self.isPaused = False
end = self.parent.status_bar.running_field, _("Program not running")
event_manager.SendCustomEvent(self.parent, end)
self.parent.outputWindow.redirect('reset')
sys.settrace(None)
self.ProgramEditor.remove_highlight()
self.ProgramEditor.Refresh()
class UsedRobot(object):
def __init__(self, avenues=1, streets=1, orient_key='E',
beepers=0, name=None, colour='grey', parent=Visible_world()):
true_robot = parent.addOneRobot(avenues=avenues,
streets = streets,
orient_key=orient_key,
beepers=beepers,
name = name,
colour = colour)
self.robot = parent.robot_dict[true_robot.name]
self.name = true_robot.name
self.program = rur_program()
self.parent = parent
self.parent.object_dict[self.name] = True
self.program.wait_update_refresh(self.robot, self.name)
def __del__(self):
self.parent.object_dict[self.name] = False
def move(self):
self.program.move(self.name)
def turn_off(self):
self.program.turn_off(self.name)
def turn_left(self):
self.program.turn_left(self.name)
def put_beeper(self):
self.program.put_beeper(self.name)
def pick_beeper(self):
self.program.pick_beeper(self.name)
def set_trace_style(self, style=1, colour='sea green'):
self.program.set_trace_style(style, colour, self.name)
def set_delay(self, delay=0.3):
self.program.set_delay(delay, self.name)
def front_is_clear(self):
return self.program.front_is_clear(self.name)
def facing_north(self):
return self.program.facing_north(self.name)
def carries_beepers(self):
return self.program.carries_beepers(self.name)
def on_beeper(self): # new name
return self.program.next_to_a_beeper(self.name)
def next_to_a_beeper(self): # old name kept for compatibility...
return self.program.next_to_a_beeper(self.name)
class RefurbishedRobot(UsedRobot):
def __init__(self, avenues=1, streets=1, orient_key='E',
beepers=0, name=None, colour='grey', parent=Visible_world()):
#UsedRobot.__init__(self, avenues=avenues, orient_key = orient_key,
# beepers=beepers, name=name, colour=colour, parent=parent)
true_robot = parent.addOneRobot(avenues=avenues,
streets = streets,
orient_key=orient_key,
beepers=beepers,
name = name,
colour = colour,
better = True)
self.robot = parent.robot_dict[true_robot.name]
self.name = true_robot.name
self.program = rur_program()
self.parent = parent
self.parent.object_dict[self.name] = True
self.program.wait_update_refresh(self.robot, self.name)
def turn_right(self):
self.program.turn_right(self.name)
def facing_east(self):
return self.program.facing_east(self.name)
def facing_west(self):
return self.program.facing_west(self.name)
def facing_south(self):
return self.program.facing_south(self.name)
def roll_dice(self, n=6):
return self.program.roll_dice(n, self.name)
|