用Python海龟画一棵会‘生长’的树:从科赫雪花到分形二叉树的保姆级教程
用Python海龟画一棵会“生长”的树:从科赫雪花到分形二叉树的保姆级教程
看着屏幕上由代码生成的树木逐渐“生长”出来,仿佛能感受到数字世界里的生命力。这种将数学规律转化为视觉艺术的过程,正是编程与创意结合的迷人之处。今天,我们就用Python的turtle模块,从最基础的分形概念出发,一步步创造属于你自己的数字森林。
1. 准备工作:理解分形与递归
分形是大自然的几何语言。仔细观察一片雪花、一棵树或一段海岸线,你会发现它们的局部与整体有着惊人的相似性——这就是分形的核心特征:自相似性。数学家芒德布罗在20世纪70年代系统性地提出了分形理论,为我们理解这些复杂形态提供了工具。
递归则是实现分形的编程利器。简单来说,递归就是“自己调用自己”的过程。想象一下俄罗斯套娃:每个套娃内部都包含一个更小的、结构相同的套娃。在编程中,递归函数通过不断调用自身来解决问题,直到满足某个终止条件。
分形与递归的经典组合:
- 科赫雪花:通过无限细分三角形边来模拟雪花
- 分形树:通过重复分支模式模拟植物生长
- 曼德勃罗集:通过简单公式迭代产生无限复杂的图案
2. 搭建基础:科赫雪花的绘制
让我们从经典的科赫雪花开始热身。这个看似复杂的图形,其实只需要几行递归代码就能实现。
2.1 科赫曲线的构建原理
科赫曲线的生成遵循一个简单的规则:
- 画一条直线(0阶)
- 将线段三等分,用等边三角形的两边替换中间段(1阶)
- 对每个新线段重复步骤2(n阶)
import turtle
def koch_curve(length, depth):
if depth == 0:
turtle.forward(length)
else:
koch_curve(length/3, depth-1)
turtle.left(60)
koch_curve(length/3, depth-1)
turtle.right(120)
koch_curve(length/3, depth-1)
turtle.left(60)
koch_curve(length/3, depth-1)
2.2 从曲线到雪花
将三条科赫曲线以等边三角形的方式组合,就得到了科赫雪花:
def draw_koch_snowflake():
turtle.speed(0)
turtle.penup()
turtle.goto(-150, 90)
turtle.pendown()
for _ in range(3):
koch_curve(300, 4)
turtle.right(120)
turtle.hideturtle()
turtle.done()
运行这段代码,你会看到一个精致的雪花图案逐渐在屏幕上展开。尝试调整depth参数(比如从2到5),观察不同迭代次数下图形的变化。
3. 进阶挑战:分形二叉树的实现
掌握了科赫雪花后,我们来创造更有生命感的图形——会“生长”的树。
3.1 基础分形树
最基本的二叉树遵循这样的递归规则:
- 画主干(向前移动)
- 向右转一定角度,画右侧分支(缩短长度)
- 向左转两倍角度,画左侧分支(缩短长度)
- 重复直到分支长度小于阈值
def draw_tree(branch_len, angle):
if branch_len > 5:
turtle.forward(branch_len)
turtle.right(angle)
draw_tree(branch_len * 0.7, angle)
turtle.left(angle * 2)
draw_tree(branch_len * 0.7, angle)
turtle.right(angle)
turtle.backward(branch_len)
3.2 让树更逼真
基础版本虽然正确,但看起来有些机械。我们可以通过以下改进增加真实感:
树干粗细变化:
def draw_tree(branch_len, angle, pen_size):
turtle.pensize(pen_size)
if branch_len > 5:
turtle.forward(branch_len)
turtle.right(angle)
draw_tree(branch_len * 0.7, angle, pen_size * 0.8)
turtle.left(angle * 2)
draw_tree(branch_len * 0.7, angle, pen_size * 0.8)
turtle.right(angle)
turtle.backward(branch_len)
添加树叶效果:
def draw_tree(branch_len, angle, pen_size):
turtle.pensize(pen_size)
if branch_len > 5:
# 树干和树枝为棕色
turtle.pencolor("brown")
turtle.forward(branch_len)
# 右分支
turtle.right(angle)
draw_tree(branch_len * 0.7, angle, pen_size * 0.8)
# 左分支
turtle.left(angle * 2)
draw_tree(branch_len * 0.7, angle, pen_size * 0.8)
# 小分支画成绿色(树叶)
if branch_len < 15:
turtle.pencolor("green")
turtle.pensize(3)
turtle.right(angle)
turtle.backward(branch_len)
4. 注入生命力:随机性与自然感
真正的树木不会完全对称。通过引入随机性,我们可以让数字树更加自然。
4.1 添加随机扰动
import random
def draw_tree(branch_len, angle, pen_size):
turtle.pensize(pen_size)
if branch_len > 5:
# 添加长度随机变化(±10%)
actual_len = branch_len * random.uniform(0.9, 1.1)
turtle.forward(actual_len)
# 添加角度随机变化(±30%)
right_angle = angle * random.uniform(0.7, 1.3)
turtle.right(right_angle)
draw_tree(branch_len * 0.7, angle, pen_size * 0.8)
left_angle = angle * random.uniform(0.7, 1.3) * 2
turtle.left(left_angle)
draw_tree(branch_len * 0.7, angle, pen_size * 0.8)
turtle.right(right_angle)
turtle.backward(actual_len)
4.2 季节变化效果
通过修改颜色,我们可以模拟不同季节的树木:
def set_seasonal_color(branch_len, season):
if branch_len < 15: # 树叶
if season == "spring":
turtle.pencolor("#7CFC00") # 嫩绿
elif season == "summer":
turtle.pencolor("#228B22") # 深绿
elif season == "autumn":
turtle.pencolor(random.choice(["#FFA500", "#FF4500", "#FFD700"])) # 橙/红/金
else: # winter
turtle.pencolor("#A9A9A9") # 灰色
else: # 树干
turtle.pencolor("#8B4513") # 棕色
5. 创意扩展:打造你的数字森林
掌握了基本技术后,让我们发挥创意,创造更丰富的视觉效果。
5.1 多棵树组合
def draw_forest():
turtle.speed(0)
turtle.left(90)
turtle.penup()
positions = [(-200, -100), (0, -100), (200, -100)]
sizes = [80, 120, 100]
for pos, size in zip(positions, sizes):
turtle.goto(pos)
turtle.pendown()
draw_tree(size, 20, size/15)
turtle.penup()
turtle.hideturtle()
turtle.done()
5.2 添加环境元素
def draw_environment():
# 画地面
turtle.pencolor("green")
turtle.penup()
turtle.goto(-400, -100)
turtle.pendown()
turtle.begin_fill()
for _ in range(2):
turtle.forward(800)
turtle.right(90)
turtle.forward(50)
turtle.right(90)
turtle.end_fill()
# 画太阳
turtle.penup()
turtle.goto(300, 200)
turtle.pendown()
turtle.pencolor("yellow")
turtle.fillcolor("yellow")
turtle.begin_fill()
turtle.circle(50)
turtle.end_fill()
5.3 交互式树木生长
让用户控制树木的生长过程:
def interactive_tree():
depth = turtle.numinput("分形树", "请输入递归深度(3-7):", default=5, minval=3, maxval=7)
angle = turtle.numinput("分形树", "请输入分支角度(15-45):", default=25, minval=15, maxval=45)
turtle.speed(0)
turtle.left(90)
turtle.penup()
turtle.backward(200)
turtle.pendown()
draw_tree(150, angle, 10)
turtle.done()
在探索这些代码时,我常常被递归的魔力所震撼——简单的规则通过不断自我引用,竟能创造出如此复杂的自然形态。记得第一次成功运行分形树代码时,那种看着数字枝条在屏幕上“生长”的喜悦至今难忘。编程不仅是解决问题的工具,更可以成为表达创意的画布。
更多推荐
所有评论(0)