Goal: 藉由有趣的「海龜動畫繪圖」學會基礎的 Python 程式設計
本篇介紹基礎的 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
文章目录
5.9 畫多重旋轉圓, codes 封裝在一個函數
turtle 有內建的畫圓的指令 circle()
circle() 畫圓, 參數是半徑 (沒有ellipse)
dot() 在該地點畫一黑點
我們也可以自己寫一個畫圓的函數如下:
def circle():
for i in range(36):
T.fd(10)
T.lt(10)
Ex: 證明以上海龜之起點與終點會合一
以下畫出 6 個圓, 海龜身上內部的顏色可以用
T.fillcolor("blue")
設為藍色
或是用
T.color("yellow","blue")
設畫筆顏色為 yellow, 海龜內部顏色為 blue.
# By Prof P-J Lai MATH NKNU
# 201604
# MIT多重圓例子.py
from turtle import *
T=Turtle()
T.shape("turtle")
T.color("yellow","blue")
#T.fillcolor("blue")
T.turtlesize(2)
bgcolor("black")
T.pensize(5)
def circle():
for i in range(36):
T.fd(10)
T.lt(10)
for k in range(6):
circle()
T.lt(60)
5.9.1 畫多重旋轉圓, 由 color_list 依序取出各種顏色
以下使用一個自己定義的顏色串列: color_list=[“red”,“green”,“blue”,“purple”,“orange”,“yellow”],
由此 color_list 依序取出各種顏色, 每次都更改畫筆的顏色 pencolor( ),
,
color_list=["red","green","blue","purple","orange","yellow"]
for k in color_list:
T.pencolor(k)
,
# By Prof P-J Lai MATH NKNU
# 201604
# MIT多重圓例子_colorList.py
from turtle import *
T=Turtle()
T.shape("turtle")
#T.color("yellow","red")
T.fillcolor("orange")
T.turtlesize(2)
bgcolor("black")
T.pensize(5)
#T.pencolor("Green")
def circle():
for i in range(36):
T.fd(10)
T.lt(10)
color_list=["red","green","blue","purple","orange","yellow"]
for k in color_list:
T.pencolor(k)
circle()
T.lt(60)
如果改成七種顏色,
color_list=["red","green","blue","purple","orange","yellow","pink"]
則有些地方的codes需要做適當修改:
例如此時就是畫出七個圓, 如果每次還是旋轉60
∘
^{\circ}
∘, 會造成第七個圓與第二個圓重疊, 此時我們可以修改轉動角度, 依據 color_list 的長度(Python的指令: len(color_list
)來決定轉動的角度為
36
0
∘
l
e
n
(
c
o
l
o
r
_
l
i
s
t
)
\frac{360^\circ}{len(color\_list)}
len(color_list)360∘
完整程式碼如下:
# By Prof P-J Lai MATH NKNU
# 20221012
# MIT多重圓例子color_list.py
from turtle import *
T=Turtle()
T.shape("turtle")
T.color("yellow","green")
#T.fillcolor("blue")
T.turtlesize(2)
bgcolor("black")
T.pensize(5)
T.speed(5)
def circle():
for i in range(36):
T.fd(20)
T.lt(10)
color_list=["red","green","blue","purple","orange","yellow","pink"]
for k in color_list:
T.pencolor(k)
circle()
T.lt(360/len(color_list))
5.9.2 Python內建的隨機數指令, 畫多重旋轉圓, 隨機變換背景顏色
隨機變換顏色, 需要產生隨機數,
先補充一下, Python 如何產生隨機數
Python內建的隨機數指令:
需先載入內建的 random 模組
>>> import random
產生隨機整數
>>> random.randint(1,10)
4
產生隨機 0~1 的小數
>>> random.random()
0.6428795725944434
- 以下可以等進階時再細看
>>> random.uniform(1,5)
1.3000399653858126
>>> data = range(1,11)
隨機抽取一個(抽一張牌)
>>> random.choice(data)
9
>>> random.choice(data)
7
>>> random.choice(data)
4
random.shuffle() 隨機洗牌(隨機排列)
To shuffle an immutable sequence and return a new shuffled list,
use sample(x, k=len(x)) instead.
>>> data = [1,2,3,4,5,6,7]
>>> random.shuffle(data)
>>> data
[7, 1, 3, 4, 5, 6, 2]
>>> data_shuffle=random.shuffle(data)
>>> data_shuffle
>>> type(data_shuffle)
<class ‘NoneType’>
random.sample() 隨機抽樣
random.sample(data,2):
從 data中抽出2個個體.
Returns a new list containing elements from the population while leaving the original population unchanged.
>>> random.sample([1,2,3,4],2)
[4, 2]
>>> random.sample([1,2,3,4],4)
[2, 4, 1, 3]
尺度大時, 建議用 range(n), 效能較高
To choose a sample from a range of integers, use a range() object as an argument.
This is especially fast and space efficient for sampling from a large population:
sample(range(10000000), k=60)
random.randrange(a, b, step)
random.choices(seq, weights=None, *, cum_weights=None, k=1)
注:
排列, np 的排列用 permutation與內建的shuffle()類似, 與內建的sample()較不同,
>>> from numpy.random import permutation
.
- 以上可以等進階時再細看
隨機變換背景顏色:
mport random
turtle.bgcolor(random.randint(0,256)/256, random.randint(0,256)/256,random.randint(0,256)/256)
或是
turtle.bgcolor(random.random( ), random.random( ), random.random( ))
注意: 是 turtle.bgcolor()
, 不是 T.bgcolor()
# By Prof P-J Lai MATH NKNU
import turtle
import random
T=turtle.Turtle()
T.shape("turtle")
T.color("yellow")
T.turtlesize(2)
turtle.bgcolor(0,0,0)#RGB
T.pensize(5)
def circle():
for i in range(36):
T.fd(10)
T.lt(10)
color_list=["red","green","blue","purple","orange","yellow"]
for k in color_list:
#bgcolor(random.randint(0,256)/256, random.randint(0,256)/256,random.randint(0,256)/256)
turtle.bgcolor(random.random(),random.random( ),random.random( ))
T.pencolor(k)
circle()
T.lt(60)
#random.randint(0,256)/256 可以用 random.random( )取代 2016/4/8
5.9.3 畫多重旋轉圓, 隨機變換背景顏色與畫筆顏色
用類似的指令, 進一步, 除了隨機變換背景顏色, 也同時隨機變換畫筆顏色:
turtle.bgcolor(random.random(), random.random(), random.random())
T.pencolor( random.random(), random.random(), random.random())
# By Prof P-J Lai MATH NKNU
import turtle
import random
T=turtle.Turtle()
T.shape("turtle")
T.color("yellow")
T.turtlesize(2)
turtle.bgcolor("black")
T.pensize(5)
def circle():
for i in range(36):
T.fd(10)
T.lt(10)
#color_list=["red","green","blue","purple","orange","yellow"]
for k in range(6):
turtle.bgcolor(random.random(), random.random(),random.random())
T.pencolor(random.random(), random.random(),random.random())
circle()
T.lt(60)
5.9.4 畫多重旋轉圓, 隨機蓋印 stamp()
5.9.4.1 蓋印 stamp()
此處我們增加一個 stamp()
的實驗, stamp()呼叫時, 會在當下的位置, 畫出烏龜的形狀在該位置,
stamp()
在該地點留下一個一模一樣的烏龜圖形(像蓋章的效果), 會有一個id
clearstamp(id)
# 將編號為id之蓋章消除
clearstamps()
, 刪除全部 stamp,
clearstamps( n )
刪除前n 個 stamp
以下實驗蓋印效果,
前進 100 再蓋一個章, 會留下一個黑色海龜的章,
前進50, 改顏色為紅色, 再蓋一個章, 會留下一個紅色海龜的章,
前進50, 左轉 90, 前進200, 再蓋一個章, 會留下一個紅色海龜的章,
>>> import turtle
>>> T=turtle.Turtle()
>>> T.fd(100)
>>> T.shape('turtle')
>>> T.stamp()
5
>>> T.fd(50)
>>> T.fillcolor('red')
>>> T.stamp()
6
>>> T.fd(50)
>>> T.lt(90)
>>> T.fd(200)
如果再下一個 T.clearstamp(6)
, 則紅色海龜的章會被刪除,
>>> T.clearstamp(6)
5.9.4.2 在畫圓,多邊形的過程中蓋印
以下將之前畫多重圓(多邊形)的 codes 中, 自定義之畫圓(多邊形的函數修改, 改成輸入n, 畫正n邊形, 並且每畫一個邊長就蓋印一次, T.stamp()
def circle(n):
for i in range(n):
T.fd(50)
T.stamp()
T.lt(360/n)
或是
def polygonStamp(n):
for i in range(n):
T.fd(100)
T.stamp()
T.lt(360/n)
畫6個正n邊形中間蓋印顏色不變_1
# By Prof P-J Lai MATH NKNU
# 20230310 畫6個正n邊形,中間蓋印,顏色不變
import turtle
#from random import *
T=turtle.Turtle()
T.shape("turtle")
T.color("yellow")
T.fillcolor("blue")
T.turtlesize(1)
#bgcolor("black")
T.pensize(3)
T.pencolor("Green")
def polygonStamp(n):
for i in range(n):
T.fd(100)
T.stamp()
T.lt(360/n)
for _ in range(6):
polygonStamp(5)
T.lt(60)
畫6個正n邊形中間蓋印海龜形狀海龜畫筆顏色都隨機改變
最終版本: 海龜形狀,海龜顏色, 畫筆顏色 都隨機改變
烏龜的形狀從給定之列表依序取出, 自己定義一個 shape_list, 裡面的"turtle",“classic”,“arrow”,“circle”,“square”,“triangle” 形狀名稱是模組給好的, 不能改名稱,
shape_list=["turtle","classic","arrow","circle","square","triangle"]
{中文含意: 烏龜, 古典箭頭, 較大的箭頭, 圓, 正方形, 三角形}
則每次蓋印, 就會蓋出不同之形狀
# By Prof P-J Lai MATH NKNU
from turtle import *
from random import *
T=Turtle()
T.shape("turtle")
T.color("yellow")
T.fillcolor("blue")
T.turtlesize(1)
bgcolor("black")
T.pensize(2)
#T.pencolor("Green")
def circle(n):
for i in range(n):
T.fd(50)
T.stamp()
T.lt(360/n)
color_list=["red","green","blue","purple","orange","yellow"]
shape_list=["turtle","classic","arrow","circle","square","triangle"]
index=0
for k in color_list:
T.shape(shape_list[index])
index=index+1
bgcolor(random(), random(),random())
T.color(random(), random(),random())
T.pencolor(k)
circle(12)
T.lt(60)
使用 random.choice()
較簡潔 畫6個正n邊形中間蓋印海龜形狀海龜畫筆顏色都隨機改變
較簡潔的版本 使用 random.choice()
# By Prof P-J Lai MATH NKNU
# 20230310畫6個正n邊形中間蓋印隨機形狀隨機畫筆海龜顏色_4
import turtle
import random
#from turtle import *
##from random import *
T=turtle.Turtle()
T.shape("turtle")
T.color("yellow","blue")
#T.fillcolor("blue")
T.turtlesize(1)
turtle.bgcolor("black")
T.pensize(2)
T.pencolor("gold")
def circleStamp(n):
for i in range(n):
T.fd(50)
T.stamp()
T.lt(360/n)
color_list=["red","green","blue","purple","orange","yellow"]
shape_list=["turtle","classic","arrow","circle","square","triangle"]
for _ in range(6):
#T.pencolor(random.choice(color_list))
T.color(random.choice(color_list),random.choice(color_list))
T.shape(random.choice(shape_list))
circleStamp(12)
T.lt(60)
5.10 畫螺旋正方形, tracer( ) 的 help( ) 示例
tracer()
可以調控動畫的速度,
turtle.tracer = tracer(n=None, delay=None)
n 表示畫好n個影格再撥放出來,
delay 表示播放之間, 間格 delay 秒/1000.
以下圖形是 >> help(‘turtle.tracer’) 的示例
是一個較密集之螺旋正方形
##>> help('turtle.tracer')
##Help on function tracer in turtle:
##
##turtle.tracer = tracer(n=None, delay=None)
## Turns turtle animation on/off and set delay for update drawings.
##
## Optional arguments:
## n -- nonnegative integer
## delay -- nonnegative integer
##
## If n is given, only each n-th regular screen update is really performed.
## (Can be used to accelerate the drawing of complex graphics.)
## Second arguments sets delay value (see RawTurtle.delay())
from turtle import *
#tracer(1, 10) #預設
tracer(1,100) # 變得很慢
tracer(2,10) # 比tracer(1, 10)快
dist = 2
for i in range(200):
fd(dist)
rt(90)
dist += 2
以下我們增加隨機 color()的設置, 畫出圖形如下
from turtle import *
import random
#tracer(1, 10) #預設
tracer(1.5, 10)
dist = 2
for i in range(200):
fd(dist)
rt(90)
dist += 2
color(random.random(),random.random(),random.random())
Ex: 如果想畫出正5邊形的螺線, 請問以上程式碼該如何修改?
Hint: 將以上右轉90度 rt(90), 改成右轉 360/5=72 度, rt(72), 就可以.
Ex: 如果改成輸入 n >2 正整數, 就可以畫出正 n 邊形的螺線, 請問以上程式碼該如何修改?
Ans:
from turtle import *
import random
#from math import pi
import math
#tracer(1, 10) #預設
tracer(2, 10)
#dist = 2
def regularPolySpiral(n=5,dist=2,step=1):
#angle = 2*math.pi/n
angle = 2*180/n
for i in range(400):
fd(dist)
rt(angle)
dist += step
color(random.random(),random.random(),random.random())
>>> regularPolySpiral(11,2,0.5)
畫出:
Ex: 如果將以上正4邊形的螺線的程式碼中, 右轉90度, 改成 89度, 請問會出現何種型態? 類似, 正 5 邊形的螺線的程式碼中, 右轉 360/5=72 度, 改成 71度, 等等.
5.11 畫螺旋形, T.dot( size, color) 加彩色串珠
在前進時, 使用 T.dot( size, color), 就會蓋出一顆珠子的形狀,
把以上的正多邊形螺線, 改成串珠的型態
help(‘turtle.tracer’)_例子_4.10 畫螺旋七方形_彩色串珠_color.py
# help('turtle.tracer')_例子_4.10 畫螺旋七方形_彩色串珠_color.py
# P-J Lai MATH NKNU 20201004
##>> help('turtle.tracer')
##Help on function tracer in turtle:
##
##turtle.tracer = tracer(n=None, delay=None)
## Turns turtle animation on/off and set delay for update drawings.
##
## Optional arguments:
## n -- nonnegative integer
## delay -- nonnegative integer
##
## If n is given, only each n-th regular screen update is really performed.
## (Can be used to accelerate the drawing of complex graphics.)
## Second arguments sets delay value (see RawTurtle.delay())
from turtle import *
import random
#tracer(1, 10) #預設
#tracer(0, 0)
pensize(2)
bgcolor('black')
dist = 2
for i in range(200):
fd(dist)
dot(7,(random.random(),random.random(),random.random()))
#rt(90)
rt(360/7-1)
dist += 2
color(random.random(),random.random(),random.random())
以下改成螺線串珠
help(‘turtle.tracer’)_例子_4.10 畫螺旋線_彩色串珠_color_10.py
# P-J Lai MATH NKNU 20201004
##>> help('turtle.tracer')
##Help on function tracer in turtle:
##
##turtle.tracer = tracer(n=None, delay=None)
## Turns turtle animation on/off and set delay for update drawings.
##
## Optional arguments:
## n -- nonnegative integer
## delay -- nonnegative integer
##
## If n is given, only each n-th regular screen update is really performed.
## (Can be used to accelerate the drawing of complex graphics.)
## Second arguments sets delay value (see RawTurtle.delay())
from turtle import *
import random
#tracer(1, 10) #預設
tracer(0, 0)
pensize(2)
bgcolor('black')
dist = 1
penup()
for i in range(500):
fd(dist)
dot(7,(random.random(),random.random(),random.random()))
#rt(90)
rt(10)
dist += 0.1
color(random.random(),random.random(),random.random())
Ex: 改成越中心的珠子越小, 看看視覺效果是否會更好?
5.11 畫放射折線並蓋印, 消除 “魔術數字”
參考網路看到的放射折線並蓋印的圖, LOGO 16 Turtles doing a different dance. Why do you only see 15 turtles?
Ref: http://faculty.chas.uni.edu/~jacobson/logo.html link
放射直線
先試做還沒蓋印的放射直線
# By Prof. P-J Lai 20201202
import turtle
import random
T = turtle.Turtle()
T.pensize(3)
T.speed(0)
for i in range(25):
T.shape('turtle')
T.color(random.random(),random.random(),random.random())
T.fd(200)
T.penup()
T.goto(0,0)
T.rt(360/25)
T.pendown()
再增加蓋印的動作 T.stamp()
# By Prof. P-J Lai 20201109
import turtle
import random
T = turtle.Turtle()
T.pensize(3)
T.speed(1)
for i in range(25):
T.shape('turtle')
T.color(random.random(),random.random(),random.random())
T.fd(200)
T.stamp()
T.penup()
T.goto(0,0)
T.rt(360/25)
T.pendown()
增加每小步蓋一個 dot()
turtle放射直線_dot_彩色串珠_蓋印.py
以下是執行到中間步驟的圖
# By Prof. P-J Lai 20201109
import turtle
import random
T = turtle.Turtle()
T.pensize(3)
T.speed(0)
for i in range(25):
T.shape('turtle')
T.color(random.random(),random.random(),random.random())
for i in range(30):
#T.penup()
T.fd(15)
T.dot(10,(random.random(),random.random(),random.random()))
T.stamp()
T.penup()
T.goto(0,0)
T.rt(360/25)
T.pendown()
放射折線
先試做還沒蓋印的放射折線
codes:
# By Prof. P-J Lai 20201109
import turtle
import random
T = turtle.Turtle()
T.pensize(3)
for i in range(16):
T.shape('turtle')
T.color(random.random(),random.random(),random.random())
T.fd(100)
T.rt(90)
T.fd(50)
T.lt(90)
T.fd(100)
T.rt(30)
T.fd(50)
T.lt(60)
T.fd(50)
T.rt(30)
T.fd(50)
T.penup()
T.goto(0,0)
T.rt(360/16)
T.pendown()
在上面的基礎增加蓋印的動作,
試做蓋印的放射折線
# By Prof. P-J Lai 20201109
import turtle
import random
T = turtle.Turtle()
T.pensize(3)
for i in range(16):
T.shape('turtle')
T.color(random.random(),random.random(),random.random())
T.fd(100)
T.rt(90)
T.fd(50)
T.lt(90)
T.fd(100)
T.rt(30)
T.fd(50)
T.lt(60)
T.fd(50)
T.rt(30)
T.fd(50)
T.stamp()
T.penup()
T.goto(0,0)
T.rt(360/16)
T.pendown()
數量增加為 25 個放射狀海龜蓋印
以上程式碼中有所謂的 魔術數字,就是以下 16 這個數字,
for i in range(16):
,
,
T.rt(360/16)
Ex: 請同學將以上 codes 改成用函數封裝,輸入引數 n, 就會畫 n 個放射狀海龜蓋印, 就不會有魔術數字的狀況.
5.12 用 random.choice([上,下, 左, 右]) 模擬 “隨機漫步” (隨機游動, 布朗運動)
使用 random 模組中, 隨機抽牌 的 指令 random.choice()
:
random.choice([1,4,2,8,7,,,,])
每次都隨機選擇出一個元素
用
T.lt(random.choice([0,90,180,270]))
使海龜每次都隨機選擇上,下, 左, 右前進.
# Ref: A Guide to the TurtleGraphics Package for R_入門例子
# random lines
# By Prof. P-J Lai MATH NKNU 20201012
# 本來要試放射狀, 試成隨機折線 20201029
# random lines_等長隨機漫步_4方.py 20201101
import turtle
import random
T = turtle.Turtle()
T.shape('turtle')
T.speed(0)
T.fillcolor('green')
T.pensize(3)
turtle.bgcolor('black')
#turtle.tracer(0,0)
penSizeList = [1,2,3,4,5]
for k in range(1):
T.penup()
T.goto(random.randint(-100,100),random.randint(-100,100))
T.pendown()
for i in range(1000):
T.pencolor(random.random(),random.random(),random.random())
T.fd(10)
T.lt(random.choice([0,90,180,270]))
5.13 Project: 讓多隻海龜同時移動 模擬 starfield 星際大戰的光速飛行場景
參考
Coding Challenge #1 Starfield in Processing
https://www.youtube.com/watch?v=17WoOqgXsRM link
Coding Challenge #1: Starfield in Processing with music
https://www.youtube.com/watch?v=KWhnilgKM1M link
裏 模擬 starfield 星際大戰的光速飛行場景
Project: 請同學嘗試用 Pyhton 模擬 starfield 星際大戰的光速飛行場,
(需要多隻海龜同時移動的方法, 可以參考
從 Logo 海龜繪圖 學習 Python - 高中彈性課程系列 1 課程簡介, sec 各項提示或補充之總表
https://editor.csdn.net/md/?articleId=107502070 link)
Reference
-
需要多隻海龜同時移動的方法, 可以參考
從 Logo 海龜繪圖 學習 Python - 高中彈性課程系列 1 課程簡介, sec 各項提示或補充之總表
https://editor.csdn.net/md/?articleId=107502070 link) -
以下這份影片的圖形與本篇的很多類似, 但是他沒有提供程式碼: https://youtu.be/hPsjMTz-aDQ link.
-
以 Python重寫 MIT pythonTturtle Log 圖 與 河西朝雄C語言書中 的海龜繪圖圖形https://download.csdn.net/download/m0_47985483/87032053 link