blob: d68e405cd6fc7cbdefe1bd068ed0c391fe2e825b [file] [log] [blame]
Guido van Rossumb241b671998-12-04 16:42:46 +00001# LogoMation-like turtle graphics
2
Georg Brandle3a25832006-05-17 14:56:04 +00003"""
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
Guido van Rossumb241b671998-12-04 16:42:46 +000017from math import * # Also for export
18import Tkinter
Guido van Rossumfd2ede22002-09-23 16:55:05 +000019
Georg Brandle3a25832006-05-17 14:56:04 +000020speeds = ['fastest', 'fast', 'normal', 'slow', 'slowest']
21
Martin v. Löwis4b6ea792000-10-01 17:52:01 +000022class Error(Exception):
23 pass
Guido van Rossumb241b671998-12-04 16:42:46 +000024
25class RawPen:
26
27 def __init__(self, canvas):
28 self._canvas = canvas
29 self._items = []
30 self._tracing = 1
Guido van Rossum3c7a25a2001-08-09 16:42:07 +000031 self._arrow = 0
Georg Brandle3a25832006-05-17 14:56:04 +000032 self._delay = 10 # default delay for drawing
Guido van Rossumb241b671998-12-04 16:42:46 +000033 self.degrees()
34 self.reset()
35
36 def degrees(self, fullcircle=360.0):
Georg Brandle3a25832006-05-17 14:56:04 +000037 """ Set angle measurement units to degrees.
38
39 Example:
40 >>> turtle.degrees()
41 """
Guido van Rossumb241b671998-12-04 16:42:46 +000042 self._fullcircle = fullcircle
43 self._invradian = pi / (fullcircle * 0.5)
44
45 def radians(self):
Georg Brandle3a25832006-05-17 14:56:04 +000046 """ Set the angle measurement units to radians.
47
48 Example:
49 >>> turtle.radians()
50 """
Guido van Rossumb241b671998-12-04 16:42:46 +000051 self.degrees(2.0*pi)
52
53 def reset(self):
Georg Brandle3a25832006-05-17 14:56:04 +000054 """ Clear the screen, re-center the pen, and set variables to
55 the default values.
56
57 Example:
58 >>> turtle.position()
59 [0.0, -22.0]
60 >>> turtle.heading()
61 100.0
62 >>> turtle.reset()
63 >>> turtle.position()
64 [0.0, 0.0]
65 >>> turtle.heading()
66 0.0
67 """
Guido van Rossumb241b671998-12-04 16:42:46 +000068 canvas = self._canvas
Martin v. Löwis73b9b662002-09-22 13:00:26 +000069 self._canvas.update()
Guido van Rossumb241b671998-12-04 16:42:46 +000070 width = canvas.winfo_width()
71 height = canvas.winfo_height()
72 if width <= 1:
73 width = canvas['width']
74 if height <= 1:
75 height = canvas['height']
76 self._origin = float(width)/2.0, float(height)/2.0
77 self._position = self._origin
78 self._angle = 0.0
79 self._drawing = 1
80 self._width = 1
81 self._color = "black"
82 self._filling = 0
83 self._path = []
84 self._tofill = []
85 self.clear()
86 canvas._root().tkraise()
87
88 def clear(self):
Georg Brandle3a25832006-05-17 14:56:04 +000089 """ Clear the screen. The turtle does not move.
90
91 Example:
92 >>> turtle.clear()
93 """
Guido van Rossumb241b671998-12-04 16:42:46 +000094 self.fill(0)
95 canvas = self._canvas
96 items = self._items
97 self._items = []
98 for item in items:
99 canvas.delete(item)
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000100 self._delete_turtle()
101 self._draw_turtle()
102
Guido van Rossumb241b671998-12-04 16:42:46 +0000103 def tracer(self, flag):
Georg Brandle3a25832006-05-17 14:56:04 +0000104 """ Set tracing on if flag is True, and off if it is False.
105 Tracing means line are drawn more slowly, with an
106 animation of an arrow along the line.
107
108 Example:
109 >>> turtle.tracer(False) # turns off Tracer
110 """
Guido van Rossumb241b671998-12-04 16:42:46 +0000111 self._tracing = flag
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000112 if not self._tracing:
113 self._delete_turtle()
114 self._draw_turtle()
Guido van Rossumb241b671998-12-04 16:42:46 +0000115
116 def forward(self, distance):
Georg Brandle3a25832006-05-17 14:56:04 +0000117 """ Go forward distance steps.
118
119 Example:
120 >>> turtle.position()
121 [0.0, 0.0]
122 >>> turtle.forward(25)
123 >>> turtle.position()
124 [25.0, 0.0]
125 >>> turtle.forward(-75)
126 >>> turtle.position()
127 [-50.0, 0.0]
128 """
Guido van Rossumb241b671998-12-04 16:42:46 +0000129 x0, y0 = start = self._position
130 x1 = x0 + distance * cos(self._angle*self._invradian)
131 y1 = y0 - distance * sin(self._angle*self._invradian)
132 self._goto(x1, y1)
133
134 def backward(self, distance):
Georg Brandle3a25832006-05-17 14:56:04 +0000135 """ Go backwards distance steps.
136
137 The turtle's heading does not change.
138
139 Example:
140 >>> turtle.position()
141 [0.0, 0.0]
142 >>> turtle.backward(30)
143 >>> turtle.position()
144 [-30.0, 0.0]
145 """
Guido van Rossumb241b671998-12-04 16:42:46 +0000146 self.forward(-distance)
147
148 def left(self, angle):
Georg Brandle3a25832006-05-17 14:56:04 +0000149 """ Turn left angle units (units are by default degrees,
150 but can be set via the degrees() and radians() functions.)
151
152 When viewed from above, the turning happens in-place around
153 its front tip.
154
155 Example:
156 >>> turtle.heading()
157 22
158 >>> turtle.left(45)
159 >>> turtle.heading()
160 67.0
161 """
Guido van Rossumb241b671998-12-04 16:42:46 +0000162 self._angle = (self._angle + angle) % self._fullcircle
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000163 self._draw_turtle()
Guido van Rossumb241b671998-12-04 16:42:46 +0000164
165 def right(self, angle):
Georg Brandle3a25832006-05-17 14:56:04 +0000166 """ Turn right angle units (units are by default degrees,
167 but can be set via the degrees() and radians() functions.)
168
169 When viewed from above, the turning happens in-place around
170 its front tip.
171
172 Example:
173 >>> turtle.heading()
174 22
175 >>> turtle.right(45)
176 >>> turtle.heading()
177 337.0
178 """
Guido van Rossumb241b671998-12-04 16:42:46 +0000179 self.left(-angle)
180
181 def up(self):
Georg Brandle3a25832006-05-17 14:56:04 +0000182 """ Pull the pen up -- no drawing when moving.
183
184 Example:
185 >>> turtle.up()
186 """
Guido van Rossumb241b671998-12-04 16:42:46 +0000187 self._drawing = 0
188
189 def down(self):
Georg Brandle3a25832006-05-17 14:56:04 +0000190 """ Put the pen down -- draw when moving.
191
192 Example:
193 >>> turtle.down()
194 """
Guido van Rossumb241b671998-12-04 16:42:46 +0000195 self._drawing = 1
196
197 def width(self, width):
Georg Brandle3a25832006-05-17 14:56:04 +0000198 """ Set the line to thickness to width.
199
200 Example:
201 >>> turtle.width(10)
202 """
Guido van Rossumb241b671998-12-04 16:42:46 +0000203 self._width = float(width)
204
205 def color(self, *args):
Georg Brandle3a25832006-05-17 14:56:04 +0000206 """ Set the pen color.
207
208 Three input formats are allowed:
209
210 color(s)
211 s is a Tk specification string, such as "red" or "yellow"
212
213 color((r, g, b))
214 *a tuple* of r, g, and b, which represent, an RGB color,
215 and each of r, g, and b are in the range [0..1]
216
217 color(r, g, b)
218 r, g, and b represent an RGB color, and each of r, g, and b
219 are in the range [0..1]
220
221 Example:
222
223 >>> turtle.color('brown')
224 >>> tup = (0.2, 0.8, 0.55)
225 >>> turtle.color(tup)
226 >>> turtle.color(0, .5, 0)
227 """
Guido van Rossumb241b671998-12-04 16:42:46 +0000228 if not args:
229 raise Error, "no color arguments"
230 if len(args) == 1:
231 color = args[0]
232 if type(color) == type(""):
233 # Test the color first
234 try:
235 id = self._canvas.create_line(0, 0, 0, 0, fill=color)
Martin v. Löwis4b6ea792000-10-01 17:52:01 +0000236 except Tkinter.TclError:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000237 raise Error, "bad color string: %r" % (color,)
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000238 self._set_color(color)
Guido van Rossumb241b671998-12-04 16:42:46 +0000239 return
240 try:
241 r, g, b = color
242 except:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000243 raise Error, "bad color sequence: %r" % (color,)
Guido van Rossumb241b671998-12-04 16:42:46 +0000244 else:
245 try:
246 r, g, b = args
247 except:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000248 raise Error, "bad color arguments: %r" % (args,)
Guido van Rossumb241b671998-12-04 16:42:46 +0000249 assert 0 <= r <= 1
250 assert 0 <= g <= 1
251 assert 0 <= b <= 1
252 x = 255.0
253 y = 0.5
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000254 self._set_color("#%02x%02x%02x" % (int(r*x+y), int(g*x+y), int(b*x+y)))
255
256 def _set_color(self,color):
257 self._color = color
258 self._draw_turtle()
259
Georg Brandle3a25832006-05-17 14:56:04 +0000260 def write(self, text, move=False):
261 """ Write text at the current pen position.
262
263 If move is true, the pen is moved to the bottom-right corner
264 of the text. By default, move is False.
265
266 Example:
267 >>> turtle.write('The race is on!')
268 >>> turtle.write('Home = (0, 0)', True)
269 """
270 x, y = self._position
Guido van Rossumb241b671998-12-04 16:42:46 +0000271 x = x-1 # correction -- calibrated for Windows
Fred Draked038ca82000-10-23 18:31:14 +0000272 item = self._canvas.create_text(x, y,
Georg Brandle3a25832006-05-17 14:56:04 +0000273 text=str(text), anchor="sw",
Guido van Rossumb241b671998-12-04 16:42:46 +0000274 fill=self._color)
275 self._items.append(item)
276 if move:
277 x0, y0, x1, y1 = self._canvas.bbox(item)
278 self._goto(x1, y1)
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000279 self._draw_turtle()
Guido van Rossumb241b671998-12-04 16:42:46 +0000280
281 def fill(self, flag):
Georg Brandle3a25832006-05-17 14:56:04 +0000282 """ Call fill(1) before drawing the shape you
283 want to fill, and fill(0) when done.
284
285 Example:
286 >>> turtle.fill(1)
287 >>> turtle.forward(100)
288 >>> turtle.left(90)
289 >>> turtle.forward(100)
290 >>> turtle.left(90)
291 >>> turtle.forward(100)
292 >>> turtle.left(90)
293 >>> turtle.forward(100)
294 >>> turtle.fill(0)
295 """
Guido van Rossumb241b671998-12-04 16:42:46 +0000296 if self._filling:
297 path = tuple(self._path)
298 smooth = self._filling < 0
299 if len(path) > 2:
300 item = self._canvas._create('polygon', path,
301 {'fill': self._color,
302 'smooth': smooth})
303 self._items.append(item)
Guido van Rossumb241b671998-12-04 16:42:46 +0000304 if self._tofill:
305 for item in self._tofill:
306 self._canvas.itemconfigure(item, fill=self._color)
307 self._items.append(item)
308 self._path = []
309 self._tofill = []
310 self._filling = flag
311 if flag:
312 self._path.append(self._position)
Raymond Hettingeraf81c2e2003-06-09 08:50:57 +0000313 self.forward(0)
Guido van Rossumb241b671998-12-04 16:42:46 +0000314
Georg Brandle3a25832006-05-17 14:56:04 +0000315 def begin_fill(self):
316 """ Called just before drawing a shape to be filled.
317
318 Example:
319 >>> turtle.begin_fill()
320 >>> turtle.forward(100)
321 >>> turtle.left(90)
322 >>> turtle.forward(100)
323 >>> turtle.left(90)
324 >>> turtle.forward(100)
325 >>> turtle.left(90)
326 >>> turtle.forward(100)
327 >>> turtle.end_fill()
328 """
329 self.fill(1)
330
331 def end_fill(self):
332 """ Called after drawing a shape to be filled.
333
334 Example:
335 >>> turtle.begin_fill()
336 >>> turtle.forward(100)
337 >>> turtle.left(90)
338 >>> turtle.forward(100)
339 >>> turtle.left(90)
340 >>> turtle.forward(100)
341 >>> turtle.left(90)
342 >>> turtle.forward(100)
343 >>> turtle.end_fill()
344 """
345 self.fill(0)
346
Guido van Rossumb241b671998-12-04 16:42:46 +0000347 def circle(self, radius, extent=None):
Georg Brandle3a25832006-05-17 14:56:04 +0000348 """ Draw a circle with given radius.
349 The center is radius units left of the turtle; extent
350 determines which part of the circle is drawn. If not given,
351 the entire circle is drawn.
352
353 If extent is not a full circle, one endpoint of the arc is the
354 current pen position. The arc is drawn in a counter clockwise
355 direction if radius is positive, otherwise in a clockwise
356 direction. In the process, the direction of the turtle is
357 changed by the amount of the extent.
358
359 >>> turtle.circle(50)
360 >>> turtle.circle(120, 180) # half a circle
361 """
Guido van Rossumb241b671998-12-04 16:42:46 +0000362 if extent is None:
363 extent = self._fullcircle
364 x0, y0 = self._position
365 xc = x0 - radius * sin(self._angle * self._invradian)
366 yc = y0 - radius * cos(self._angle * self._invradian)
367 if radius >= 0.0:
Georg Brandle3a25832006-05-17 14:56:04 +0000368 start = self._angle - (self._fullcircle / 4.0)
Guido van Rossumb241b671998-12-04 16:42:46 +0000369 else:
Georg Brandle3a25832006-05-17 14:56:04 +0000370 start = self._angle + (self._fullcircle / 4.0)
Guido van Rossumb241b671998-12-04 16:42:46 +0000371 extent = -extent
372 if self._filling:
373 if abs(extent) >= self._fullcircle:
374 item = self._canvas.create_oval(xc-radius, yc-radius,
375 xc+radius, yc+radius,
376 width=self._width,
377 outline="")
378 self._tofill.append(item)
379 item = self._canvas.create_arc(xc-radius, yc-radius,
380 xc+radius, yc+radius,
381 style="chord",
382 start=start,
383 extent=extent,
384 width=self._width,
385 outline="")
386 self._tofill.append(item)
387 if self._drawing:
388 if abs(extent) >= self._fullcircle:
389 item = self._canvas.create_oval(xc-radius, yc-radius,
390 xc+radius, yc+radius,
391 width=self._width,
392 outline=self._color)
393 self._items.append(item)
394 item = self._canvas.create_arc(xc-radius, yc-radius,
395 xc+radius, yc+radius,
396 style="arc",
397 start=start,
398 extent=extent,
399 width=self._width,
400 outline=self._color)
401 self._items.append(item)
402 angle = start + extent
403 x1 = xc + abs(radius) * cos(angle * self._invradian)
404 y1 = yc - abs(radius) * sin(angle * self._invradian)
405 self._angle = (self._angle + extent) % self._fullcircle
406 self._position = x1, y1
407 if self._filling:
408 self._path.append(self._position)
Martin v. Löwis73b9b662002-09-22 13:00:26 +0000409 self._draw_turtle()
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000410
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000411 def heading(self):
Georg Brandle3a25832006-05-17 14:56:04 +0000412 """ Return the turtle's current heading.
413
414 Example:
415 >>> turtle.heading()
416 67.0
417 """
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000418 return self._angle
419
420 def setheading(self, angle):
Georg Brandle3a25832006-05-17 14:56:04 +0000421 """ Set the turtle facing the given angle.
422
423 Here are some common directions in degrees:
424
425 0 - east
426 90 - north
427 180 - west
428 270 - south
429
430 Example:
431 >>> turtle.setheading(90)
432 >>> turtle.heading()
433 90
434 >>> turtle.setheading(128)
435 >>> turtle.heading()
436 128
437 """
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000438 self._angle = angle
439 self._draw_turtle()
440
441 def window_width(self):
Georg Brandle3a25832006-05-17 14:56:04 +0000442 """ Returns the width of the turtle window.
443
444 Example:
445 >>> turtle.window_width()
446 640
447 """
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000448 width = self._canvas.winfo_width()
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000449 if width <= 1: # the window isn't managed by a geometry manager
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000450 width = self._canvas['width']
451 return width
452
453 def window_height(self):
Georg Brandle3a25832006-05-17 14:56:04 +0000454 """ Return the height of the turtle window.
455
456 Example:
457 >>> turtle.window_height()
458 768
459 """
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000460 height = self._canvas.winfo_height()
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000461 if height <= 1: # the window isn't managed by a geometry manager
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000462 height = self._canvas['height']
463 return height
464
465 def position(self):
Georg Brandle3a25832006-05-17 14:56:04 +0000466 """ Return the current (x, y) location of the turtle.
467
468 Example:
469 >>> turtle.position()
470 [0.0, 240.0]
471 """
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000472 x0, y0 = self._origin
473 x1, y1 = self._position
474 return [x1-x0, -y1+y0]
475
476 def setx(self, xpos):
Georg Brandle3a25832006-05-17 14:56:04 +0000477 """ Set the turtle's x coordinate to be xpos.
478
479 Example:
480 >>> turtle.position()
481 [10.0, 240.0]
482 >>> turtle.setx(10)
483 >>> turtle.position()
484 [10.0, 240.0]
485 """
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000486 x0, y0 = self._origin
487 x1, y1 = self._position
488 self._goto(x0+xpos, y1)
489
490 def sety(self, ypos):
Georg Brandle3a25832006-05-17 14:56:04 +0000491 """ Set the turtle's y coordinate to be ypos.
492
493 Example:
494 >>> turtle.position()
495 [0.0, 0.0]
496 >>> turtle.sety(-22)
497 >>> turtle.position()
498 [0.0, -22.0]
499 """
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000500 x0, y0 = self._origin
501 x1, y1 = self._position
502 self._goto(x1, y0-ypos)
Guido van Rossumb241b671998-12-04 16:42:46 +0000503
Georg Brandle3a25832006-05-17 14:56:04 +0000504 def towards(self, *args):
505 """Returs the angle, which corresponds to the line
506 from turtle-position to point (x,y).
507
508 Argument can be two coordinates or one pair of coordinates
509 or a RawPen/Pen instance.
510
511 Example:
512 >>> turtle.position()
513 [10.0, 10.0]
514 >>> turtle.towards(0,0)
515 225.0
516 """
517 if len(args) == 2:
518 x, y = args
519 else:
520 arg = args[0]
521 if isinstance(arg, RawPen):
522 x, y = arg.position()
523 else:
524 x, y = arg
525 x0, y0 = self.position()
526 dx = x - x0
527 dy = y - y0
528 return (atan2(dy,dx) / self._invradian) % self._fullcircle
529
Guido van Rossumb241b671998-12-04 16:42:46 +0000530 def goto(self, *args):
Georg Brandle3a25832006-05-17 14:56:04 +0000531 """ Go to the given point.
532
533 If the pen is down, then a line will be drawn. The turtle's
534 orientation does not change.
535
536 Two input formats are accepted:
537
538 goto(x, y)
539 go to point (x, y)
540
541 goto((x, y))
542 go to point (x, y)
543
544 Example:
545 >>> turtle.position()
546 [0.0, 0.0]
547 >>> turtle.goto(50, -45)
548 >>> turtle.position()
549 [50.0, -45.0]
550 """
Guido van Rossumb241b671998-12-04 16:42:46 +0000551 if len(args) == 1:
552 try:
553 x, y = args[0]
554 except:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000555 raise Error, "bad point argument: %r" % (args[0],)
Guido van Rossumb241b671998-12-04 16:42:46 +0000556 else:
557 try:
558 x, y = args
559 except:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000560 raise Error, "bad coordinates: %r" % (args[0],)
Guido van Rossumb241b671998-12-04 16:42:46 +0000561 x0, y0 = self._origin
562 self._goto(x0+x, y0-y)
563
564 def _goto(self, x1, y1):
Georg Brandle3a25832006-05-17 14:56:04 +0000565 x0, y0 = self._position
Guido van Rossumb241b671998-12-04 16:42:46 +0000566 self._position = map(float, (x1, y1))
567 if self._filling:
568 self._path.append(self._position)
569 if self._drawing:
Guido van Rossumbffa52f2002-09-29 00:25:51 +0000570 if self._tracing:
Guido van Rossumb241b671998-12-04 16:42:46 +0000571 dx = float(x1 - x0)
572 dy = float(y1 - y0)
573 distance = hypot(dx, dy)
574 nhops = int(distance)
575 item = self._canvas.create_line(x0, y0, x0, y0,
576 width=self._width,
Guido van Rossumb241b671998-12-04 16:42:46 +0000577 capstyle="round",
578 fill=self._color)
579 try:
580 for i in range(1, 1+nhops):
581 x, y = x0 + dx*i/nhops, y0 + dy*i/nhops
582 self._canvas.coords(item, x0, y0, x, y)
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000583 self._draw_turtle((x,y))
Guido van Rossumb241b671998-12-04 16:42:46 +0000584 self._canvas.update()
Georg Brandle3a25832006-05-17 14:56:04 +0000585 self._canvas.after(self._delay)
Guido van Rossuma659efe2001-01-01 19:11:07 +0000586 # in case nhops==0
587 self._canvas.coords(item, x0, y0, x1, y1)
Guido van Rossumb241b671998-12-04 16:42:46 +0000588 self._canvas.itemconfigure(item, arrow="none")
Martin v. Löwis4b6ea792000-10-01 17:52:01 +0000589 except Tkinter.TclError:
Guido van Rossumb241b671998-12-04 16:42:46 +0000590 # Probably the window was closed!
591 return
592 else:
593 item = self._canvas.create_line(x0, y0, x1, y1,
594 width=self._width,
595 capstyle="round",
596 fill=self._color)
597 self._items.append(item)
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000598 self._draw_turtle()
599
Georg Brandle3a25832006-05-17 14:56:04 +0000600 def speed(self, speed):
601 """ Set the turtle's speed.
602
603 speed must one of these five strings:
604
605 'fastest' is a 0 ms delay
606 'fast' is a 5 ms delay
607 'normal' is a 10 ms delay
608 'slow' is a 15 ms delay
609 'slowest' is a 20 ms delay
610
611 Example:
612 >>> turtle.speed('slow')
613 """
614 try:
615 speed = speed.strip().lower()
616 self._delay = speeds.index(speed) * 5
617 except:
618 raise ValueError("%r is not a valid speed. speed must be "
619 "one of %s" % (speed, speeds))
620
621
622 def delay(self, delay):
623 """ Set the drawing delay in milliseconds.
624
625 This is intended to allow finer control of the drawing speed
626 than the speed() method
627
628 Example:
629 >>> turtle.delay(15)
630 """
631 if int(delay) < 0:
632 raise ValueError("delay must be greater than or equal to 0")
633 self._delay = int(delay)
634
635 def _draw_turtle(self, position=[]):
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000636 if not self._tracing:
637 return
638 if position == []:
639 position = self._position
640 x,y = position
641 distance = 8
642 dx = distance * cos(self._angle*self._invradian)
643 dy = distance * sin(self._angle*self._invradian)
644 self._delete_turtle()
Martin v. Löwis4157ffb2002-03-28 15:45:57 +0000645 self._arrow = self._canvas.create_line(x-dx,y+dy,x,y,
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000646 width=self._width,
647 arrow="last",
648 capstyle="round",
649 fill=self._color)
650 self._canvas.update()
651
652 def _delete_turtle(self):
653 if self._arrow != 0:
654 self._canvas.delete(self._arrow)
Georg Brandle3a25832006-05-17 14:56:04 +0000655 self._arrow = 0
Guido van Rossumb241b671998-12-04 16:42:46 +0000656
657
658_root = None
659_canvas = None
660_pen = None
Georg Brandle3a25832006-05-17 14:56:04 +0000661_width = 0.50 # 50% of window width
662_height = 0.75 # 75% of window height
663_startx = None
664_starty = None
665_title = "Turtle Graphics" # default title
Guido van Rossumb241b671998-12-04 16:42:46 +0000666
667class Pen(RawPen):
668
669 def __init__(self):
670 global _root, _canvas
671 if _root is None:
Martin v. Löwis4b6ea792000-10-01 17:52:01 +0000672 _root = Tkinter.Tk()
Guido van Rossumb241b671998-12-04 16:42:46 +0000673 _root.wm_protocol("WM_DELETE_WINDOW", self._destroy)
Georg Brandle3a25832006-05-17 14:56:04 +0000674 _root.title(_title)
675
Guido van Rossumb241b671998-12-04 16:42:46 +0000676 if _canvas is None:
677 # XXX Should have scroll bars
Martin v. Löwis4b6ea792000-10-01 17:52:01 +0000678 _canvas = Tkinter.Canvas(_root, background="white")
Guido van Rossumb241b671998-12-04 16:42:46 +0000679 _canvas.pack(expand=1, fill="both")
Georg Brandle3a25832006-05-17 14:56:04 +0000680
681 setup(width=_width, height= _height, startx=_startx, starty=_starty)
682
Guido van Rossumb241b671998-12-04 16:42:46 +0000683 RawPen.__init__(self, _canvas)
684
685 def _destroy(self):
686 global _root, _canvas, _pen
687 root = self._canvas._root()
688 if root is _root:
689 _pen = None
690 _root = None
691 _canvas = None
692 root.destroy()
Fred Draked038ca82000-10-23 18:31:14 +0000693
Guido van Rossumb241b671998-12-04 16:42:46 +0000694def _getpen():
695 global _pen
Georg Brandle3a25832006-05-17 14:56:04 +0000696 if not _pen:
697 _pen = Pen()
698 return _pen
699
700class Turtle(Pen):
701 pass
702
703"""For documentation of the following functions see
704 the RawPen methods with the same names
705"""
Guido van Rossumb241b671998-12-04 16:42:46 +0000706
707def degrees(): _getpen().degrees()
708def radians(): _getpen().radians()
709def reset(): _getpen().reset()
710def clear(): _getpen().clear()
711def tracer(flag): _getpen().tracer(flag)
712def forward(distance): _getpen().forward(distance)
713def backward(distance): _getpen().backward(distance)
714def left(angle): _getpen().left(angle)
715def right(angle): _getpen().right(angle)
716def up(): _getpen().up()
717def down(): _getpen().down()
718def width(width): _getpen().width(width)
Raymond Hettingerff41c482003-04-06 09:01:11 +0000719def color(*args): _getpen().color(*args)
Guido van Rossumb241b671998-12-04 16:42:46 +0000720def write(arg, move=0): _getpen().write(arg, move)
721def fill(flag): _getpen().fill(flag)
Georg Brandle3a25832006-05-17 14:56:04 +0000722def begin_fill(): _getpen().begin_fill()
723def end_fill(): _getpen.end_fill()
Guido van Rossumb241b671998-12-04 16:42:46 +0000724def circle(radius, extent=None): _getpen().circle(radius, extent)
Raymond Hettingerff41c482003-04-06 09:01:11 +0000725def goto(*args): _getpen().goto(*args)
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000726def heading(): return _getpen().heading()
727def setheading(angle): _getpen().setheading(angle)
728def position(): return _getpen().position()
729def window_width(): return _getpen().window_width()
730def window_height(): return _getpen().window_height()
731def setx(xpos): _getpen().setx(xpos)
732def sety(ypos): _getpen().sety(ypos)
Georg Brandle3a25832006-05-17 14:56:04 +0000733def towards(*args): return _getpen().towards(*args)
734
735def done(): _root.mainloop()
736def delay(delay): return _getpen().delay(delay)
737def speed(speed): return _getpen().speed(speed)
738
739for methodname in dir(RawPen):
740 """ copies RawPen docstrings to module functions of same name """
741 if not methodname.startswith("_"):
742 eval(methodname).__doc__ = RawPen.__dict__[methodname].__doc__
743
744
745def setup(**geometry):
746 """ Sets the size and position of the main window.
747
748 Keywords are width, height, startx and starty
749
750 width: either a size in pixels or a fraction of the screen.
751 Default is 50% of screen.
752 height: either the height in pixels or a fraction of the screen.
753 Default is 75% of screen.
754
755 Setting either width or height to None before drawing will force
756 use of default geometry as in older versions of turtle.py
Tim Petersfd4c4192006-05-18 02:06:40 +0000757
Georg Brandle3a25832006-05-17 14:56:04 +0000758 startx: starting position in pixels from the left edge of the screen.
759 Default is to center window. Setting startx to None is the default
760 and centers window horizontally on screen.
Tim Petersfd4c4192006-05-18 02:06:40 +0000761
Georg Brandle3a25832006-05-17 14:56:04 +0000762 starty: starting position in pixels from the top edge of the screen.
763 Default is to center window. Setting starty to None is the default
764 and centers window vertically on screen.
765
766 Examples:
767 >>> setup (width=200, height=200, startx=0, starty=0)
768
769 sets window to 200x200 pixels, in upper left of screen
770
771 >>> setup(width=.75, height=0.5, startx=None, starty=None)
772
773 sets window to 75% of screen by 50% of screen and centers
774
775 >>> setup(width=None)
776
777 forces use of default geometry as in older versions of turtle.py
778 """
Tim Petersfd4c4192006-05-18 02:06:40 +0000779
Georg Brandle3a25832006-05-17 14:56:04 +0000780 global _width, _height, _startx, _starty
781
782 width = geometry.get('width',_width)
783 if width >= 0 or width == None:
784 _width = width
785 else:
786 raise ValueError, "width can not be less than 0"
787
788 height = geometry.get('height',_height)
789 if height >= 0 or height == None:
790 _height = height
791 else:
792 raise ValueError, "height can not be less than 0"
Tim Petersfd4c4192006-05-18 02:06:40 +0000793
Georg Brandle3a25832006-05-17 14:56:04 +0000794 startx = geometry.get('startx', _startx)
795 if startx >= 0 or startx == None:
796 _startx = _startx
797 else:
798 raise ValueError, "startx can not be less than 0"
799
800 starty = geometry.get('starty', _starty)
801 if starty >= 0 or starty == None:
802 _starty = starty
803 else:
804 raise ValueError, "startx can not be less than 0"
805
806
807 if _root and _width and _height:
808 if 0 < _width <= 1:
809 _width = _root.winfo_screenwidth() * +width
810 if 0 < _height <= 1:
811 _height = _root.winfo_screenheight() * _height
812
813 # center window on screen
814 if _startx is None:
815 _startx = (_root.winfo_screenwidth() - _width) / 2
Tim Petersfd4c4192006-05-18 02:06:40 +0000816
Georg Brandle3a25832006-05-17 14:56:04 +0000817 if _starty is None:
818 _starty = (_root.winfo_screenheight() - _height) / 2
819
820 _root.geometry("%dx%d+%d+%d" % (_width, _height, _startx, _starty))
821
822def title(title):
823 """ set the window title.
824
825 By default this is set to 'Turtle Graphics'
826
827 Example:
828 >>> title("My Window")
829 """
Tim Petersfd4c4192006-05-18 02:06:40 +0000830
Georg Brandle3a25832006-05-17 14:56:04 +0000831 global _title
832 _title = title
Guido van Rossumb241b671998-12-04 16:42:46 +0000833
834def demo():
835 reset()
836 tracer(1)
837 up()
838 backward(100)
839 down()
840 # draw 3 squares; the last filled
841 width(3)
842 for i in range(3):
843 if i == 2:
844 fill(1)
845 for j in range(4):
846 forward(20)
847 left(90)
848 if i == 2:
849 color("maroon")
850 fill(0)
851 up()
852 forward(30)
853 down()
854 width(1)
855 color("black")
856 # move out of the way
857 tracer(0)
858 up()
859 right(90)
860 forward(100)
861 right(90)
862 forward(100)
863 right(180)
864 down()
865 # some text
866 write("startstart", 1)
867 write("start", 1)
868 color("red")
869 # staircase
870 for i in range(5):
871 forward(20)
872 left(90)
873 forward(20)
874 right(90)
875 # filled staircase
876 fill(1)
877 for i in range(5):
878 forward(20)
879 left(90)
880 forward(20)
881 right(90)
882 fill(0)
Georg Brandle3a25832006-05-17 14:56:04 +0000883 tracer(1)
Guido van Rossumb241b671998-12-04 16:42:46 +0000884 # more text
885 write("end")
Georg Brandle3a25832006-05-17 14:56:04 +0000886
887def demo2():
888 # exercises some new and improved features
889 speed('fast')
890 width(3)
891
892 # draw a segmented half-circle
893 setheading(towards(0,0))
894 x,y = position()
895 r = (x**2+y**2)**.5/2.0
896 right(90)
897 pendown = True
898 for i in range(18):
899 if pendown:
900 up()
901 pendown = False
902 else:
903 down()
904 pendown = True
905 circle(r,10)
906 sleep(2)
Tim Petersfd4c4192006-05-18 02:06:40 +0000907
908 reset()
Georg Brandle3a25832006-05-17 14:56:04 +0000909 left(90)
Tim Petersfd4c4192006-05-18 02:06:40 +0000910
Georg Brandle3a25832006-05-17 14:56:04 +0000911 # draw a series of triangles
912 l = 10
913 color("green")
914 width(3)
915 left(180)
916 sp = 5
917 for i in range(-2,16):
918 if i > 0:
919 color(1.0-0.05*i,0,0.05*i)
920 fill(1)
921 color("green")
922 for j in range(3):
923 forward(l)
924 left(120)
925 l += 10
926 left(15)
927 if sp > 0:
928 sp = sp-1
929 speed(speeds[sp])
930 color(0.25,0,0.75)
931 fill(0)
932 color("green")
933
934 left(130)
935 up()
936 forward(90)
937 color("red")
938 speed('fastest')
Tim Petersfd4c4192006-05-18 02:06:40 +0000939 down();
Georg Brandle3a25832006-05-17 14:56:04 +0000940
941 # create a second turtle and make the original pursue and catch it
942 turtle=Turtle()
943 turtle.reset()
944 turtle.left(90)
945 turtle.speed('normal')
946 turtle.up()
947 turtle.goto(280,40)
948 turtle.left(24)
949 turtle.down()
950 turtle.speed('fast')
951 turtle.color("blue")
952 turtle.width(2)
953 speed('fastest')
954
955 # turn default turtle towards new turtle object
956 setheading(towards(turtle))
957 while ( abs(position()[0]-turtle.position()[0])>4 or
958 abs(position()[1]-turtle.position()[1])>4):
959 turtle.forward(3.5)
960 turtle.left(0.6)
961 # turn default turtle towards new turtle object
962 setheading(towards(turtle))
963 forward(4)
964 write("CAUGHT! ", move=True)
965
Tim Petersfd4c4192006-05-18 02:06:40 +0000966
Guido van Rossumb241b671998-12-04 16:42:46 +0000967
968if __name__ == '__main__':
Georg Brandle3a25832006-05-17 14:56:04 +0000969 from time import sleep
Guido van Rossumb241b671998-12-04 16:42:46 +0000970 demo()
Georg Brandle3a25832006-05-17 14:56:04 +0000971 sleep(3)
972 demo2()
973 done()