blob: 0fe83a3df8e1ab3519e8ffd2b2f863650e75b2d8 [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:
Martin v. Löwis3798da02006-06-17 18:44:27 +0000637 self._canvas.update()
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000638 return
639 if position == []:
640 position = self._position
641 x,y = position
642 distance = 8
643 dx = distance * cos(self._angle*self._invradian)
644 dy = distance * sin(self._angle*self._invradian)
645 self._delete_turtle()
Martin v. Löwis4157ffb2002-03-28 15:45:57 +0000646 self._arrow = self._canvas.create_line(x-dx,y+dy,x,y,
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000647 width=self._width,
648 arrow="last",
649 capstyle="round",
650 fill=self._color)
651 self._canvas.update()
652
653 def _delete_turtle(self):
654 if self._arrow != 0:
655 self._canvas.delete(self._arrow)
Georg Brandle3a25832006-05-17 14:56:04 +0000656 self._arrow = 0
Guido van Rossumb241b671998-12-04 16:42:46 +0000657
658
659_root = None
660_canvas = None
661_pen = None
Georg Brandle3a25832006-05-17 14:56:04 +0000662_width = 0.50 # 50% of window width
663_height = 0.75 # 75% of window height
664_startx = None
665_starty = None
666_title = "Turtle Graphics" # default title
Guido van Rossumb241b671998-12-04 16:42:46 +0000667
668class Pen(RawPen):
669
670 def __init__(self):
671 global _root, _canvas
672 if _root is None:
Martin v. Löwis4b6ea792000-10-01 17:52:01 +0000673 _root = Tkinter.Tk()
Guido van Rossumb241b671998-12-04 16:42:46 +0000674 _root.wm_protocol("WM_DELETE_WINDOW", self._destroy)
Georg Brandle3a25832006-05-17 14:56:04 +0000675 _root.title(_title)
676
Guido van Rossumb241b671998-12-04 16:42:46 +0000677 if _canvas is None:
678 # XXX Should have scroll bars
Martin v. Löwis4b6ea792000-10-01 17:52:01 +0000679 _canvas = Tkinter.Canvas(_root, background="white")
Guido van Rossumb241b671998-12-04 16:42:46 +0000680 _canvas.pack(expand=1, fill="both")
Georg Brandle3a25832006-05-17 14:56:04 +0000681
682 setup(width=_width, height= _height, startx=_startx, starty=_starty)
683
Guido van Rossumb241b671998-12-04 16:42:46 +0000684 RawPen.__init__(self, _canvas)
685
686 def _destroy(self):
687 global _root, _canvas, _pen
688 root = self._canvas._root()
689 if root is _root:
690 _pen = None
691 _root = None
692 _canvas = None
693 root.destroy()
Fred Draked038ca82000-10-23 18:31:14 +0000694
Guido van Rossumb241b671998-12-04 16:42:46 +0000695def _getpen():
696 global _pen
Georg Brandle3a25832006-05-17 14:56:04 +0000697 if not _pen:
698 _pen = Pen()
699 return _pen
700
701class Turtle(Pen):
702 pass
703
704"""For documentation of the following functions see
705 the RawPen methods with the same names
706"""
Guido van Rossumb241b671998-12-04 16:42:46 +0000707
708def degrees(): _getpen().degrees()
709def radians(): _getpen().radians()
710def reset(): _getpen().reset()
711def clear(): _getpen().clear()
712def tracer(flag): _getpen().tracer(flag)
713def forward(distance): _getpen().forward(distance)
714def backward(distance): _getpen().backward(distance)
715def left(angle): _getpen().left(angle)
716def right(angle): _getpen().right(angle)
717def up(): _getpen().up()
718def down(): _getpen().down()
719def width(width): _getpen().width(width)
Raymond Hettingerff41c482003-04-06 09:01:11 +0000720def color(*args): _getpen().color(*args)
Guido van Rossumb241b671998-12-04 16:42:46 +0000721def write(arg, move=0): _getpen().write(arg, move)
722def fill(flag): _getpen().fill(flag)
Georg Brandle3a25832006-05-17 14:56:04 +0000723def begin_fill(): _getpen().begin_fill()
Georg Brandl1be63af2006-06-28 20:23:25 +0000724def end_fill(): _getpen().end_fill()
Guido van Rossumb241b671998-12-04 16:42:46 +0000725def circle(radius, extent=None): _getpen().circle(radius, extent)
Raymond Hettingerff41c482003-04-06 09:01:11 +0000726def goto(*args): _getpen().goto(*args)
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000727def heading(): return _getpen().heading()
728def setheading(angle): _getpen().setheading(angle)
729def position(): return _getpen().position()
730def window_width(): return _getpen().window_width()
731def window_height(): return _getpen().window_height()
732def setx(xpos): _getpen().setx(xpos)
733def sety(ypos): _getpen().sety(ypos)
Georg Brandle3a25832006-05-17 14:56:04 +0000734def towards(*args): return _getpen().towards(*args)
735
736def done(): _root.mainloop()
737def delay(delay): return _getpen().delay(delay)
738def speed(speed): return _getpen().speed(speed)
739
740for methodname in dir(RawPen):
741 """ copies RawPen docstrings to module functions of same name """
742 if not methodname.startswith("_"):
743 eval(methodname).__doc__ = RawPen.__dict__[methodname].__doc__
744
745
746def setup(**geometry):
747 """ Sets the size and position of the main window.
748
749 Keywords are width, height, startx and starty
750
751 width: either a size in pixels or a fraction of the screen.
752 Default is 50% of screen.
753 height: either the height in pixels or a fraction of the screen.
754 Default is 75% of screen.
755
756 Setting either width or height to None before drawing will force
757 use of default geometry as in older versions of turtle.py
Tim Petersfd4c4192006-05-18 02:06:40 +0000758
Georg Brandle3a25832006-05-17 14:56:04 +0000759 startx: starting position in pixels from the left edge of the screen.
760 Default is to center window. Setting startx to None is the default
761 and centers window horizontally on screen.
Tim Petersfd4c4192006-05-18 02:06:40 +0000762
Georg Brandle3a25832006-05-17 14:56:04 +0000763 starty: starting position in pixels from the top edge of the screen.
764 Default is to center window. Setting starty to None is the default
765 and centers window vertically on screen.
766
767 Examples:
768 >>> setup (width=200, height=200, startx=0, starty=0)
769
770 sets window to 200x200 pixels, in upper left of screen
771
772 >>> setup(width=.75, height=0.5, startx=None, starty=None)
773
774 sets window to 75% of screen by 50% of screen and centers
775
776 >>> setup(width=None)
777
778 forces use of default geometry as in older versions of turtle.py
779 """
Tim Petersfd4c4192006-05-18 02:06:40 +0000780
Georg Brandle3a25832006-05-17 14:56:04 +0000781 global _width, _height, _startx, _starty
782
783 width = geometry.get('width',_width)
784 if width >= 0 or width == None:
785 _width = width
786 else:
787 raise ValueError, "width can not be less than 0"
788
789 height = geometry.get('height',_height)
790 if height >= 0 or height == None:
791 _height = height
792 else:
793 raise ValueError, "height can not be less than 0"
Tim Petersfd4c4192006-05-18 02:06:40 +0000794
Georg Brandle3a25832006-05-17 14:56:04 +0000795 startx = geometry.get('startx', _startx)
796 if startx >= 0 or startx == None:
797 _startx = _startx
798 else:
799 raise ValueError, "startx can not be less than 0"
800
801 starty = geometry.get('starty', _starty)
802 if starty >= 0 or starty == None:
803 _starty = starty
804 else:
805 raise ValueError, "startx can not be less than 0"
806
807
808 if _root and _width and _height:
809 if 0 < _width <= 1:
810 _width = _root.winfo_screenwidth() * +width
811 if 0 < _height <= 1:
812 _height = _root.winfo_screenheight() * _height
813
814 # center window on screen
815 if _startx is None:
816 _startx = (_root.winfo_screenwidth() - _width) / 2
Tim Petersfd4c4192006-05-18 02:06:40 +0000817
Georg Brandle3a25832006-05-17 14:56:04 +0000818 if _starty is None:
819 _starty = (_root.winfo_screenheight() - _height) / 2
820
821 _root.geometry("%dx%d+%d+%d" % (_width, _height, _startx, _starty))
822
823def title(title):
824 """ set the window title.
825
826 By default this is set to 'Turtle Graphics'
827
828 Example:
829 >>> title("My Window")
830 """
Tim Petersfd4c4192006-05-18 02:06:40 +0000831
Georg Brandle3a25832006-05-17 14:56:04 +0000832 global _title
833 _title = title
Guido van Rossumb241b671998-12-04 16:42:46 +0000834
835def demo():
836 reset()
837 tracer(1)
838 up()
839 backward(100)
840 down()
841 # draw 3 squares; the last filled
842 width(3)
843 for i in range(3):
844 if i == 2:
845 fill(1)
846 for j in range(4):
847 forward(20)
848 left(90)
849 if i == 2:
850 color("maroon")
851 fill(0)
852 up()
853 forward(30)
854 down()
855 width(1)
856 color("black")
857 # move out of the way
858 tracer(0)
859 up()
860 right(90)
861 forward(100)
862 right(90)
863 forward(100)
864 right(180)
865 down()
866 # some text
867 write("startstart", 1)
868 write("start", 1)
869 color("red")
870 # staircase
871 for i in range(5):
872 forward(20)
873 left(90)
874 forward(20)
875 right(90)
876 # filled staircase
877 fill(1)
878 for i in range(5):
879 forward(20)
880 left(90)
881 forward(20)
882 right(90)
883 fill(0)
Georg Brandle3a25832006-05-17 14:56:04 +0000884 tracer(1)
Guido van Rossumb241b671998-12-04 16:42:46 +0000885 # more text
886 write("end")
Georg Brandle3a25832006-05-17 14:56:04 +0000887
888def demo2():
889 # exercises some new and improved features
890 speed('fast')
891 width(3)
892
893 # draw a segmented half-circle
894 setheading(towards(0,0))
895 x,y = position()
896 r = (x**2+y**2)**.5/2.0
897 right(90)
898 pendown = True
899 for i in range(18):
900 if pendown:
901 up()
902 pendown = False
903 else:
904 down()
905 pendown = True
906 circle(r,10)
907 sleep(2)
Tim Petersfd4c4192006-05-18 02:06:40 +0000908
909 reset()
Georg Brandle3a25832006-05-17 14:56:04 +0000910 left(90)
Tim Petersfd4c4192006-05-18 02:06:40 +0000911
Georg Brandle3a25832006-05-17 14:56:04 +0000912 # draw a series of triangles
913 l = 10
914 color("green")
915 width(3)
916 left(180)
917 sp = 5
918 for i in range(-2,16):
919 if i > 0:
920 color(1.0-0.05*i,0,0.05*i)
921 fill(1)
922 color("green")
923 for j in range(3):
924 forward(l)
925 left(120)
926 l += 10
927 left(15)
928 if sp > 0:
929 sp = sp-1
930 speed(speeds[sp])
931 color(0.25,0,0.75)
932 fill(0)
933 color("green")
934
935 left(130)
936 up()
937 forward(90)
938 color("red")
939 speed('fastest')
Tim Petersfd4c4192006-05-18 02:06:40 +0000940 down();
Georg Brandle3a25832006-05-17 14:56:04 +0000941
942 # create a second turtle and make the original pursue and catch it
943 turtle=Turtle()
944 turtle.reset()
945 turtle.left(90)
946 turtle.speed('normal')
947 turtle.up()
948 turtle.goto(280,40)
949 turtle.left(24)
950 turtle.down()
951 turtle.speed('fast')
952 turtle.color("blue")
953 turtle.width(2)
954 speed('fastest')
955
956 # turn default turtle towards new turtle object
957 setheading(towards(turtle))
958 while ( abs(position()[0]-turtle.position()[0])>4 or
959 abs(position()[1]-turtle.position()[1])>4):
960 turtle.forward(3.5)
961 turtle.left(0.6)
962 # turn default turtle towards new turtle object
963 setheading(towards(turtle))
964 forward(4)
965 write("CAUGHT! ", move=True)
966
Tim Petersfd4c4192006-05-18 02:06:40 +0000967
Guido van Rossumb241b671998-12-04 16:42:46 +0000968
969if __name__ == '__main__':
Georg Brandle3a25832006-05-17 14:56:04 +0000970 from time import sleep
Guido van Rossumb241b671998-12-04 16:42:46 +0000971 demo()
Georg Brandle3a25832006-05-17 14:56:04 +0000972 sleep(3)
973 demo2()
974 done()