All pastes #382846 Raw Edit

I am turtle

public python v1 · immutable
·published 2007-03-05 23:12 UTC
rendered paste body
# LogoMation-like turtle graphics"""Turtle graphics is a popular way for introducing programming tokids. It was part of the original Logo programming language developedby Wally Feurzeig and Seymour Papert in 1966.Imagine a robotic turtle starting at (0, 0) in the x-y plane. Give itthe command turtle.forward(15), and it moves (on-screen!) 15 pixels inthe direction it is facing, drawing a line as it moves. Give it thecommand turtle.left(25), and it rotates in-place 25 degrees clockwise.By combining together these and similar commands, intricate shapes andpictures can easily be drawn."""from math import * # Also for exportimport Tkinterspeeds = ['fastest', 'fast', 'normal', 'slow', 'slowest']class Error(Exception):    passclass RawPen:    def __init__(self, canvas):        self._canvas = canvas        self._items = []        self._tracing = 1        self._arrow = 0        self._delay = 10     # default delay for drawing        self._angle = 0.0        self.degrees()        self.reset()    def degrees(self, fullcircle=360.0):        """ Set angle measurement units to degrees.        Example:        >>> turtle.degrees()        """        # Don't try to change _angle if it is 0, because        # _fullcircle might not be set, yet        if self._angle:            self._angle = (self._angle / self._fullcircle) * fullcircle        self._fullcircle = fullcircle        self._invradian = pi / (fullcircle * 0.5)    def radians(self):        """ Set the angle measurement units to radians.        Example:        >>> turtle.radians()        """        self.degrees(2.0*pi)    def reset(self):        """ Clear the screen, re-center the pen, and set variables to        the default values.        Example:        >>> turtle.position()        [0.0, -22.0]        >>> turtle.heading()        100.0        >>> turtle.reset()        >>> turtle.position()        [0.0, 0.0]        >>> turtle.heading()        0.0        """        canvas = self._canvas        self._canvas.update()        width = canvas.winfo_width()        height = canvas.winfo_height()        if width <= 1:            width = canvas['width']        if height <= 1:            height = canvas['height']        self._origin = float(width)/2.0, float(height)/2.0        self._position = self._origin        self._angle = 0.0        self._drawing = 1        self._width = 1        self._color = "black"        self._filling = 0        self._path = []        self.clear()        canvas._root().tkraise()    def clear(self):        """ Clear the screen. The turtle does not move.        Example:        >>> turtle.clear()        """        self.fill(0)        canvas = self._canvas        items = self._items        self._items = []        for item in items:            canvas.delete(item)        self._delete_turtle()        self._draw_turtle()    def tracer(self, flag):        """ Set tracing on if flag is True, and off if it is False.        Tracing means line are drawn more slowly, with an        animation of an arrow along the line.        Example:        >>> turtle.tracer(False)   # turns off Tracer        """        self._tracing = flag        if not self._tracing:            self._delete_turtle()        self._draw_turtle()    def forward(self, distance):        """ Go forward distance steps.        Example:        >>> turtle.position()        [0.0, 0.0]        >>> turtle.forward(25)        >>> turtle.position()        [25.0, 0.0]        >>> turtle.forward(-75)        >>> turtle.position()        [-50.0, 0.0]        """        x0, y0 = start = self._position        x1 = x0 + distance * cos(self._angle*self._invradian)        y1 = y0 - distance * sin(self._angle*self._invradian)        self._goto(x1, y1)    def backward(self, distance):        """ Go backwards distance steps.        The turtle's heading does not change.        Example:        >>> turtle.position()        [0.0, 0.0]        >>> turtle.backward(30)        >>> turtle.position()        [-30.0, 0.0]        """        self.forward(-distance)    def left(self, angle):        """ Turn left angle units (units are by default degrees,        but can be set via the degrees() and radians() functions.)        When viewed from above, the turning happens in-place around        its front tip.        Example:        >>> turtle.heading()        22        >>> turtle.left(45)        >>> turtle.heading()        67.0        """        self._angle = (self._angle + angle) % self._fullcircle        self._draw_turtle()    def right(self, angle):        """ Turn right angle units (units are by default degrees,        but can be set via the degrees() and radians() functions.)        When viewed from above, the turning happens in-place around        its front tip.        Example:        >>> turtle.heading()        22        >>> turtle.right(45)        >>> turtle.heading()        337.0        """        self.left(-angle)    def up(self):        """ Pull the pen up -- no drawing when moving.        Example:        >>> turtle.up()        """        self._drawing = 0    def down(self):        """ Put the pen down -- draw when moving.        Example:        >>> turtle.down()        """        self._drawing = 1    def width(self, width):        """ Set the line to thickness to width.        Example:        >>> turtle.width(10)        """        self._width = float(width)    def color(self, *args):        """ Set the pen color.        Three input formats are allowed:            color(s)            s is a Tk specification string, such as "red" or "yellow"            color((r, g, b))            *a tuple* of r, g, and b, which represent, an RGB color,            and each of r, g, and b are in the range [0..1]            color(r, g, b)            r, g, and b represent an RGB color, and each of r, g, and b            are in the range [0..1]        Example:        >>> turtle.color('brown')        >>> tup = (0.2, 0.8, 0.55)        >>> turtle.color(tup)        >>> turtle.color(0, .5, 0)        """        if not args:            raise Error, "no color arguments"        if len(args) == 1:            color = args[0]            if type(color) == type(""):                # Test the color first                try:                    id = self._canvas.create_line(0, 0, 0, 0, fill=color)                except Tkinter.TclError:                    raise Error, "bad color string: %r" % (color,)                self._set_color(color)                return            try:                r, g, b = color            except:                raise Error, "bad color sequence: %r" % (color,)        else:            try:                r, g, b = args            except:                raise Error, "bad color arguments: %r" % (args,)        assert 0 <= r <= 1        assert 0 <= g <= 1        assert 0 <= b <= 1        x = 255.0        y = 0.5        self._set_color("#%02x%02x%02x" % (int(r*x+y), int(g*x+y), int(b*x+y)))    def _set_color(self,color):        self._color = color        self._draw_turtle()    def write(self, text, move=False):        """ Write text at the current pen position.        If move is true, the pen is moved to the bottom-right corner        of the text. By default, move is False.        Example:        >>> turtle.write('The race is on!')        >>> turtle.write('Home = (0, 0)', True)        """        x, y  = self._position        x = x-1 # correction -- calibrated for Windows        item = self._canvas.create_text(x, y,                                        text=str(text), anchor="sw",                                        fill=self._color)        self._items.append(item)        if move:            x0, y0, x1, y1 = self._canvas.bbox(item)            self._goto(x1, y1)        self._draw_turtle()    def fill(self, flag):        """ Call fill(1) before drawing the shape you         want to fill, and fill(0) when done.        Example:        >>> turtle.fill(1)        >>> turtle.forward(100)        >>> turtle.left(90)        >>> turtle.forward(100)        >>> turtle.left(90)        >>> turtle.forward(100)        >>> turtle.left(90)        >>> turtle.forward(100)        >>> turtle.fill(0)        """        if self._filling:            path = tuple(self._path)            smooth = self._filling < 0            if len(path) > 2:                item = self._canvas._create('polygon', path,                                            {'fill': self._color,                                             'smooth': smooth})                self._items.append(item)        self._path = []        self._filling = flag        if flag:            self._path.append(self._position)    def begin_fill(self):        """ Called just before drawing a shape to be filled.            Must eventually be followed by a corresponding end_fill() call.            Otherwise it will be ignored.        Example:        >>> turtle.begin_fill()        >>> turtle.forward(100)        >>> turtle.left(90)        >>> turtle.forward(100)        >>> turtle.left(90)        >>> turtle.forward(100)        >>> turtle.left(90)        >>> turtle.forward(100)        >>> turtle.end_fill()        """        self._path = [self._position]        self._filling = 1    def end_fill(self):        """ Called after drawing a shape to be filled.        Example:        >>> turtle.begin_fill()        >>> turtle.forward(100)        >>> turtle.left(90)        >>> turtle.forward(100)        >>> turtle.left(90)        >>> turtle.forward(100)        >>> turtle.left(90)        >>> turtle.forward(100)        >>> turtle.end_fill()        """        self.fill(0)    def circle(self, radius, extent = None):        """ Draw a circle with given radius.        The center is radius units left of the turtle; extent        determines which part of the circle is drawn. If not given,        the entire circle is drawn.        If extent is not a full circle, one endpoint of the arc is the        current pen position. The arc is drawn in a counter clockwise        direction if radius is positive, otherwise in a clockwise        direction. In the process, the direction of the turtle is        changed by the amount of the extent.        >>> turtle.circle(50)        >>> turtle.circle(120, 180)  # half a circle        """        if extent is None:            extent = self._fullcircle        frac = abs(extent)/self._fullcircle        steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac)        w = 1.0 * extent / steps        w2 = 0.5 * w        l = 2.0 * radius * sin(w2*self._invradian)        if radius < 0:            l, w, w2 = -l, -w, -w2        self.left(w2)        for i in range(steps):            self.forward(l)            self.left(w)        self.right(w2)    def heading(self):        """ Return the turtle's current heading.        Example:        >>> turtle.heading()        67.0        """        return self._angle    def setheading(self, angle):        """ Set the turtle facing the given angle.        Here are some common directions in degrees:           0 - east          90 - north         180 - west         270 - south        Example:        >>> turtle.setheading(90)        >>> turtle.heading()        90        >>> turtle.setheading(128)        >>> turtle.heading()        128        """        self._angle = angle        self._draw_turtle()    def window_width(self):        """ Returns the width of the turtle window.        Example:        >>> turtle.window_width()        640        """        width = self._canvas.winfo_width()        if width <= 1:  # the window isn't managed by a geometry manager            width = self._canvas['width']        return width    def window_height(self):        """ Return the height of the turtle window.        Example:        >>> turtle.window_height()        768        """        height = self._canvas.winfo_height()        if height <= 1: # the window isn't managed by a geometry manager            height = self._canvas['height']        return height    def position(self):        """ Return the current (x, y) location of the turtle.        Example:        >>> turtle.position()        [0.0, 240.0]        """        x0, y0 = self._origin        x1, y1 = self._position        return [x1-x0, -y1+y0]    def setx(self, xpos):        """ Set the turtle's x coordinate to be xpos.        Example:        >>> turtle.position()        [10.0, 240.0]        >>> turtle.setx(10)        >>> turtle.position()        [10.0, 240.0]        """        x0, y0 = self._origin        x1, y1 = self._position        self._goto(x0+xpos, y1)    def sety(self, ypos):        """ Set the turtle's y coordinate to be ypos.        Example:        >>> turtle.position()        [0.0, 0.0]        >>> turtle.sety(-22)        >>> turtle.position()        [0.0, -22.0]        """        x0, y0 = self._origin        x1, y1 = self._position        self._goto(x1, y0-ypos)    def towards(self, *args):        """Returs the angle, which corresponds to the line        from turtle-position to point (x,y).        Argument can be two coordinates or one pair of coordinates        or a RawPen/Pen instance.        Example:        >>> turtle.position()        [10.0, 10.0]        >>> turtle.towards(0,0)        225.0        """        if len(args) == 2:            x, y = args        else:            arg = args[0]            if isinstance(arg, RawPen):                x, y = arg.position()            else:                x, y = arg        x0, y0 = self.position()        dx = x - x0        dy = y - y0        return (atan2(dy,dx) / self._invradian) % self._fullcircle    def goto(self, *args):        """ Go to the given point.        If the pen is down, then a line will be drawn. The turtle's        orientation does not change.        Two input formats are accepted:           goto(x, y)           go to point (x, y)           goto((x, y))           go to point (x, y)        Example:        >>> turtle.position()        [0.0, 0.0]        >>> turtle.goto(50, -45)        >>> turtle.position()        [50.0, -45.0]        """        if len(args) == 1:            try:                x, y = args[0]            except:                raise Error, "bad point argument: %r" % (args[0],)        else:            try:                x, y = args            except:                raise Error, "bad coordinates: %r" % (args[0],)        x0, y0 = self._origin        self._goto(x0+x, y0-y)    def _goto(self, x1, y1):        x0, y0 = self._position        self._position = map(float, (x1, y1))        if self._filling:            self._path.append(self._position)        if self._drawing:            if self._tracing:                dx = float(x1 - x0)                dy = float(y1 - y0)                distance = hypot(dx, dy)                nhops = int(distance)                item = self._canvas.create_line(x0, y0, x0, y0,                                                width=self._width,                                                capstyle="round",                                                fill=self._color)                try:                    for i in range(1, 1+nhops):                        x, y = x0 + dx*i/nhops, y0 + dy*i/nhops                        self._canvas.coords(item, x0, y0, x, y)                        self._draw_turtle((x,y))                        self._canvas.update()                        self._canvas.after(self._delay)                    # in case nhops==0                    self._canvas.coords(item, x0, y0, x1, y1)                    self._canvas.itemconfigure(item, arrow="none")                except Tkinter.TclError:                    # Probably the window was closed!                    return            else:                item = self._canvas.create_line(x0, y0, x1, y1,                                                width=self._width,                                                capstyle="round",                                                fill=self._color)            self._items.append(item)        self._draw_turtle()    def speed(self, speed):        """ Set the turtle's speed.        speed must one of these five strings:            'fastest' is a 0 ms delay            'fast' is a 5 ms delay            'normal' is a 10 ms delay            'slow' is a 15 ms delay            'slowest' is a 20 ms delay         Example:         >>> turtle.speed('slow')        """        try:            speed = speed.strip().lower()            self._delay = speeds.index(speed) * 5        except:            raise ValueError("%r is not a valid speed. speed must be "                             "one of %s" % (speed, speeds))    def delay(self, delay):        """ Set the drawing delay in milliseconds.        This is intended to allow finer control of the drawing speed        than the speed() method        Example:        >>> turtle.delay(15)        """        if int(delay) < 0:            raise ValueError("delay must be greater than or equal to 0")        self._delay = int(delay)    def _draw_turtle(self, position=[]):        if not self._tracing:            self._canvas.update()            return        if position == []:            position = self._position        x,y = position        distance = 8        dx = distance * cos(self._angle*self._invradian)        dy = distance * sin(self._angle*self._invradian)        self._delete_turtle()        self._arrow = self._canvas.create_line(x-dx,y+dy,x,y,                                          width=self._width,                                          arrow="last",                                          capstyle="round",                                          fill=self._color)        self._canvas.update()    def _delete_turtle(self):        if self._arrow != 0:            self._canvas.delete(self._arrow)            self._arrow = 0_root = None_canvas = None_pen = None_width = 0.50                  # 50% of window width_height = 0.75                 # 75% of window height_startx = None_starty = None_title = "Turtle Graphics"     # default titleclass Pen(RawPen):    def __init__(self):        global _root, _canvas        if _root is None:            _root = Tkinter.Tk()            _root.wm_protocol("WM_DELETE_WINDOW", self._destroy)            _root.title(_title)        if _canvas is None:            # XXX Should have scroll bars            _canvas = Tkinter.Canvas(_root, background="white")            _canvas.pack(expand=1, fill="both")            setup(width=_width, height= _height, startx=_startx, starty=_starty)        RawPen.__init__(self, _canvas)    def _destroy(self):        global _root, _canvas, _pen        root = self._canvas._root()        if root is _root:            _pen = None            _root = None            _canvas = None        root.destroy()def _getpen():    global _pen    if not _pen:        _pen = Pen()    return _penclass Turtle(Pen):    pass"""For documentation of the following functions see   the RawPen methods with the same names"""def degrees(): _getpen().degrees()def radians(): _getpen().radians()def reset(): _getpen().reset()def clear(): _getpen().clear()def tracer(flag): _getpen().tracer(flag)def forward(distance): _getpen().forward(distance)def backward(distance): _getpen().backward(distance)def left(angle): _getpen().left(angle)def right(angle): _getpen().right(angle)def up(): _getpen().up()def down(): _getpen().down()def width(width): _getpen().width(width)def color(*args): _getpen().color(*args)def write(arg, move=0): _getpen().write(arg, move)def fill(flag): _getpen().fill(flag)def begin_fill(): _getpen().begin_fill()def end_fill(): _getpen().end_fill()def circle(radius, extent=None): _getpen().circle(radius, extent)def goto(*args): _getpen().goto(*args)def heading(): return _getpen().heading()def setheading(angle): _getpen().setheading(angle)def position(): return _getpen().position()def window_width(): return _getpen().window_width()def window_height(): return _getpen().window_height()def setx(xpos): _getpen().setx(xpos)def sety(ypos): _getpen().sety(ypos)def towards(*args): return _getpen().towards(*args)def done(): _root.mainloop()def delay(delay): return _getpen().delay(delay)def speed(speed): return _getpen().speed(speed)for methodname in dir(RawPen):    """ copies RawPen docstrings to module functions of same name """    if not methodname.startswith("_"):        eval(methodname).__doc__ = RawPen.__dict__[methodname].__doc__def setup(**geometry):    """ Sets the size and position of the main window.    Keywords are width, height, startx and starty:    width: either a size in pixels or a fraction of the screen.      Default is 50% of screen.    height: either the height in pixels or a fraction of the screen.      Default is 75% of screen.    Setting either width or height to None before drawing will force      use of default geometry as in older versions of turtle.py    startx: starting position in pixels from the left edge of the screen.      Default is to center window. Setting startx to None is the default      and centers window horizontally on screen.    starty: starting position in pixels from the top edge of the screen.      Default is to center window. Setting starty to None is the default      and centers window vertically on screen.    Examples:    >>> setup (width=200, height=200, startx=0, starty=0)    sets window to 200x200 pixels, in upper left of screen    >>> setup(width=.75, height=0.5, startx=None, starty=None)    sets window to 75% of screen by 50% of screen and centers    >>> setup(width=None)    forces use of default geometry as in older versions of turtle.py    """    global _width, _height, _startx, _starty    width = geometry.get('width',_width)    if width >= 0 or width == None:        _width = width    else:        raise ValueError, "width can not be less than 0"    height = geometry.get('height',_height)    if height >= 0 or height == None:        _height = height    else:        raise ValueError, "height can not be less than 0"    startx = geometry.get('startx', _startx)    if startx >= 0 or startx == None:        _startx = _startx    else:        raise ValueError, "startx can not be less than 0"    starty = geometry.get('starty', _starty)    if starty >= 0 or starty == None:        _starty = starty    else:        raise ValueError, "startx can not be less than 0"    if _root and _width and _height:        if 0 < _width <= 1:            _width = _root.winfo_screenwidth() * +width        if 0 < _height <= 1:            _height = _root.winfo_screenheight() * _height        # center window on screen        if _startx is None:            _startx = (_root.winfo_screenwidth() - _width) / 2        if _starty is None:            _starty = (_root.winfo_screenheight() - _height) / 2        _root.geometry("%dx%d+%d+%d" % (_width, _height, _startx, _starty))def title(title):    """Set the window title.    By default this is set to 'Turtle Graphics'    Example:    >>> title("My Window")    """    global _title    _title = titledef demo():    reset()    tracer(1)    up()    backward(100)    down()    # draw 3 squares; the last filled    width(3)    for i in range(3):        if i == 2:            fill(1)        for j in range(4):            forward(20)            left(90)        if i == 2:            color("maroon")            fill(0)        up()        forward(30)        down()    width(1)    color("black")    # move out of the way    tracer(0)    up()    right(90)    forward(100)    right(90)    forward(100)    right(180)    down()    # some text    write("startstart", 1)    write("start", 1)    color("red")    # staircase    for i in range(5):        forward(20)        left(90)        forward(20)        right(90)    # filled staircase    fill(1)    for i in range(5):        forward(20)        left(90)        forward(20)        right(90)    fill(0)    tracer(1)    # more text    write("end")def demo2():    # exercises some new and improved features    speed('fast')    width(3)    # draw a segmented half-circle    setheading(towards(0,0))    x,y = position()    r = (x**2+y**2)**.5/2.0    right(90)    pendown = True    for i in range(18):        if pendown:            up()            pendown = False        else:            down()            pendown = True        circle(r,10)    sleep(2)    reset()    left(90)    # draw a series of triangles    l = 10    color("green")    width(3)    left(180)    sp = 5    for i in range(-2,16):        if i > 0:            color(1.0-0.05*i,0,0.05*i)            fill(1)            color("green")        for j in range(3):            forward(l)            left(120)        l += 10        left(15)        if sp > 0:            sp = sp-1            speed(speeds[sp])    color(0.25,0,0.75)    fill(0)    # draw and fill a concave shape    left(120)    up()    forward(70)    right(30)    down()    color("red")    speed("fastest")    fill(1)    for i in range(4):        circle(50,90)        right(90)        forward(30)        right(90)    color("yellow")    fill(0)    left(90)    up()    forward(30)    down();    color("red")    # create a second turtle and make the original pursue and catch it    turtle=Turtle()    turtle.reset()    turtle.left(90)    turtle.speed('normal')    turtle.up()    turtle.goto(280,40)    turtle.left(24)    turtle.down()    turtle.speed('fast')    turtle.color("blue")    turtle.width(2)    speed('fastest')    # turn default turtle towards new turtle object    setheading(towards(turtle))    while ( abs(position()[0]-turtle.position()[0])>4 or            abs(position()[1]-turtle.position()[1])>4):        turtle.forward(3.5)        turtle.left(0.6)        # turn default turtle towards new turtle object        setheading(towards(turtle))        forward(4)    write("CAUGHT! ", move=True)if __name__ == '__main__':    from time import sleep    demo()    sleep(3)    demo2()    done()