我承认我激动了,居然刚发现python从2.5版本开始就自带了turtle这个模块。一见到这个久违了的名字,记忆就像一双大手,把我一下拽回那个属于童年的翡翠梦境。
本文就带各位看官在梦境中走一遭,示范如何使用python3提供的turtle模块进行七巧板拼图。
什么是小海龟?
话说了这么多,到底啥是小海龟?其实小海龟是国外用来启蒙青少年学习计算机的经典案例,源自一门名为Logo的专用语言。通过简单的指令,就可以操纵画板上的小海龟前进后退,左右转向。屏幕上的小海龟就是小朋友手中的画笔,能够在屏幕上绘制出各种各样的图形,通过所见即所得的方式激发小朋友们学习计算机的热情,算是寓教于乐的绝佳样板。
中西合璧的应用竞赛
回想起来很幸运,1999年我有幸代表无锡参加了在上海市少年宫举办的第三届全国少儿计算机应用竞赛。比赛一共分为两个项目,一项是使用windows95系统下自带的画图软件制作小报,美观者胜;另一项就是使用Logo语言在规定时间内绘制各种七巧板,根据完成数量判定胜负。
在那个486刚刚流行的年代,为了响应邓小平“教育要从娃娃抓起”的号召,一些有识之士及时把计算机相关教育引入国内,并组织发起一系列比赛,包括上文提到的全国少儿计算机应用竞赛。印象特别深刻的是除了我参加的这两个项目之外,大赛还开设了诸如机器人走迷宫之类的项目:娃娃们把机器人放在迷宫入口,机器人就开始跌跌撞撞地寻找出口。这在现在都算是相当超前的计算机早教了吧。
比赛结束之后还有大巴载着我们去参观计算机博物馆,给娃娃们展览那一系列梦境之源:8086系列芯片。那个年纪的我仅仅知道这些就是传说中计算机的大脑,但是它到底是怎么运作的?无论如何,这个问题已经悄然为我日后的生
活埋下了一条重要的主线。
重温经典
为了向Logo语言致敬,我将在使用python3的turtle模块时尽量模拟Logo环境,包括:
- 放弃python3提供的面向对象的编程范式而使用过程式范式
- 通过设置
turtle.mode('logo')
使用Logo定义的默认方向
- 0代表正北方
- 90代表正东方
- 180代表正南方
- 270代表正西方
听我指挥
要让小海龟动起来,第一步当然是基础的移动指令和转向指令:
- 前进
turtle.forward(distance)
或者turtle.fd(distance)
- 后退
turtle.backward(distance)
或者turtle.back(distance)
- 向左转
turtle.left(degree)
- 向右转
turtle.right(degree)
- 也可以直接设置小海龟的朝向
turtle.setheading(degree)
通过调用这些最基础的指令就能在画布上画出一个基本的正方形了。
1 2 3 4 5 6 7 8 9 10 11 12
| import turtle
turtle.mode('logo') turtle.home()
for i in range(4): turtle.forward(100) turtle.right(90)
if __name__=='__main__': turtle.exitonclick()
|
效果如下图:
五颜六色
如果只是画出形状岂不是太单调了,五颜六色的世界才能吸引孩子们的眼球。turtle提供两条指令来进行颜色控制:
- 设置画笔颜色
turtle.pencolor(color_string)
- 设置填充颜色
turtle.fillcolor(color_string)
- 或者同时设置画笔颜色和填充颜色
turtle.color(pencolor, fillcolor)
如果要给一个形状填充颜色,需要调用begin_fill和end_fill方法。以下代码示范了如何在画布上画出一个红色的正三角。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import turtle
turtle.mode('logo') turtle.home() turtle.color('red', 'red') turtle.setheading(30)
turtle.begin_fill() for i in range(3): turtle.forward(100) turtle.right(120) turtle.end_fill()
if __name__=='__main__': turtle.exitonclick()
|
效果如下图:
过程化
过程化编程是一种为了提高代码可复用性而将代码组织成一个个可重复调用过程的编程范式,在七巧板这个案例中,我们可以为每一块七巧板定义一个专用的过程,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
| ''' filename: tangrams.py Define procedures for each tangram. ''' import turtle
turtle.mode('logo')
SMALL_LENGTH = 100 MIDDLE_LENGTH = round(SMALL_LENGTH * (2 ** 0.5), 2) LARGE_LENGTH = SMALL_LENGTH * 2 LARGEST_LENGTH = round(2 * SMALL_LENGTH * (2 ** 0.5), 2)
COLOR_LARGE_TRIANGLE_1 = '#99FF00' COLOR_LARGE_TRIANGLE_2 = '#FF3300' COLOR_MIDDLE_TRIANGLE = '#0033FF' COLOR_SMALL_TRIANGLE_1 = '#FF66FF' COLOR_SMALL_TRIANGLE_2 = '#6600CC' COLOR_SQUARE = '#FFFF33' COLOR_TRAPEZOID = '#CCCCCC'
def base_triangle(side_length, color): turtle.color(color, color) turtle.begin_fill() turtle.fd(side_length) turtle.right(135) turtle.fd(round(side_length * (2 ** 0.5), 2)) turtle.right(135) turtle.fd(side_length) turtle.right(90) turtle.end_fill()
def base_square(side_length, color): turtle.color(color, color) turtle.begin_fill()
for i in range(4): turtle.fd(side_length) turtle.right(90) turtle.end_fill()
def base_trapezoid(side_length, color, direction='left'): turtle.color(color, color) turtle.begin_fill()
turtle.fd(round(side_length * (2 ** 0.5), 2)) if direction=='left': turtle.left(45) else: turtle.right(45) turtle.fd(side_length) if direction=='left': turtle.left(135) else: turtle.right(135) turtle.fd(round(side_length * (2 ** 0.5), 2)) if direction=='left': turtle.left(45) else: turtle.right(45) turtle.fd(side_length) if direction=='left': turtle.left(135) else: turtle.right(135) turtle.end_fill()
def move(distance): turtle.penup() turtle.fd(distance) turtle.pendown()
def right(degree): turtle.right(degree)
def left(degree): turtle.left(degree)
def end(): turtle.hideturtle() turtle.exitonclick()
def large_triangle_1(): base_triangle(LARGE_LENGTH, COLOR_LARGE_TRIANGLE_1)
def large_triangle_2(): base_triangle(LARGE_LENGTH, COLOR_LARGE_TRIANGLE_2)
def small_triangle_1(): base_triangle(SMALL_LENGTH, COLOR_SMALL_TRIANGLE_1)
def small_triangle_2(): base_triangle(SMALL_LENGTH, COLOR_SMALL_TRIANGLE_2)
def middle_triangle(): base_triangle(MIDDLE_LENGTH, COLOR_MIDDLE_TRIANGLE)
def square(): base_square(SMALL_LENGTH, COLOR_SQUARE)
def trapezoid(direction): base_trapezoid(SMALL_LENGTH, COLOR_TRAPEZOID, direction)
if __name__=='__main__': left(45) square() right(90) large_triangle_1() right(90) large_triangle_2() right(90) small_triangle_1() move(SMALL_LENGTH*2) right(135) trapezoid('right') move(LARGEST_LENGTH) right(90) middle_triangle() move(MIDDLE_LENGTH) right(45) move(SMALL_LENGTH) right(180) small_triangle_2() end()
|
如果单独运行上面的代码文件,可以得到如下的七巧板图案:
来拼七巧板吧!
通过在你自己的代码中引入上面的模块,看官们就可以自己来绘制任意七巧板图形啦,比如我们用下面的代码来拼一个阿拉伯数字1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import turtle from tangrams import *
left(45) square()
move(SMALL_LENGTH) right(90) move(SMALL_LENGTH) small_triangle_1()
right(90) move(SMALL_LENGTH) left(135) trapezoid('right')
left(135) move(SMALL_LENGTH) right(180) large_triangle_1()
right(90) move(LARGE_LENGTH) right(90) large_triangle_2()
move(SMALL_LENGTH) right(180) small_triangle_2()
right(90) middle_triangle()
end()
|
效果如下图:
接下来就请有兴趣的看官自由发挥,实现下图中的其他阿拉伯数字吧:
写在最后
Logo语言之所以能够作为一门教育专用语言受到孩子们的青睐,源于它抓住了画图这个切入口,在吸引孩子们动手画画的同时,潜移默化地为孩子们启蒙了二位坐标系,角度,方向等一系列几何概念。
时至今日,我尤其感激当年发起少儿计算机应用竞赛的前辈们。当时比赛的两个项目暗中契合了如今计算机在我们日常生活中通过提供计算能力所提供的主流应用场景:
- 感知延伸
所有在线展示环境(web网页/视频站点/音乐网站以及集大成者游戏),都借由计算机拓展了我们的感知系统,提升的是我们接触获取信息的效率。
- 建模
通用计算机通过执行内存中的程序来模拟人类活动,越来越多的流程被移植到计算平台上来执行,以利用计算机稳定/高速的特点,提升的是处理信息本身的效率。
更快地获取信息加上更快地处理信息,我们离奇点越来越近。
参考资料
- Logo语言
- 七巧板 - 维基百科,自由的百科全书
- 过程式编程 - 维基百科,自由的百科全书
- 24.1. turtle — Turtle graphics — Python 3.6.3rc1 documentation