blob: e4cac294dfefe84306b7b6900787f4d4cdc88d01 [file] [log] [blame]
Georg Brandl33cece02008-05-20 06:58:21 +00001# LogoMation-like turtle graphics
2
3"""
4Turtle graphics is a popular way for introducing programming to
5kids. It was part of the original Logo programming language developed
6by Wally Feurzeig and Seymour Papert in 1966.
7
8Imagine a robotic turtle starting at (0, 0) in the x-y plane. Give it
9the command turtle.forward(15), and it moves (on-screen!) 15 pixels in
10the direction it is facing, drawing a line as it moves. Give it the
11command turtle.left(25), and it rotates in-place 25 degrees clockwise.
12
13By combining together these and similar commands, intricate shapes and
14pictures can easily be drawn.
15"""
16
17from math import * # Also for export
18from time import sleep
Georg Brandl6634bf22008-05-20 07:13:37 +000019import Tkinter
Georg Brandl33cece02008-05-20 06:58:21 +000020
21speeds = ['fastest', 'fast', 'normal', 'slow', 'slowest']
22
23class Error(Exception):
24 pass
25
26class RawPen:
27
28 def __init__(self, canvas):
29 self._canvas = canvas
30 self._items = []
31 self._tracing = 1
32 self._arrow = 0
33 self._delay = 10 # default delay for drawing
34 self._angle = 0.0
35 self.degrees()
36 self.reset()
37
38 def degrees(self, fullcircle=360.0):
39 """ Set angle measurement units to degrees.
40
41 Example:
42 >>> turtle.degrees()
43 """
44 # Don't try to change _angle if it is 0, because
45 # _fullcircle might not be set, yet
46 if self._angle:
47 self._angle = (self._angle / self._fullcircle) * fullcircle
48 self._fullcircle = fullcircle
49 self._invradian = pi / (fullcircle * 0.5)
50
51 def radians(self):
52 """ Set the angle measurement units to radians.
53
54 Example:
55 >>> turtle.radians()
56 """
57 self.degrees(2.0*pi)
58
59 def reset(self):
60 """ Clear the screen, re-center the pen, and set variables to
61 the default values.
62
63 Example:
64 >>> turtle.position()
65 [0.0, -22.0]
66 >>> turtle.heading()
67 100.0
68 >>> turtle.reset()
69 >>> turtle.position()
70 [0.0, 0.0]
71 >>> turtle.heading()
72 0.0
73 """
74 canvas = self._canvas
75 self._canvas.update()
76 width = canvas.winfo_width()
77 height = canvas.winfo_height()
78 if width <= 1:
79 width = canvas['width']
80 if height <= 1:
81 height = canvas['height']
82 self._origin = float(width)/2.0, float(height)/2.0
83 self._position = self._origin
84 self._angle = 0.0
85 self._drawing = 1
86 self._width = 1
87 self._color = "black"
88 self._filling = 0
89 self._path = []
90 self.clear()
91 canvas._root().tkraise()
92
93 def clear(self):
94 """ Clear the screen. The turtle does not move.
95
96 Example:
97 >>> turtle.clear()
98 """
99 self.fill(0)
100 canvas = self._canvas
101 items = self._items
102 self._items = []
103 for item in items:
104 canvas.delete(item)
105 self._delete_turtle()
106 self._draw_turtle()
107
108 def tracer(self, flag):
109 """ Set tracing on if flag is True, and off if it is False.
110 Tracing means line are drawn more slowly, with an
111 animation of an arrow along the line.
112
113 Example:
114 >>> turtle.tracer(False) # turns off Tracer
115 """
116 self._tracing = flag
117 if not self._tracing:
118 self._delete_turtle()
119 self._draw_turtle()
120
121 def forward(self, distance):
122 """ Go forward distance steps.
123
124 Example:
125 >>> turtle.position()
126 [0.0, 0.0]
127 >>> turtle.forward(25)
128 >>> turtle.position()
129 [25.0, 0.0]
130 >>> turtle.forward(-75)
131 >>> turtle.position()
132 [-50.0, 0.0]
133 """
134 x0, y0 = start = self._position
135 x1 = x0 + distance * cos(self._angle*self._invradian)
136 y1 = y0 - distance * sin(self._angle*self._invradian)
137 self._goto(x1, y1)
138
139 def backward(self, distance):
140 """ Go backwards distance steps.
141
142 The turtle's heading does not change.
143
144 Example:
145 >>> turtle.position()
146 [0.0, 0.0]
147 >>> turtle.backward(30)
148 >>> turtle.position()
149 [-30.0, 0.0]
150 """
151 self.forward(-distance)
152
153 def left(self, angle):
154 """ Turn left angle units (units are by default degrees,
155 but can be set via the degrees() and radians() functions.)
156
157 When viewed from above, the turning happens in-place around
158 its front tip.
159
160 Example:
161 >>> turtle.heading()
162 22
163 >>> turtle.left(45)
164 >>> turtle.heading()
165 67.0
166 """
167 self._angle = (self._angle + angle) % self._fullcircle
168 self._draw_turtle()
169
170 def right(self, angle):
171 """ Turn right angle units (units are by default degrees,
172 but can be set via the degrees() and radians() functions.)
173
174 When viewed from above, the turning happens in-place around
175 its front tip.
176
177 Example:
178 >>> turtle.heading()
179 22
180 >>> turtle.right(45)
181 >>> turtle.heading()
182 337.0
183 """
184 self.left(-angle)
185
186 def up(self):
187 """ Pull the pen up -- no drawing when moving.
188
189 Example:
190 >>> turtle.up()
191 """
192 self._drawing = 0
193
194 def down(self):
195 """ Put the pen down -- draw when moving.
196
197 Example:
198 >>> turtle.down()
199 """
200 self._drawing = 1
201
202 def width(self, width):
203 """ Set the line to thickness to width.
204
205 Example:
206 >>> turtle.width(10)
207 """
208 self._width = float(width)
209
210 def color(self, *args):
211 """ Set the pen color.
212
213 Three input formats are allowed:
214
215 color(s)
216 s is a Tk specification string, such as "red" or "yellow"
217
218 color((r, g, b))
219 *a tuple* of r, g, and b, which represent, an RGB color,
220 and each of r, g, and b are in the range [0..1]
221
222 color(r, g, b)
223 r, g, and b represent an RGB color, and each of r, g, and b
224 are in the range [0..1]
225
226 Example:
227
228 >>> turtle.color('brown')
229 >>> tup = (0.2, 0.8, 0.55)
230 >>> turtle.color(tup)
231 >>> turtle.color(0, .5, 0)
232 """
233 if not args:
234 raise Error, "no color arguments"
235 if len(args) == 1:
236 color = args[0]
237 if type(color) == type(""):
238 # Test the color first
239 try:
240 id = self._canvas.create_line(0, 0, 0, 0, fill=color)
Georg Brandl6634bf22008-05-20 07:13:37 +0000241 except Tkinter.TclError:
Georg Brandl33cece02008-05-20 06:58:21 +0000242 raise Error, "bad color string: %r" % (color,)
243 self._set_color(color)
244 return
245 try:
246 r, g, b = color
247 except:
248 raise Error, "bad color sequence: %r" % (color,)
249 else:
250 try:
251 r, g, b = args
252 except:
253 raise Error, "bad color arguments: %r" % (args,)
254 assert 0 <= r <= 1
255 assert 0 <= g <= 1
256 assert 0 <= b <= 1
257 x = 255.0
258 y = 0.5
259 self._set_color("#%02x%02x%02x" % (int(r*x+y), int(g*x+y), int(b*x+y)))
260
261 def _set_color(self,color):
262 self._color = color
263 self._draw_turtle()
264
265 def write(self, text, move=False):
266 """ Write text at the current pen position.
267
268 If move is true, the pen is moved to the bottom-right corner
269 of the text. By default, move is False.
270
271 Example:
272 >>> turtle.write('The race is on!')
273 >>> turtle.write('Home = (0, 0)', True)
274 """
275 x, y = self._position
276 x = x-1 # correction -- calibrated for Windows
277 item = self._canvas.create_text(x, y,
278 text=str(text), anchor="sw",
279 fill=self._color)
280 self._items.append(item)
281 if move:
282 x0, y0, x1, y1 = self._canvas.bbox(item)
283 self._goto(x1, y1)
284 self._draw_turtle()
285
286 def fill(self, flag):
287 """ Call fill(1) before drawing the shape you
288 want to fill, and fill(0) when done.
289
290 Example:
291 >>> turtle.fill(1)
292 >>> turtle.forward(100)
293 >>> turtle.left(90)
294 >>> turtle.forward(100)
295 >>> turtle.left(90)
296 >>> turtle.forward(100)
297 >>> turtle.left(90)
298 >>> turtle.forward(100)
299 >>> turtle.fill(0)
300 """
301 if self._filling:
302 path = tuple(self._path)
303 smooth = self._filling < 0
304 if len(path) > 2:
305 item = self._canvas._create('polygon', path,
306 {'fill': self._color,
307 'smooth': smooth})
308 self._items.append(item)
309 self._path = []
310 self._filling = flag
311 if flag:
312 self._path.append(self._position)
313
314 def begin_fill(self):
315 """ Called just before drawing a shape to be filled.
316 Must eventually be followed by a corresponding end_fill() call.
317 Otherwise it will be ignored.
318
319 Example:
320 >>> turtle.begin_fill()
321 >>> turtle.forward(100)
322 >>> turtle.left(90)
323 >>> turtle.forward(100)
324 >>> turtle.left(90)
325 >>> turtle.forward(100)
326 >>> turtle.left(90)
327 >>> turtle.forward(100)
328 >>> turtle.end_fill()
329 """
330 self._path = [self._position]
331 self._filling = 1
332
333 def end_fill(self):
334 """ Called after drawing a shape to be filled.
335
336 Example:
337 >>> turtle.begin_fill()
338 >>> turtle.forward(100)
339 >>> turtle.left(90)
340 >>> turtle.forward(100)
341 >>> turtle.left(90)
342 >>> turtle.forward(100)
343 >>> turtle.left(90)
344 >>> turtle.forward(100)
345 >>> turtle.end_fill()
346 """
347 self.fill(0)
348
349 def circle(self, radius, extent = None):
350 """ Draw a circle with given radius.
351 The center is radius units left of the turtle; extent
352 determines which part of the circle is drawn. If not given,
353 the entire circle is drawn.
354
355 If extent is not a full circle, one endpoint of the arc is the
356 current pen position. The arc is drawn in a counter clockwise
357 direction if radius is positive, otherwise in a clockwise
358 direction. In the process, the direction of the turtle is
359 changed by the amount of the extent.
360
361 >>> turtle.circle(50)
362 >>> turtle.circle(120, 180) # half a circle
363 """
364 if extent is None:
365 extent = self._fullcircle
366 frac = abs(extent)/self._fullcircle
367 steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac)
368 w = 1.0 * extent / steps
369 w2 = 0.5 * w
370 l = 2.0 * radius * sin(w2*self._invradian)
371 if radius < 0:
372 l, w, w2 = -l, -w, -w2
373 self.left(w2)
374 for i in range(steps):
375 self.forward(l)
376 self.left(w)
377 self.right(w2)
378
379 def heading(self):
380 """ Return the turtle's current heading.
381
382 Example:
383 >>> turtle.heading()
384 67.0
385 """
386 return self._angle
387
388 def setheading(self, angle):
389 """ Set the turtle facing the given angle.
390
391 Here are some common directions in degrees:
392
393 0 - east
394 90 - north
395 180 - west
396 270 - south
397
398 Example:
399 >>> turtle.setheading(90)
400 >>> turtle.heading()
401 90
402 >>> turtle.setheading(128)
403 >>> turtle.heading()
404 128
405 """
406 self._angle = angle
407 self._draw_turtle()
408
409 def window_width(self):
410 """ Returns the width of the turtle window.
411
412 Example:
413 >>> turtle.window_width()
414 640
415 """
416 width = self._canvas.winfo_width()
417 if width <= 1: # the window isn't managed by a geometry manager
418 width = self._canvas['width']
419 return width
420
421 def window_height(self):
422 """ Return the height of the turtle window.
423
424 Example:
425 >>> turtle.window_height()
426 768
427 """
428 height = self._canvas.winfo_height()
429 if height <= 1: # the window isn't managed by a geometry manager
430 height = self._canvas['height']
431 return height
432
433 def position(self):
434 """ Return the current (x, y) location of the turtle.
435
436 Example:
437 >>> turtle.position()
438 [0.0, 240.0]
439 """
440 x0, y0 = self._origin
441 x1, y1 = self._position
442 return [x1-x0, -y1+y0]
443
444 def setx(self, xpos):
445 """ Set the turtle's x coordinate to be xpos.
446
447 Example:
448 >>> turtle.position()
449 [10.0, 240.0]
450 >>> turtle.setx(10)
451 >>> turtle.position()
452 [10.0, 240.0]
453 """
454 x0, y0 = self._origin
455 x1, y1 = self._position
456 self._goto(x0+xpos, y1)
457
458 def sety(self, ypos):
459 """ Set the turtle's y coordinate to be ypos.
460
461 Example:
462 >>> turtle.position()
463 [0.0, 0.0]
464 >>> turtle.sety(-22)
465 >>> turtle.position()
466 [0.0, -22.0]
467 """
468 x0, y0 = self._origin
469 x1, y1 = self._position
470 self._goto(x1, y0-ypos)
471
472 def towards(self, *args):
473 """Returs the angle, which corresponds to the line
474 from turtle-position to point (x,y).
475
476 Argument can be two coordinates or one pair of coordinates
477 or a RawPen/Pen instance.
478
479 Example:
480 >>> turtle.position()
481 [10.0, 10.0]
482 >>> turtle.towards(0,0)
483 225.0
484 """
485 if len(args) == 2:
486 x, y = args
487 else:
488 arg = args[0]
489 if isinstance(arg, RawPen):
490 x, y = arg.position()
491 else:
492 x, y = arg
493 x0, y0 = self.position()
494 dx = x - x0
495 dy = y - y0
496 return (atan2(dy,dx) / self._invradian) % self._fullcircle
497
498 def goto(self, *args):
499 """ Go to the given point.
500
501 If the pen is down, then a line will be drawn. The turtle's
502 orientation does not change.
503
504 Two input formats are accepted:
505
506 goto(x, y)
507 go to point (x, y)
508
509 goto((x, y))
510 go to point (x, y)
511
512 Example:
513 >>> turtle.position()
514 [0.0, 0.0]
515 >>> turtle.goto(50, -45)
516 >>> turtle.position()
517 [50.0, -45.0]
518 """
519 if len(args) == 1:
520 try:
521 x, y = args[0]
522 except:
523 raise Error, "bad point argument: %r" % (args[0],)
524 else:
525 try:
526 x, y = args
527 except:
528 raise Error, "bad coordinates: %r" % (args[0],)
529 x0, y0 = self._origin
530 self._goto(x0+x, y0-y)
531
532 def _goto(self, x1, y1):
533 x0, y0 = self._position
534 self._position = map(float, (x1, y1))
535 if self._filling:
536 self._path.append(self._position)
537 if self._drawing:
538 if self._tracing:
539 dx = float(x1 - x0)
540 dy = float(y1 - y0)
541 distance = hypot(dx, dy)
542 nhops = int(distance)
543 item = self._canvas.create_line(x0, y0, x0, y0,
544 width=self._width,
545 capstyle="round",
546 fill=self._color)
547 try:
548 for i in range(1, 1+nhops):
549 x, y = x0 + dx*i/nhops, y0 + dy*i/nhops
550 self._canvas.coords(item, x0, y0, x, y)
551 self._draw_turtle((x,y))
552 self._canvas.update()
553 self._canvas.after(self._delay)
554 # in case nhops==0
555 self._canvas.coords(item, x0, y0, x1, y1)
556 self._canvas.itemconfigure(item, arrow="none")
Georg Brandl6634bf22008-05-20 07:13:37 +0000557 except Tkinter.TclError:
Georg Brandl33cece02008-05-20 06:58:21 +0000558 # Probably the window was closed!
559 return
560 else:
561 item = self._canvas.create_line(x0, y0, x1, y1,
562 width=self._width,
563 capstyle="round",
564 fill=self._color)
565 self._items.append(item)
566 self._draw_turtle()
567
568 def speed(self, speed):
569 """ Set the turtle's speed.
570
571 speed must one of these five strings:
572
573 'fastest' is a 0 ms delay
574 'fast' is a 5 ms delay
575 'normal' is a 10 ms delay
576 'slow' is a 15 ms delay
577 'slowest' is a 20 ms delay
578
579 Example:
580 >>> turtle.speed('slow')
581 """
582 try:
583 speed = speed.strip().lower()
584 self._delay = speeds.index(speed) * 5
585 except:
586 raise ValueError("%r is not a valid speed. speed must be "
587 "one of %s" % (speed, speeds))
588
589
590 def delay(self, delay):
591 """ Set the drawing delay in milliseconds.
592
593 This is intended to allow finer control of the drawing speed
594 than the speed() method
595
596 Example:
597 >>> turtle.delay(15)
598 """
599 if int(delay) < 0:
600 raise ValueError("delay must be greater than or equal to 0")
601 self._delay = int(delay)
602
603 def _draw_turtle(self, position=[]):
604 if not self._tracing:
605 self._canvas.update()
606 return
607 if position == []:
608 position = self._position
609 x,y = position
610 distance = 8
611 dx = distance * cos(self._angle*self._invradian)
612 dy = distance * sin(self._angle*self._invradian)
613 self._delete_turtle()
614 self._arrow = self._canvas.create_line(x-dx,y+dy,x,y,
615 width=self._width,
616 arrow="last",
617 capstyle="round",
618 fill=self._color)
619 self._canvas.update()
620
621 def _delete_turtle(self):
622 if self._arrow != 0:
623 self._canvas.delete(self._arrow)
624 self._arrow = 0
625
626
627_root = None
628_canvas = None
629_pen = None
630_width = 0.50 # 50% of window width
631_height = 0.75 # 75% of window height
632_startx = None
633_starty = None
634_title = "Turtle Graphics" # default title
635
636class Pen(RawPen):
637
638 def __init__(self):
639 global _root, _canvas
640 if _root is None:
Georg Brandl6634bf22008-05-20 07:13:37 +0000641 _root = Tkinter.Tk()
Georg Brandl33cece02008-05-20 06:58:21 +0000642 _root.wm_protocol("WM_DELETE_WINDOW", self._destroy)
643 _root.title(_title)
644
645 if _canvas is None:
646 # XXX Should have scroll bars
Georg Brandl6634bf22008-05-20 07:13:37 +0000647 _canvas = Tkinter.Canvas(_root, background="white")
Georg Brandl33cece02008-05-20 06:58:21 +0000648 _canvas.pack(expand=1, fill="both")
649
650 setup(width=_width, height= _height, startx=_startx, starty=_starty)
651
652 RawPen.__init__(self, _canvas)
653
654 def _destroy(self):
655 global _root, _canvas, _pen
656 root = self._canvas._root()
657 if root is _root:
658 _pen = None
659 _root = None
660 _canvas = None
661 root.destroy()
662
663def _getpen():
664 global _pen
665 if not _pen:
666 _pen = Pen()
667 return _pen
668
669class Turtle(Pen):
670 pass
671
672"""For documentation of the following functions see
673 the RawPen methods with the same names
674"""
675
676def degrees(): _getpen().degrees()
677def radians(): _getpen().radians()
678def reset(): _getpen().reset()
679def clear(): _getpen().clear()
680def tracer(flag): _getpen().tracer(flag)
681def forward(distance): _getpen().forward(distance)
682def backward(distance): _getpen().backward(distance)
683def left(angle): _getpen().left(angle)
684def right(angle): _getpen().right(angle)
685def up(): _getpen().up()
686def down(): _getpen().down()
687def width(width): _getpen().width(width)
688def color(*args): _getpen().color(*args)
689def write(arg, move=0): _getpen().write(arg, move)
690def fill(flag): _getpen().fill(flag)
691def begin_fill(): _getpen().begin_fill()
692def end_fill(): _getpen().end_fill()
693def circle(radius, extent=None): _getpen().circle(radius, extent)
694def goto(*args): _getpen().goto(*args)
695def heading(): return _getpen().heading()
696def setheading(angle): _getpen().setheading(angle)
697def position(): return _getpen().position()
698def window_width(): return _getpen().window_width()
699def window_height(): return _getpen().window_height()
700def setx(xpos): _getpen().setx(xpos)
701def sety(ypos): _getpen().sety(ypos)
702def towards(*args): return _getpen().towards(*args)
703
704def done(): _root.mainloop()
705def delay(delay): return _getpen().delay(delay)
706def speed(speed): return _getpen().speed(speed)
707
708for methodname in dir(RawPen):
709 """ copies RawPen docstrings to module functions of same name """
710 if not methodname.startswith("_"):
711 eval(methodname).__doc__ = RawPen.__dict__[methodname].__doc__
712
713
714def setup(**geometry):
715 """ Sets the size and position of the main window.
716
717 Keywords are width, height, startx and starty:
718
719 width: either a size in pixels or a fraction of the screen.
720 Default is 50% of screen.
721 height: either the height in pixels or a fraction of the screen.
722 Default is 75% of screen.
723
724 Setting either width or height to None before drawing will force
725 use of default geometry as in older versions of turtle.py
726
727 startx: starting position in pixels from the left edge of the screen.
728 Default is to center window. Setting startx to None is the default
729 and centers window horizontally on screen.
730
731 starty: starting position in pixels from the top edge of the screen.
732 Default is to center window. Setting starty to None is the default
733 and centers window vertically on screen.
734
735 Examples:
736 >>> setup (width=200, height=200, startx=0, starty=0)
737
738 sets window to 200x200 pixels, in upper left of screen
739
740 >>> setup(width=.75, height=0.5, startx=None, starty=None)
741
742 sets window to 75% of screen by 50% of screen and centers
743
744 >>> setup(width=None)
745
746 forces use of default geometry as in older versions of turtle.py
747 """
748
749 global _width, _height, _startx, _starty
750
751 width = geometry.get('width',_width)
752 if width >= 0 or width is None:
753 _width = width
754 else:
755 raise ValueError, "width can not be less than 0"
756
757 height = geometry.get('height',_height)
758 if height >= 0 or height is None:
759 _height = height
760 else:
761 raise ValueError, "height can not be less than 0"
762
763 startx = geometry.get('startx', _startx)
764 if startx >= 0 or startx is None:
765 _startx = _startx
766 else:
767 raise ValueError, "startx can not be less than 0"
768
769 starty = geometry.get('starty', _starty)
770 if starty >= 0 or starty is None:
771 _starty = starty
772 else:
773 raise ValueError, "startx can not be less than 0"
774
775
776 if _root and _width and _height:
777 if 0 < _width <= 1:
778 _width = _root.winfo_screenwidth() * +width
779 if 0 < _height <= 1:
780 _height = _root.winfo_screenheight() * _height
781
782 # center window on screen
783 if _startx is None:
784 _startx = (_root.winfo_screenwidth() - _width) / 2
785
786 if _starty is None:
787 _starty = (_root.winfo_screenheight() - _height) / 2
788
789 _root.geometry("%dx%d+%d+%d" % (_width, _height, _startx, _starty))
790
791def title(title):
792 """Set the window title.
793
794 By default this is set to 'Turtle Graphics'
795
796 Example:
797 >>> title("My Window")
798 """
799
800 global _title
801 _title = title
802
803def demo():
804 reset()
805 tracer(1)
806 up()
807 backward(100)
808 down()
809 # draw 3 squares; the last filled
810 width(3)
811 for i in range(3):
812 if i == 2:
813 fill(1)
814 for j in range(4):
815 forward(20)
816 left(90)
817 if i == 2:
818 color("maroon")
819 fill(0)
820 up()
821 forward(30)
822 down()
823 width(1)
824 color("black")
825 # move out of the way
826 tracer(0)
827 up()
828 right(90)
829 forward(100)
830 right(90)
831 forward(100)
832 right(180)
833 down()
834 # some text
835 write("startstart", 1)
836 write("start", 1)
837 color("red")
838 # staircase
839 for i in range(5):
840 forward(20)
841 left(90)
842 forward(20)
843 right(90)
844 # filled staircase
845 fill(1)
846 for i in range(5):
847 forward(20)
848 left(90)
849 forward(20)
850 right(90)
851 fill(0)
852 tracer(1)
853 # more text
854 write("end")
855
856def demo2():
857 # exercises some new and improved features
858 speed('fast')
859 width(3)
860
861 # draw a segmented half-circle
862 setheading(towards(0,0))
863 x,y = position()
864 r = (x**2+y**2)**.5/2.0
865 right(90)
866 pendown = True
867 for i in range(18):
868 if pendown:
869 up()
870 pendown = False
871 else:
872 down()
873 pendown = True
874 circle(r,10)
875 sleep(2)
876
877 reset()
878 left(90)
879
880 # draw a series of triangles
881 l = 10
882 color("green")
883 width(3)
884 left(180)
885 sp = 5
886 for i in range(-2,16):
887 if i > 0:
888 color(1.0-0.05*i,0,0.05*i)
889 fill(1)
890 color("green")
891 for j in range(3):
892 forward(l)
893 left(120)
894 l += 10
895 left(15)
896 if sp > 0:
897 sp = sp-1
898 speed(speeds[sp])
899 color(0.25,0,0.75)
900 fill(0)
901
902 # draw and fill a concave shape
903 left(120)
904 up()
905 forward(70)
906 right(30)
907 down()
908 color("red")
909 speed("fastest")
910 fill(1)
911 for i in range(4):
912 circle(50,90)
913 right(90)
914 forward(30)
915 right(90)
916 color("yellow")
917 fill(0)
918 left(90)
919 up()
920 forward(30)
921 down();
922
923 color("red")
924
925 # create a second turtle and make the original pursue and catch it
926 turtle=Turtle()
927 turtle.reset()
928 turtle.left(90)
929 turtle.speed('normal')
930 turtle.up()
931 turtle.goto(280,40)
932 turtle.left(24)
933 turtle.down()
934 turtle.speed('fast')
935 turtle.color("blue")
936 turtle.width(2)
937 speed('fastest')
938
939 # turn default turtle towards new turtle object
940 setheading(towards(turtle))
941 while ( abs(position()[0]-turtle.position()[0])>4 or
942 abs(position()[1]-turtle.position()[1])>4):
943 turtle.forward(3.5)
944 turtle.left(0.6)
945 # turn default turtle towards new turtle object
946 setheading(towards(turtle))
947 forward(4)
948 write("CAUGHT! ", move=True)
949
950
951
952if __name__ == '__main__':
953 demo()
954 sleep(3)
955 demo2()
956 done()