本篇主要是討論用 python 模擬自然界的雪花結晶形狀, (注意: 非網路上常提到的 雪花算法).
“Talk is cheap. Show me the code.”
― Linus Torvalds
老子第41章
上德若谷
大白若辱
大方無隅
大器晚成
大音希聲
大象無形
道隱無名
拳打千遍, 身法自然
“There’s no shortage of remarkable ideas, what’s missing is the will to execute them.” – Seth Godin
「很棒的點子永遠不會匱乏,然而缺少的是執行點子的意志力。」—賽斯.高汀
本系列文章之連結
-
從turtle海龜動畫學習Python-高中彈性課程1 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 2 安裝 Python, 線上執行 Python link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 3 烏龜繪圖 所需之Python基礎 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 4 烏龜開始畫圖 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 5 用函數封裝重複性指令-呼叫函數令烏龜畫正 n 邊形 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 6 畫多重旋轉圓,螺旋正方形 link
-
從turtle海龜動畫 學習 Python - 7 遞歸 recursive - 高中彈性課程系列 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 8 碎形 (分形 fractal) link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 8.1 碎形 L-system link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 9 Python 物件導向介紹 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 9.1 Python 物件導向的練習 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 10 藝術畫 自定義海龜形狀 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 10.1 藝術畫 python繪製天然雪花結晶 https://blog.csdn.net/m0_47985483/article/details/122262036 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 10.2 藝術畫 Python 製作生成式藝術 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 11.1 氣泡排序 - 用 turtle 呈現演算法之執行動作 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 11.2 maze 迷宮 - 用 turtle 呈現演算法之執行動作 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 11.3 連分數演算法與轉轉相除法- 用 turtle 呈現演算法之執行動作 link
-
從turtle海龜動畫 學習 Python - 高中彈性課程系列 11.4 最短路徑 Dijkstra- 用 turtle 呈現演算法之執行動作 link
本篇主要是討論用 python 模擬自然界的雪花結晶形狀, (注意: 非網路上常提到的 雪花算法).
樹枝雪花
參考 GeekGurlDiaries 的程式碼
此處我們先參考以下 GeekGurlDiaries YouTube 上影片的程式碼:
Ref: How to make Snowflakes with Code (Xmas Hour of Code Special) link
# Geek Gurl Diaries Episode 33: Xmas Special Make Snowflakes with Turtle
# By Carrie Anne Philbin
# https://www.youtube.com/watch?v=DHmeX7YTHBY
import turtle
import random
# setup the window with a background colour
wn = turtle.Screen()
wn.bgcolor("cyan")
# assign a name to your turtle
elsa = turtle.Turtle()
elsa.speed(15)
# create a list of colours
sfcolor = ["white", "blue", "purple", "grey", "magenta"]
# create a function to create different size snowflakes
def snowflake(size):
# move the pen into starting position
elsa.penup()
elsa.forward(10*size)
elsa.left(45)
elsa.pendown()
elsa.color(random.choice(sfcolor))
# draw branch 8 times to make a snowflake
for i in range(8):
branch(size)
elsa.left(45)
# create one branch of the snowflake
def branch(size):
for i in range(3):
for i in range(3):
elsa.forward(10.0*size/3)
elsa.backward(10.0*size/3)
elsa.right(45)
elsa.left(90)
elsa.backward(10.0*size/3)
elsa.left(45)
elsa.right(90)
elsa.forward(10.0*size)
# loop to create 20 different sized snowflakes with different starting co-ordinates
for i in range(20):
x = random.randint(-200, 200)
y = random.randint(-200, 200)
sf_size = random.randint(1, 4)
elsa.penup()
elsa.goto(x, y)
elsa.pendown()
snowflake(sf_size)
# leave the window open until you click to close
wn.exitonclick()
效果如下:
分解說明
branch()
我們看到, 主要是透過 branch()
繪製每個單一大枝葉,
snowflake()
則是呼叫 branch() 8次, 繪出8個主要枝葉, 間格 45度, 就完成雪花,
我們將程式碼簡化到只剩 branch(), 觀察他的動作
# Geek Gurl Diaries Episode 33: Xmas Special Make Snowflakes with Turtle
# By Carrie Anne Philbin
# https://www.youtube.com/watch?v=DHmeX7YTHBY
import turtle
wn = turtle.Screen()
# assign a name to your turtle
elsa = turtle.Turtle()
elsa.speed(1)
size = 20
# move the pen into starting position
elsa.penup()
elsa.forward(10*size)
elsa.left(45)
elsa.pendown()
# create one branch of the snowflake
def branch(size):
for i in range(3):
for i in range(3):
elsa.forward(10.0*size/3)
elsa.backward(10.0*size/3)
elsa.right(45)
elsa.left(90)
elsa.backward(10.0*size/3)
elsa.left(45)
elsa.right(90)
elsa.forward(10.0*size)
branch(size)
branch(20)
繪製的效果如下:
branch() 中的小迴圈
branch()
中的小迴圈主要是做畫出三個小分支葉的動作
透過前進再後退, 然後右轉45度, 完成畫出一個小枝,
畫三次小枝, 組成三個小分支葉,
以下是小迴圈 codes:
for i in range(3):
elsa.forward(10.0*size/3)
elsa.backward(10.0*size/3)
elsa.right(45)
以下為完成畫出一個小分枝
每個小迴圈畫出3個小分支,
外迴圈則
重複三次小迴圈,
執行3次小迴圈, 畫出3組3個小分支葉就組成一個大分枝,
就完成整個大分枝的繪製,
branch() 中的大迴圈
以下執行外迴圈, 完成整個大分枝的繪製:
for i in range(3):
for i in range(3):
elsa.forward(10.0*size/3)
elsa.backward(10.0*size/3)
elsa.right(45)
elsa.left(90)
elsa.backward(10.0*size/3)
elsa.left(45)
他的程式碼並不好讀, 需要經常調整海龜轉向, 造成程式碼不好閱讀, 難以立即從閱讀程式碼, 就能推測出畫出的形狀.
snowflake()
snowflake()
則是呼叫8次 branch()
, 完成8個大分枝組成之雪花
最後段: 畫多個隨機位置、大小、顏色之雪花
最後段則是執行20 次呼叫 snowflake()
畫雪花,
每次都重設海龜之 x, y 座標, 隨機選擇, 還有大小也是隨機選擇,
顏色之輪換則是嵌在snowflake()
程式碼內,
可以看得出, 她的程式碼有多處是耦合在一起, 不好閱讀, 也不好維護修改, (許多中小學老師 Python程式能力屬於業餘的水準, 能用 python 做教案, 已經難能可貴了).
# loop to create 20 different sized snowflakes with different starting co-ordinates
for i in range(20):
x = random.randint(-200, 200)
y = random.randint(-200, 200)
sf_size = random.randint(1, 4)
elsa.penup()
elsa.goto(x, y)
elsa.pendown()
snowflake(sf_size)
修改 GeekGurlDiaries 的程式碼
雪花的瓣數確定
我們將程式碼改成較專業, 海龜旋轉角度也用較直觀的方式去設計
如果我們選擇只畫出 6瓣的雪花, 類似大自然的對稱,
只畫一個,
跑出的程式碼如下圖
如果是八瓣, 20個雪花, 則圖如下
# Geek Gurl Diaries Episode 33: Xmas Special Make Snowflakes with Turtle
# By Carrie Anne Philbin
# https://www.youtube.com/watch?v=DHmeX7YTHBY
# Revised by Prof. P-J Lai MATH NKNU 20220102
# snowflake_GeekGurlDiaries_Lai.py
import turtle
import random
# setup the window with a background colour
screen = turtle.Screen()
screen.bgcolor("cyan")
# assign a name to your turtle
T = turtle.Turtle()
T.speed(0)
# create a list of colours
colorList = ["white", "blue", "purple", "grey", "magenta", "green", "yellow"]
# create one branch of the snowflake
def branch(size):
for i in range(3):
T.left(45)
for i in range(3):
T.forward(size/3)
T.backward(size/3)
T.right(45)
T.left(90)
T.backward(size/3)
# create a function to create different size snowflakes
def snowflake(size, x, y, color, petalNumber):
# move the pen into starting position
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
# draw branch petalNumber times to make a snowflake
for i in range(petalNumber):
T.fd(size)
branch(size)
T.left(360/petalNumber)
if __name__ == "__main__":
petalNumber = 8
# loop to create 20 different sized snowflakes with different starting co-ordinates
for i in range(20):
x = random.randint(-200, 200)
y = random.randint(-200, 200)
size = random.randint(10, 50)
snowflake(size, x, y, random.choice(colorList), petalNumber)
#snowflake(100, 0, 0, "purple", petalNumber)
雪花的瓣數也隨機決定
我們修改成, 雪花的瓣數也隨機決定,
從 6, 8, 10, 12 瓣, 隨機決定:
petalNumber = random.choice([6, 8, 10, 12])
# Geek Gurl Diaries Episode 33: Xmas Special Make Snowflakes with Turtle
# By Carrie Anne Philbin
# https://www.youtube.com/watch?v=DHmeX7YTHBY
# Revised by Prof. P-J Lai MATH NKNU 20220102
# snowflake_GeekGurlDiaries_Lai_petal.py
import turtle
import random
# setup the window with a background colour
screen = turtle.Screen()
screen.bgcolor("cyan")
# assign a name to your turtle
T = turtle.Turtle()
T.speed(0)
# create a list of colours
colorList = ["white", "blue", "purple", "grey", "magenta", "green", "yellow"]
# create one branch of the snowflake
def branch(size):
for i in range(3):
T.left(45)
for i in range(3):
T.forward(size/3)
T.backward(size/3)
T.right(45)
T.left(90)
T.backward(size/3)
# create a function to create different size snowflakes
def snowflake(size, x, y, color, petalNumber):
# move the pen into starting position
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
# draw branch petalNumber times to make a snowflake
for i in range(petalNumber):
T.fd(size)
branch(size)
T.left(360/petalNumber)
if __name__ == "__main__":
# petalNumber = 8
# loop to create 20 different sized snowflakes with different starting co-ordinates
for i in range(20):
x = random.randint(-250, 250)
y = random.randint(-250, 250)
size = random.randint(10, 50)
petalNumber = random.choice([6, 8, 10, 12])
snowflake(size, x, y, random.choice(colorList), petalNumber)
#snowflake(100, 0, 0, "purple", petalNumber)
改用 stamp()
蓋印 功能畫雪花
回憶一下本系列第一篇提到 海龜蓋印 功能:
可以使用 stamp()
指令, 在當下海龜該地點留下一個與海龜當下形狀一模一樣的海龜圖形(像蓋章的效果), 會有一個id指定,
clearstamp(id)
# 將編號為id之蓋章消除
clearstamps()
刪除全部 stamp,
clearstamps( n )
刪除前 n 個 stamp
參考本系列第一篇: 從turtle海龜動畫學習Python-高中彈性課程1, 海龜蓋印 (依照當前的的狀), https://blog.csdn.net/m0_47985483/article/details/107502070 link
想用 stamp()
功能, 必須先令海龜的形狀是想蓋印的形狀, 再使用 stamp() 指令,
此時必須用 自定義海龜形狀 的方法, 樣可以參考本系列第一篇: 從turtle海龜動畫學習Python-高中彈性課程1, 自定義海龜形狀 (依照當前的的狀), 第一種方法 turtle.get_poly() 的方法, 第二個例子, https://blog.csdn.net/m0_47985483/article/details/107502070 link
- 產生單一一個雪花形狀: 可以先用前兩節的 “雪花的瓣數確定”, 的程式碼,
- 再用
get_poly()
,register_shape()
的方法, 定義此雪花為一個新的海龜形狀, 取名為 “myShape”, - 再令當下海龜的形狀是此新的雪花形狀
T.shape("myShape")
以下, 我們先畫出一個雪花形狀,
再用他註冊一個新的海龜形狀: 只要把產生雪花的函數 snowflake()
放在T.begin_poly()
, T.end_poly()
中間就可以,
再用 turtle.register_shape("myShape", T.get_poly())
, 即完成註冊新的海龜形狀,
再將海龜形狀令為此新定義之形狀 “myshape”
T.shape("myShape")
T.begin_poly()
snowflake(40, 0, 0, "red", 8)
T.end_poly()
turtle.register_shape("myShape", T.get_poly())
T.shape("myShape")
複習get_poly()
的方法
流程:
begin_poly()
做動作: 海龜畫出一個多邊形, 或畫一個任意形狀
end_poly()
再用 register_shape() 取名稱註冊成一個形狀, 取名為 “myshape”
register_shape("myshape", get_poly())
- 以下, 我們先畫出一個雪花形狀, 先把
snowflake()
的程式碼寫好. - 只要把產生雪花的函數
snowflake()
放在T.begin_poly()
,T.end_poly()
中間就可以:
T.begin_poly()
snowflake(40, 0, 0, "red", 8)
T.end_poly()
- 再用他註冊一個新的形狀,
turtle.register_shape("myShape", T.get_poly())
- 再令當下海龜的形狀是此新的海龜形狀
T.shape("myShape")
以下是蓋出3個印的結果:
codes:
# -*- coding: utf-8 -*-
# set custom shape 20160617
#Turtle 24.1. Turtle graphics — Python v3.3
# Tested by Prof. P-J Lai MATH NKNU 20210103
##24.1.3.7. Special Turtle methods
##begin_poly()
##end_poly()
##register_shape("myshape",get_poly())
##T.shape("myShape")
##較單純!
##以下測試第二個例子 雪花形狀
##以下, 我們先畫出一個雪花形狀, 再用他註冊一個新的形狀,
##只要把產生雪花的函數 snowflake() 放在T.begin_poly(), T.end_poly() 中間就可以:
# custom_Shape_get_poly()_snow_stamp_4.py
import turtle
T=turtle.Turtle()
turtle.bgcolor("cyan")
T.speed(0)
# create one branch of the snowflake
def branch(size):
for i in range(3):
T.left(45)
for i in range(3):
T.forward(size/3)
T.backward(size/3)
T.right(45)
T.left(90)
T.backward(size/3)
# create a function to create different size snowflakes
def snowflake(size, x, y, color, petalNumber):
# move the pen into starting position
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
# draw branch petalNumber times to make a snowflake
for i in range(petalNumber):
T.fd(size)
branch(size)
T.left(360/petalNumber)
T.home()
T.begin_poly()
snowflake(40, 0, 0, "red", 8)
T.end_poly()
turtle.register_shape("myShape", T.get_poly())
T.shape("myShape")
#T.turtlesize()
T.color('red')
T.forward(200)
T.stamp()
T.left(90)
T.forward(200)
T.stamp()
T.left(90)
T.forward(200)
用 stamp()
蓋印畫雪花, 花瓣數隨機決定
我們用 stamp()
蓋印功能重寫"雪花的瓣數也隨機決定"那份程式碼.
之前是用海龜走過的痕跡畫出雪花, 效能會較慢, 時間較久, 現在試試用蓋印的方式, 看看 效能會不會改善.
結果發現似乎更慢, 原因是, 等於是每次還是用畫的, 只是把畫筆提起, 再蓋印而已,
應該是當海龜量大時, 先畫出幾個海龜雪花原型, 再持續用這幾個海龜原型蓋印, 持續畫出雪花, 這樣子, 才有可能提高效能. 後面我們再用這種寫法試試.
# -*- coding: utf-8 -*-
# set custom shape 20160617
#Turtle 24.1. Turtle graphics — Python v3.3
# Tested by Prof. P-J Lai MATH NKNU 20210103
##24.1.3.7. Special Turtle methods
##begin_poly()
##end_poly()
##register_shape("myshape",get_poly())
##T.shape("myShape")
##較單純!
## 我們用 stamp() 蓋印功能重寫"雪花的瓣數也隨機決定"那份程式碼.
##以下, 我們先畫出一個雪花形狀, 再用他註冊一個新的形狀,
##只要把產生雪花的函數 snowflake() 放在T.begin_poly(), T.end_poly() 中間就可以:
# custom_Shape_get_poly()_snow_stamp_petal.py
import turtle
import random
T=turtle.Turtle()
turtle.bgcolor("cyan")
T.speed(0)
# create a list of colours
colorList = ["white", "blue", "purple", "grey", "magenta", "green", "yellow"]
# create one branch of the snowflake
def branch(size):
for i in range(3):
T.left(45)
for i in range(3):
T.forward(size/3)
T.backward(size/3)
T.right(45)
T.left(90)
T.backward(size/3)
# create a function to create different size snowflakes
def snowflake(size, x, y, color, petalNumber):
# move the pen into starting position
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
# draw branch petalNumber times to make a snowflake
for i in range(petalNumber):
T.fd(size)
branch(size)
T.left(360/petalNumber)
def snowflakeStamp(size, x, y, color, petalNumber):
# move the pen into starting position
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
# draw a snowflake by stamp()
#T.home()
T.begin_poly()
snowflake(size, x, y, color, petalNumber)
T.end_poly()
turtle.register_shape("myShape", T.get_poly())
T.shape("myShape")
T.stamp()
if __name__ == "__main__":
# loop to create 20 different sized snowflakes with different starting co-ordinates
for i in range(20):
x = random.randint(-250, 250)
y = random.randint(-250, 250)
size = random.randint(10, 50)
petalNumber = random.choice([6, 8, 10, 12])
snowflakeStamp(size, x, y, random.choice(colorList), petalNumber)
用 stamp()
蓋印畫雪花, 花瓣數隨機決定 調整效能
# -*- coding: utf-8 -*-
# set custom shape 20160617
#Turtle 24.1. Turtle graphics — Python v3.3
# Tested by Prof. P-J Lai MATH NKNU 20210103
##24.1.3.7. Special Turtle methods
##begin_poly()
##end_poly()
##register_shape("myshape",get_poly())
##T.shape("myShape")
##較單純!
## 我們用 stamp() 蓋印功能重寫"雪花的瓣數也隨機決定"那份程式碼.
##以下, 我們先畫出一個雪花形狀, 再用他註冊一個新的形狀,
##只要把產生雪花的函數 snowflake() 放在T.begin_poly(), T.end_poly() 中間就可以:
# custom_Shape_get_poly()_snow_stamp_petal_fast.py
import turtle
import random
T=turtle.Turtle()
turtle.bgcolor("cyan")
T.speed(0)
# create a list of colours
colorList = ["white", "blue", "purple", "grey", "magenta", "green", "yellow"]
# create one branch of the snowflake
def branch(size):
for i in range(3):
T.left(45)
for i in range(3):
T.forward(size/3)
T.backward(size/3)
T.right(45)
T.left(90)
T.backward(size/3)
# create a function to create different size snowflakes
def snowflake(size, x, y, color, petalNumber):
# move the pen into starting position
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
# draw branch petalNumber times to make a snowflake
for i in range(petalNumber):
T.fd(size)
branch(size)
T.left(360/petalNumber)
def snowflakeRegister(shapeName, size, x, y, color, petalNumber):
# move the pen into starting position
#T.hideturtle()
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
# draw a snowflake by stamp()
#T.home()
T.begin_poly()
snowflake(size, x, y, color, petalNumber)
T.end_poly()
turtle.register_shape(shapeName, T.get_poly())
#T.showturtle()
if __name__ == "__main__":
# loop to create 20 different sized snowflakes with different starting co-ordinates
numberTurtleShape = 5
shapeName = []
for i in range(numberTurtleShape):
petalNumber = random.choice([6, 8, 10, 12])
shapeName.append("shape" + str(i))
print(shapeName[i])
snowflakeRegister(shapeName[i], 1, 0, 0, random.choice(colorList), petalNumber)
numberTurtle = 50
for i in range(numberTurtleShape):
for j in range(int(numberTurtle/numberTurtleShape)):
print(shapeName[i])
T.shape(shapeName[i])
x = random.randint(-300, 300)
y = random.randint(-300, 300)
size = random.randint(10, 50)
T.penup()
T.goto(x,y)
T.color(random.choice(colorList))
T.pendown()
T.turtlesize(size)
T.stamp()
用 stamp()
蓋印畫雪花, 花瓣數 6,8,10,12,15, 調整效能
# -*- coding: utf-8 -*-
# set custom shape 20160617
#Turtle 24.1. Turtle graphics — Python v3.3
# Tested by Prof. P-J Lai MATH NKNU 20210103
##24.1.3.7. Special Turtle methods
##begin_poly()
##end_poly()
##register_shape("myshape",get_poly())
##T.shape("myShape")
##較單純!
## 我們用 stamp() 蓋印功能重寫"雪花的瓣數也隨機決定"那份程式碼.
##以下, 我們先畫出一個雪花形狀, 再用他註冊一個新的形狀,
##只要把產生雪花的函數 snowflake() 放在T.begin_poly(), T.end_poly() 中間就可以:
# 將 custom_Shape_get_poly()_snow_stamp_petal_fast.py 修改為
# custom_Shape_get_poly()_snow_stamp_petal_fast1.py
# 修改先產生幾個海龜形狀, 顏色大小不用特別指定,
# petal number 只照 6,8,10,12,15 等做,
# 也就是只做出 5 種 雪花原形
# 等到蓋印那時, 再調整形狀, 顏色大小
import turtle
import random
T=turtle.Turtle()
turtle.bgcolor("cyan")
T.speed(0)
# create a list of colours
colorList = ["white", "blue", "purple", "grey", "magenta", "green", "yellow"]
# create one branch of the snowflake
def branch(size):
for i in range(3):
T.left(45)
for i in range(3):
T.forward(size/3)
T.backward(size/3)
T.right(45)
T.left(90)
T.backward(size/3)
# create a function to create different size snowflakes
def snowflake(size, x, y, color, petalNumber):
# move the pen into starting position
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
# draw branch petalNumber times to make a snowflake
for i in range(petalNumber):
T.fd(size)
branch(size)
T.left(360/petalNumber)
# add new shape
def snowflakeRegister(shapeName, size, x, y, color, petalNumber):
# move the pen into starting position
#T.hideturtle()
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
T.begin_poly()
snowflake(size, x, y, color, petalNumber)
T.end_poly()
turtle.register_shape(shapeName, T.get_poly())
#T.showturtle()
if __name__ == "__main__":
# loop to create numberTurtle different sized snowflakes with different starting co-ordinates
numberTurtleShape = 5
shapeName = []
# 改成 petal number 只照 6,8,10,12,15 等做,
# 也就是只做出 5 種 雪花原形
petalList = [6, 8, 10, 12, 15]
petalNumber = len(petalList)
for i in range(petalNumber):
shapeName.append("shape" + str(i))
print(shapeName[i])
snowflakeRegister(shapeName[i], 1, 0, 0, "black", petalList[i])
numberTurtle = 50
for i in range(numberTurtleShape):
for j in range(int(numberTurtle/numberTurtleShape)):
print(shapeName[i])
T.shape(shapeName[i])
x = random.randint(-300, 300)
y = random.randint(-300, 300)
size = random.randint(10, 50)
T.penup()
T.goto(x,y)
T.color(random.choice(colorList))
T.pendown()
T.turtlesize(size)
T.stamp()
如果我們把隨機位置改成用
x = random.uniform(-350, 350)
y = random.uniform(-350, 350)
則位置會較分布均勻.
雪花結晶從上方落下, 花瓣數 6,8,10,12,15, 不用 stamp()
以下先嘗試雪花結晶單純從上方落下, 類似紫雨落下,
# -*- coding: utf-8 -*-
# set custom shape 20160617
#Turtle 24.1. Turtle graphics — Python v3.3
# Tested by Prof. P-J Lai MATH NKNU 20210103
##24.1.3.7. Special Turtle methods
##begin_poly()
##end_poly()
##register_shape("myshape",get_poly())
##T.shape("myShape")
##較單純!
## 我們用 stamp() 蓋印功能重寫"雪花的瓣數也隨機決定"那份程式碼.
##以下, 我們先畫出一個雪花形狀, 再用他註冊一個新的形狀,
##只要把產生雪花的函數 snowflake() 放在T.begin_poly(), T.end_poly() 中間就可以:
# 將 custom_Shape_get_poly()_snow_stamp_petal_fast1.py 修改為
# custom_Shape_get_poly()_snow_stamp_petal_fast2_fall
# 修改雪花結晶落下
# 不使用stamp(), 直接用海龜落下
import turtle
import random
#turtle.tracer(20,1)
#turtle.speed(0.1)
T=turtle.Turtle()
turtle.bgcolor("cyan")
T.speed(0)
# create a list of colours
colorList = ["white", "blue", "purple", "grey", "magenta", "green", "yellow"]
# create one branch of the snowflake
def branch(size):
for i in range(3):
T.left(45)
for i in range(3):
T.forward(size/3)
T.backward(size/3)
T.right(45)
T.left(90)
T.backward(size/3)
# create a function to create different size snowflakes
def snowflake(size, x, y, color, petalNumber):
# move the pen into starting position
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
# draw branch petalNumber times to make a snowflake
for i in range(petalNumber):
T.fd(size)
branch(size)
T.left(360/petalNumber)
# add new shape
def snowflakeRegister(shapeName, size, x, y, color, petalNumber):
# move the pen into starting position
#T.hideturtle()
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
T.begin_poly()
snowflake(size, x, y, color, petalNumber)
T.end_poly()
turtle.register_shape(shapeName, T.get_poly())
#T.showturtle()
if __name__ == "__main__":
# loop to create numberTurtle different sized snowflakes with different starting co-ordinates
numberTurtleShape = 5
shapeName = []
# 改成 petal number 只照 6,8,10,12,15 等做,
# 也就是只做出 5 種 雪花原形
petalList = [6, 8, 10, 12, 15]
petalNumber = len(petalList)
for i in range(petalNumber):
shapeName.append("shape" + str(i))
print(shapeName[i])
snowflakeRegister(shapeName[i], 1, 0, 0, "black", petalList[i])
# snow crystal falling
numberTurtle = 10
turtleList = []
turtleIndex = 0
for i in range(numberTurtleShape):
for j in range(int(numberTurtle/numberTurtleShape)):
turtleList.append( turtle.Turtle())
print(shapeName[i])
turtleList[turtleIndex].shape(shapeName[i])
#turtleList[turtleIndex].ht()
turtleList[turtleIndex].penup()
x = random.uniform(-350, 350)
y = 350 + random.uniform(-50, 50)
#y = random.uniform(-350, 350)
size = random.randint(10, 30)
turtleList[turtleIndex].color(random.random(), random.random(),random.random())
turtleList[turtleIndex].turtlesize(size)
turtleList[turtleIndex].rt(90)
turtleList[turtleIndex].speed(0)
turtleList[turtleIndex].penup()
turtleList[turtleIndex].goto(x,y)
turtleIndex += 1
# 每隻海龜輪流動一小段, 造成一起移動的效果
turtle.tracer(2,10)
for k in range(int(700/2)):
for i in range(numberTurtle):
turtleList[i].fd(2)
使用 while 雪花結晶持續從上方落下
# -*- coding: utf-8 -*-
# set custom shape 20160617
#Turtle 24.1. Turtle graphics — Python v3.3
# Tested by Prof. P-J Lai MATH NKNU 20210103
##24.1.3.7. Special Turtle methods
##begin_poly()
##end_poly()
##register_shape("myshape",get_poly())
##T.shape("myShape")
##較單純!
## 我們用 stamp() 蓋印功能重寫"雪花的瓣數也隨機決定"那份程式碼.
##以下, 我們先畫出一個雪花形狀, 再用他註冊一個新的形狀,
##只要把產生雪花的函數 snowflake() 放在T.begin_poly(), T.end_poly() 中間就可以:
# 將 custom_Shape_get_poly()_snow_stamp_petal_fast3_fall.py 修改為
# custom_Shape_get_poly()_snow_stamp_petal_fast3_fall_while.py
# 使用 while 持續雪花結晶從上方落下
import turtle
import random
#turtle.tracer(20,1)
#turtle.speed(0.1)
T=turtle.Turtle()
turtle.bgcolor("cyan")
T.speed(0)
# create a list of colours
colorList = ["white", "blue", "purple", "grey", "magenta", "green", "yellow"]
# create one branch of the snowflake
def branch(size):
for i in range(3):
T.left(45)
for i in range(3):
T.forward(size/3)
T.backward(size/3)
T.right(45)
T.left(90)
T.backward(size/3)
# create a function to create different size snowflakes
def snowflake(size, x, y, color, petalNumber):
# move the pen into starting position
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
# draw branch petalNumber times to make a snowflake
for i in range(petalNumber):
T.fd(size)
branch(size)
T.left(360/petalNumber)
# add new shape
def snowflakeRegister(shapeName, size, x, y, color, petalNumber):
# move the pen into starting position
#T.hideturtle()
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
T.begin_poly()
snowflake(size, x, y, color, petalNumber)
T.end_poly()
turtle.register_shape(shapeName, T.get_poly())
#T.showturtle()
if __name__ == "__main__":
# loop to create numberTurtle different sized snowflakes with different starting co-ordinates
numberTurtleShape = 5
shapeName = []
# 改成 petal number 只照 6,8,10,12,15 等做,
# 也就是只做出 5 種 雪花原形
petalList = [6, 8, 10, 12, 15]
petalNumber = len(petalList)
for i in range(petalNumber):
shapeName.append("shape" + str(i))
print(shapeName[i])
snowflakeRegister(shapeName[i], 1, 0, 0, "black", petalList[i])
# snow crystal falling
numberTurtle = 10
turtleList = []
turtleIndex = 0
for i in range(numberTurtleShape):
for j in range(int(numberTurtle/numberTurtleShape)):
turtleList.append( turtle.Turtle())
print(shapeName[i])
turtleList[turtleIndex].shape(shapeName[i])
#turtleList[turtleIndex].ht()
turtleList[turtleIndex].penup()
x = random.uniform(-350, 350)
y = 1000 + random.uniform(-350, 350)
#y = random.uniform(-350, 350)
size = random.randint(10, 30)
turtleList[turtleIndex].color(random.random(), random.random(),random.random())
turtleList[turtleIndex].turtlesize(size)
turtleList[turtleIndex].rt(90)
turtleList[turtleIndex].speed(0)
turtleList[turtleIndex].penup()
turtleList[turtleIndex].goto(x,y)
turtleIndex += 1
# 每隻海龜輪流動一小段, 造成一起移動的效果
turtle.tracer(2,10)
while True:
for k in range(int(700/2)):
for i in range(numberTurtle):
turtleList[i].fd(2)
if turtleList[i].ycor()< -400:
turtleList[i].goto(random.uniform(-350, 350), 400 + random.uniform(-50, 50))
底下程式碼稍微修改, 以提升效果:
使用 turtle.tracer(0,0)
, 讓一開始畫出雪花自定義海龜形狀的階段, 讓動畫不顯示出來, 以加快速度.
並且使用 turtel.clearscreen()
, 將畫出之形狀抹去清除, 避免在畫布中央留下一個不明所以的大圖點.
在後段, 每個雪花開始要飄落前, 再改成 turtle.tracer(20,10)
, 讓動畫顯示, 每20 幅才呈現一次, 間格 10 微秒.
海龜數量改成 50 隻
每次雪花飄落到底再跳躍到畫布上方, 之隨機範圍加大, 以免海龜過度集中
turtleList[i].goto(random.uniform(-350, 350), 400 + random.uniform(-100, 100))
調整之後的效果如下
# -*- coding: utf-8 -*-
# set custom shape 20160617
#Turtle 24.1. Turtle graphics — Python v3.3
# Tested by Prof. P-J Lai MATH NKNU 20210103
##24.1.3.7. Special Turtle methods
##begin_poly()
##end_poly()
##register_shape("myshape",get_poly())
##T.shape("myShape")
##較單純!
## 我們用 stamp() 蓋印功能重寫"雪花的瓣數也隨機決定"那份程式碼.
##以下, 我們先畫出一個雪花形狀, 再用他註冊一個新的形狀,
##只要把產生雪花的函數 snowflake() 放在T.begin_poly(), T.end_poly() 中間就可以:
# 將 custom_Shape_get_poly()_snow_stamp_petal_fast3_fall.py 修改為
# custom_Shape_get_poly()_snow_stamp_petal_fast3_fall_while.py
# 使用 while 持續雪花結晶從上方落下
import turtle
import random
sc = turtle.Screen()
#turtle.tracer(20,1)
#turtle.speed(0.1)
T=turtle.Turtle()
T.hideturtle()
#T.fd(500)
turtle.bgcolor("cyan")
T.speed(0)
# create a list of colours
colorList = ["white", "blue", "purple", "grey", "magenta", "green", "yellow"]
# create one branch of the snowflake
def branch(size):
for i in range(3):
T.left(45)
for i in range(3):
T.forward(size/3)
T.backward(size/3)
T.right(45)
T.left(90)
T.backward(size/3)
# create a function to create different size snowflakes
def snowflake(size, x, y, color, petalNumber):
# move the pen into starting position
T.penup()
T.goto(x,y)
T.color(color)
T.ht()
T.pendown()
# draw branch petalNumber times to make a snowflake
for i in range(petalNumber):
T.fd(size)
branch(size)
T.left(360/petalNumber)
# add new shape
def snowflakeRegister(shapeName, size, x, y, color, petalNumber):
# move the pen into starting position
#T.hideturtle()
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
T.begin_poly()
snowflake(size, x, y, color, petalNumber)
T.end_poly()
turtle.register_shape(shapeName, T.get_poly())
#T.showturtle()
if __name__ == "__main__":
# loop to create numberTurtle different sized snowflakes with different starting co-ordinates
numberTurtleShape = 5
shapeName = []
# 改成 petal number 只照 6,8,10,12,15 等做,
# 也就是只做出 5 種 雪花原形
petalList = [6, 8, 10, 12, 15]
petalNumber = len(petalList)
#turtle.tracer(0,0)
for i in range(petalNumber):
shapeName.append("shape" + str(i))
print(shapeName[i])
snowflakeRegister(shapeName[i], 5, 0, 0, "black", petalList[i])
turtle.clearscreen()
# snow crystal falling
numberTurtle = 50
turtleList = []
turtleIndex = 0
for i in range(numberTurtleShape):
for j in range(int(numberTurtle/numberTurtleShape)):
turtleList.append( turtle.Turtle())
turtleList[turtleIndex].ht()
print(shapeName[i])
turtleList[turtleIndex].shape(shapeName[i])
#turtleList[turtleIndex].ht()
turtleList[turtleIndex].penup()
x = random.uniform(-350, 350)
y = 1000 + random.uniform(-350, 350)
#y = random.uniform(-350, 350)
size = random.randint(1, 5)
turtleList[turtleIndex].color(random.random(), random.random(),random.random())
turtleList[turtleIndex].turtlesize(size)
turtleList[turtleIndex].rt(90)
turtleList[turtleIndex].speed(0)
turtleList[turtleIndex].penup()
turtleList[turtleIndex].goto(x,y)
turtleList[turtleIndex].st()
turtleIndex += 1
# 每隻海龜輪流動一小段, 造成一起移動的效果
turtle.tracer(20,10)
while True:
for k in range(int(700/2)):
for i in range(numberTurtle):
turtleList[i].fd(2)
if turtleList[i].ycor()< -400:
turtleList[i].goto(random.uniform(-350, 350), 400 + random.uniform(-100, 100))
#sc.exitonclick()
讓雪花結晶旋轉
# -*- coding: utf-8 -*-
# set custom shape 20160617
#Turtle 24.1. Turtle graphics — Python v3.3
# Tested by Prof. P-J Lai MATH NKNU 20210103
##24.1.3.7. Special Turtle methods
##begin_poly()
##end_poly()
##register_shape("myshape",get_poly())
##T.shape("myShape")
##較單純!
## 我們用 stamp() 蓋印功能重寫"雪花的瓣數也隨機決定"那份程式碼.
##以下, 我們先畫出一個雪花形狀, 再用他註冊一個新的形狀,
##只要把產生雪花的函數 snowflake() 放在T.begin_poly(), T.end_poly() 中間就可以:
# 將 custom_Shape_get_poly()_snow_petal_fast3_fall_while.py 修改為
# custom_Shape_get_poly()_snow_petal_fast4_fall_while_rotate.py
# 讓雪花結晶旋轉
import turtle
import random
sc = turtle.Screen()
#turtle.tracer(20,1)
#turtle.speed(0.1)
T=turtle.Turtle()
T.hideturtle()
#T.fd(500)
turtle.bgcolor("cyan")
T.speed(0)
# create a list of colours
colorList = ["white", "blue", "purple", "grey", "magenta", "green", "yellow"]
# create one branch of the snowflake
def branch(size):
for i in range(3):
T.left(45)
for i in range(3):
T.forward(size/3)
T.backward(size/3)
T.right(45)
T.left(90)
T.backward(size/3)
# create a function to create different size snowflakes
def snowflake(size, x, y, color, petalNumber):
# move the pen into starting position
T.penup()
T.goto(x,y)
T.color(color)
T.ht()
T.pendown()
# draw branch petalNumber times to make a snowflake
for i in range(petalNumber):
T.fd(size)
branch(size)
T.left(360/petalNumber)
# add new shape
def snowflakeRegister(shapeName, size, x, y, color, petalNumber):
# move the pen into starting position
#T.hideturtle()
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
T.begin_poly()
snowflake(size, x, y, color, petalNumber)
T.end_poly()
turtle.register_shape(shapeName, T.get_poly())
#T.showturtle()
if __name__ == "__main__":
# loop to create numberTurtle different sized snowflakes with different starting co-ordinates
numberTurtleShape = 5
shapeName = []
# 改成 petal number 只照 6,8,10,12,15 等做,
# 也就是只做出 5 種 雪花原形
petalList = [6, 8, 10, 12, 15]
petalNumber = len(petalList)
#turtle.tracer(0,0)
for i in range(petalNumber):
shapeName.append("shape" + str(i))
print(shapeName[i])
snowflakeRegister(shapeName[i], 5, 0, 0, "black", petalList[i])
turtle.clearscreen()
turtle.bgcolor("black")
# snow crystal falling
numberTurtle = 50
turtleList = []
turtleIndex = 0
for i in range(numberTurtleShape):
for j in range(int(numberTurtle/numberTurtleShape)):
turtleList.append( turtle.Turtle())
turtleList[turtleIndex].ht()
print(shapeName[i])
turtleList[turtleIndex].shape(shapeName[i])
#turtleList[turtleIndex].ht()
turtleList[turtleIndex].penup()
x = random.uniform(-350, 350)
y = 1000 + random.uniform(-350, 350)
#y = random.uniform(-350, 350)
size = random.randint(1, 5)
turtleList[turtleIndex].color(random.random(), random.random(),random.random())
turtleList[turtleIndex].turtlesize(size)
turtleList[turtleIndex].rt(90)
turtleList[turtleIndex].speed(0)
turtleList[turtleIndex].penup()
turtleList[turtleIndex].goto(x,y)
turtleList[turtleIndex].st()
turtleIndex += 1
# 每隻海龜輪流動一小段, 造成一起移動的效果
turtle.tracer(20,10)
while True:
for k in range(int(700/2)):
for i in range(numberTurtle):
turtleList[i].fd(2)
turtleList[i].tilt(2)
if turtleList[i].ycor()< -400:
turtleList[i].goto(random.uniform(-350, 350), 400 + random.uniform(-100, 100))
Ex: 可以修改以上程式碼,
- 讓雪花結晶旋轉, 不需要都是逆時針旋轉, 可以隨機選擇逆時針或順時針,
- 讓雪花結晶飄落, 且隨意忽左忽右的滑行.
讓雪花結晶旋轉飄落, 且隨意忽左忽右的滑行
我們暫時完成到 上面的 Ex2.
這裡看似只要稍微修改之前的程式碼就能完成 Ex2, 其實會遇到很多小問題,
例如: 你是要讓某隻海龜一下子就朝下方左或右45角的方向前進, 還是要讓他慢慢轉進?
如果是慢慢轉進, 有可能會最後變成朝上方漂浮, 變成雪花朝四方任意漂浮, 似乎不合理, 如何改成仍是符合重力原理, 雖是忽左忽右的滑行, 整體仍是朝下方飄落?
同學會在這一段的習題練習, 學到很多, 以下是作者的解法, 僅供參考, 不一定要跟我的設計一樣,
# -*- coding: utf-8 -*-
# set custom shape 20160617
#Turtle 24.1. Turtle graphics — Python v3.3
# Tested by Prof. P-J Lai MATH NKNU 20210103
##24.1.3.7. Special Turtle methods
##begin_poly()
##end_poly()
##register_shape("myshape",get_poly())
##T.shape("myShape")
##較單純!
## 我們用 stamp() 蓋印功能重寫"雪花的瓣數也隨機決定"那份程式碼.
##以下, 我們先畫出一個雪花形狀, 再用他註冊一個新的形狀,
##只要把產生雪花的函數 snowflake() 放在T.begin_poly(), T.end_poly() 中間就可以:
# 將 custom_Shape_get_poly()_snow_petal_fast4_fall_while_rotate.py 修改為
# custom_get_poly()_snow_petal_fast5_fall_while_rotate_drift.py
# 讓雪花結晶旋轉, 飄移
import turtle
import random
sc = turtle.Screen()
#turtle.tracer(20,1)
#turtle.speed(0.1)
T=turtle.Turtle()
T.hideturtle()
#T.fd(500)
turtle.bgcolor("cyan")
T.speed(0)
# create a list of colours
colorList = ["white", "blue", "purple", "grey", "magenta", "green", "yellow"]
# create one branch of the snowflake
def branch(size):
for i in range(3):
T.left(45)
for i in range(3):
T.forward(size/3)
T.backward(size/3)
T.right(45)
T.left(90)
T.backward(size/3)
# create a function to create different size snowflakes
def snowflake(size, x, y, color, petalNumber):
# move the pen into starting position
T.penup()
T.goto(x,y)
T.color(color)
T.ht()
T.pendown()
# draw branch petalNumber times to make a snowflake
for i in range(petalNumber):
T.fd(size)
branch(size)
T.left(360/petalNumber)
# add new shape
def snowflakeRegister(shapeName, size, x, y, color, petalNumber):
# move the pen into starting position
#T.hideturtle()
T.penup()
T.goto(x,y)
T.color(color)
T.pendown()
T.begin_poly()
snowflake(size, x, y, color, petalNumber)
T.end_poly()
turtle.register_shape(shapeName, T.get_poly())
#T.showturtle()
if __name__ == "__main__":
# loop to create numberTurtle different sized snowflakes with different starting co-ordinates
numberTurtle = 50
numberTurtleShape = 5
shapeName = []
# 改成 petal number 只照 6,8,10,12,15 等做,
# 也就是只做出 5 種 雪花原形
petalList = [6, 8, 10, 12, 15]
petalNumber = len(petalList)
#turtle.tracer(0,0)
for i in range(petalNumber):
shapeName.append("shape" + str(i))
print(shapeName[i])
snowflakeRegister(shapeName[i], 5, 0, 0, "black", petalList[i])
turtle.clearscreen()
turtle.bgcolor("black")
# snow crystal falling
turtleList = []
turtleIndex = 0
for i in range(numberTurtleShape):
for j in range(int(numberTurtle/numberTurtleShape)):
turtleList.append( turtle.Turtle())
turtleList[turtleIndex].ht()
print(shapeName[i])
turtleList[turtleIndex].shape(shapeName[i])
#turtleList[turtleIndex].ht()
turtleList[turtleIndex].penup()
x = random.uniform(-350, 350)
y = 1000 + random.uniform(-350, 350)
#y = random.uniform(-350, 350)
size = random.randint(1, 5)
turtleList[turtleIndex].color(random.random(), random.random(),random.random())
turtleList[turtleIndex].turtlesize(size)
turtleList[turtleIndex].rt(90)
turtleList[turtleIndex].speed(0)
turtleList[turtleIndex].penup()
turtleList[turtleIndex].goto(x,y)
turtleList[turtleIndex].st()
turtleIndex += 1
# 每隻海龜輪流動一小段, 造成一起移動的效果
turtle.tracer(30,10)
#turtle.tracer(1,10) 太慢
while True:
dies = [random.randint(0,2) for i in range(numberTurtle)]
for k in range(int(700/2)):
for i in range(numberTurtle):
## if -20<turtleList[i].heading()<200:
## turtleList[i].setheading(-90)
## turtleList[i].fd(2)
## turtleList[i].tilt(2)
if dies[i]==0:
if -20<turtleList[i].heading()<200:
turtleList[i].setheading(-90)
turtleList[i].lt(10)
turtleList[i].fd(2)
turtleList[i].tilt(2)
elif dies[i]==1:
turtleList[i].fd(2)
turtleList[i].tilt(2)
else :
if -20<turtleList[i].heading()<200:
turtleList[i].setheading(-90)
turtleList[i].rt(10)
turtleList[i].fd(2)
turtleList[i].tilt(2)
if turtleList[i].ycor()< -400:
turtleList[i].goto(random.uniform(-350, 350), 400 + random.uniform(-100, 100))
#sc.exitonclick()
以上解答碰到一個問題, 如果畫布左右寬度不限制, 讓雪花隨意往兩邊漂浮, 範圍會太大, 造成雪花過於稀疏, 畫面不美,
此時如果增加雪花數量, 以我筆記型電腦的效能, 會造成效能變慢,
以下習題建議, 對雪花往兩邊漂浮的範圍, 加以限制, 例如左右各300像素寬度, 超過就反轉海龜漂浮之左右方向, 如此, 就能保持雪花朵朵密集飄落, 畫面美麗詩意.
以下是作者的解法呈現之效果:
Ex: 可以改進以上程式碼,
3. 讓雪花結晶飄落, 且隨意忽左忽右的滑行, 且限制在適當的 x 座標寬度範圍內.
蕨葉雪花
Referencs
-
王燕平, 張超, 尊貴的雪花, 重慶大學, 2017.
-
雪花算法原理_孙略 | 雪花工场 link
-
How to make Snowflakes with Code (Xmas Hour of Code Special), https://youtu.be/DHmeX7YTHBY link.
For full code see: https://github.com/MissPhilbin/GeekGurlDiaries link -
The snowflake man, https://youtu.be/ptLmA263hlk link
-
Snowflake Bentley, https://youtu.be/x8HYqUjbKeM link
-
Identical Snowflakes? Scientist Ruins Winter For Everyone. | Deep Look, https://youtu.be/Gojddrb70N8 link
-
The Snowflake Mystery, https://youtu.be/ao2Jfm35XeE link
-
https://blog.xuite.net/mandyl333/myself/17735392/track