import Tkinter, math # Do not change these values MAX_WIDTH = 400 MAX_HEIGHT = 400 TURTLE_WIDTH = 4 TURTLE_HEIGHT = 4 RADIANS = 0 DEGREES = 1 CLOCKWISE = 1 COUNTERCLOCKWISE = -1 # Create window ROOT = Tkinter.Tk() CANVAS = Tkinter.Canvas(ROOT, width=MAX_WIDTH, height=MAX_HEIGHT, background='black') CANVAS.pack() def run(): ROOT.mainloop() class Turtle(object): """ Control a 'turtle' by moving forward and rotating """ def __init__(self, x=MAX_WIDTH/2, y=MAX_HEIGHT/2, angle=0, canvas=CANVAS, color='cyan'): """ Create a turtle at starting position x,y """ # create stack to store state in self.stateStack = [] # position turtle at middle of bottom side facing up self.curPos = (x, y) self.curAng = angle # Properties of the line drawn self.color = color self.thickness = 1 self.canvas = canvas self.turtle = 0 self.__showTurtle() def __del__(self): try: self.canvas.delete(self.turtle) except: pass def MoveForward(self, num): """ Move the turtle forward without drawing """ x = num * math.sin(self.curAng) y = num * math.cos(self.curAng) self.curPos = (self.curPos[0] + x, self.curPos[1]-y) self.canvas.move(self.turtle, x, -y) def DrawForward(self, num): """ Draw a line forward from current location at current angle """ # determine new position x = num * math.sin(self.curAng) y = num * math.cos(self.curAng) tmp = (self.curPos[0] + x, self.curPos[1]-y) # test if new position is out of bounds if not (0 <= tmp[0] <= MAX_WIDTH and 0 <= tmp[1] <= MAX_HEIGHT): raise BoundsError, "Position out of bounds" self.canvas.create_line(self.curPos[0], self.curPos[1], tmp[0], tmp[1], fill=self.color, width=self.thickness) self.curPos = tmp self.canvas.move(self.turtle, x, -y) def Rotate(self, num, dir=CLOCKWISE, unit=DEGREES): """ Rotate the turtle num units (either RADIANS or DEGREES) in dir (either CLOCKWISE or COUNTERCLOCKWISE) """ # if number is in degrees, convert to radians if unit == DEGREES: num = num*(math.pi/180.0) self.curAng += dir*num self.__showTurtle() def SetColor(self, color): """ Set the color of the line drawn """ self.canvas.itemconfig(self.turtle, fill=color) self.color = color def SetThickness(self, thickness): """ Set the thickness of the line drawn """ if thickness < 0: raise ValueError, "Thickness out of range" self.thickness = thickness def SaveState(self): """ Save the current state (position, angle, line properties) """ state = (self.curPos, self.curAng, self.color, self.thickness) self.stateStack.append(state) def RecoverState(self): """ Recover the last saved state (position, angle, line properties) """ state = self.stateStack.pop() self.curPos, self.curAng, self.color, self.thickness = state self.__showTurtle() def __showTurtle(self): """ Display turtle based on current position and angle """ alpha = -self.curAng beta = math.atan(float(TURTLE_WIDTH)/TURTLE_HEIGHT) gamma = beta - alpha theta = math.pi/2.0 - alpha - beta mag = (TURTLE_WIDTH**2 + TURTLE_HEIGHT**2)**0.5 x1 = self.curPos[0] - TURTLE_HEIGHT * math.sin(alpha) y1 = self.curPos[1] - TURTLE_HEIGHT * math.cos(alpha) x2 = self.curPos[0] + mag * math.cos(beta - alpha) y2 = self.curPos[1] + mag * math.sin(beta - alpha) x3 = self.curPos[0] - mag * math.sin(math.pi/2.-alpha-beta) y3 = self.curPos[1] + mag * math.cos(math.pi/2.-alpha-beta) self.canvas.delete(self.turtle) self.turtle = self.canvas.create_polygon(x1,y1,x2,y2,x3,y3, fill=self.color) class BoundsError(StandardError): pass