# 控制程式流程:迴圈
## 電腦的存在是為了幫人類解決繁雜工作
電腦的存在是為了為人類解決繁雜工作,所謂的重複工作,在這裡我們定義成:
- 有特定的變數
- 有既定的流程
其中既定流程又包括有預定的事件執行次數與條件,如下圖。

這一章要談的就是,如何讓程式按照你指定的次數被執行。
## 迴圈
先從一個生活例子開始談,想像你在一間的學校操場跑步,每天都要跑五圈。

如果把這件事規格化,那麼就可以拆成跑步的順序跟次數,所以就寫成:
- 執行動作:從某點移動至某點
- 執行順序:A-B-C
- 執行次數:5個回合
接著我們用Python程式語法來表示這件事,在Python,定義了兩種跟程式執行次數有關的語法,分別是`for loop`和`while loop`。
### For 迴圈(For Loop)
#### 定義次數
如果你知道要執行幾次,可以使用以下語法
```python=
for 變數 in range(start, end, step):
```
例如
```` python=
for i in range (0, 5, 1):
#執行A行為
#執行B行為
#執行C行為
````
這段程式碼,是讓A,B,C這三個行為依序被執行,並且執行五次。
在`for`後面的變數`i`,在這裡被宣告。
接著變數`i`會根據後面的`(0, 5, 1)`進行值的變化,依序是**起始參數(start)**、**終止條件參數(end)**、**Step參數**。
以這個例子來說,起始參數0將i的初始值設為0;終止條件參數5是這個迴圈的終止條件,當變數`i`>=5時,離開此迴圈;Step參數1是變數`i`每個回合加上的值。
根據以上定義,這樣的迴圈寫法,會讓這個迴圈執行5次,也就是分別是i=0,1,2,3,4這五個回合。
#### 掃描資料結構
for迴圈語法還有一個很常見的用法
```python=
for i in 資料結構:
```
資料結構包括前面介紹的`List`, `Tuple`, `Set`, `Dictionary`
如此一來,i就會走遍資料結構中的元素,並且儲存起來
例如
```python=
student_list = ["Chaoyen", "Joanne", "Manchester"]
for student in student_list:
print(f"{student}")
```
將list中的元素,一一讀取出來並輸出結果。
### 隨堂練習
全班的成績如下表所示,請設計一個程式來計算全班**數學科平均成績**,並使用以下設計原則
- 使用`Dictionary`跟`list`儲存全班資料
- 使用`for loop`讀取全班數學科成績
| 姓名 | 國文科 | 英文科 | 數學科 |
| -------- | -------- | -------- | -------- |
| Chaoyen | 80 | 87 | 67 |
| Joanne | 76 | 80 | 95 |
| Manchster | 85 | 70 | 90 |
:::spoiler 參考程式碼
```python=
student_score = { "Chaoyen":[80, 87, 67],
"Joanne":[76, 80, 95],
"Manchster":[85, 70, 90],
}
math_sum = 0 #儲存全班數學成績的累計
for score in student_score.values():
math_sum += score[2]
print(math_sum/len(student_score))
```
:::
### While 迴圈(While Loop)
```` python=
i = 0
while i < 5:
#執行A
#執行B
#執行C
i+=1
````
這段程式碼,也是讓A,B,C這三個行為依序被執行,並且執行五次。
但`while`,並不像`for`具備宣告效果,所以我們在前一行宣告變數`i`,並初始化為0。
`while`語法後面連接的,是這個迴圈的執行條件,只要符合執行條件,這個迴圈會一直被執行下去。
以這個例子來說,只要變數`i`小於5,就會依序執行行為A、行為B、行為C。
但我們希望這個迴圈執行五次就結束,所以我們在最後面加入`i+=1`也就是累加的動作,這樣經過五個回合後,也就是分別是i=0,1,2,3,4這五個回合,程式就會跳離這個while迴圈,繼續往下執行。
> i += 1 是 i = i + 1的縮寫
### 隨堂練習
請分別使用`For Loop` ,`While`設計程式,達成以下需求:
a. 依序印出10, 9, 8, 7, 6, 5, 4, 3, 2, 1
:::spoiler 參考程式碼
```python=
x = 10
y = 10
#使用for Loop
for i in range(0, 10, 1):
print(f"{x} ", end="")
x -= 1
i = 0
print("")
#使用while Loop
while i < 10:
print(f"{y} ", end="")
y -= 1
i+=1
```
:::
b. 依序印出2, 4, 6, 8, 10
:::spoiler 參考程式碼
```python=
x = 2
y = 2
#使用for Loop
for i in range(0, 5, 1):
print(f"{x} ", end="")
x += 2
i = 0
print("")
#使用while Loop
while i < 5:
print(f"{y} ", end="")
y += 2
i += 1
```
:::
### 迴圈應用:優化LED專題
在之前的專題中,我們讓左邊第一行的LED,依序點亮第一到第五顆,然後熄滅,再重來一次。
接著需求變更,改成讓左邊第二行的LED,依序點亮第一到第五顆,然後熄滅,再重來一次
```python=
from microbit import *
while True:
display.set_pixel(0, 0, 9)
sleep(1000)
display.set_pixel(0, 1, 9)
sleep(1000)
display.set_pixel(0, 2, 9)
sleep(1000)
display.set_pixel(0, 3, 9)
sleep(1000)
display.set_pixel(0, 4, 9)
sleep(1000)
```
讓我們來看看,使用巢狀迴圈來改寫程式碼,是否可以更快速面對程式功能變更需求?
```python=
from microbit import *
while True:
x = 0
y = 0
for i in range(0, 5, 1):
display.set_pixel(x, y, 9)
y += 1
sleep(1000)
display.clear()
sleep(1000)
```
改寫結果如上,我們只需要改第四行,將x=0改為x=1,就可以滿足需求,更棒的是,不管未來要點幾顆燈,我們都可以用第七到第九行,來改寫點燈的範圍。
## 巢狀迴圈
很多時候,我們在許多任務中,又可以在每個大任務中細分成許多小任務,所以在這裡我們介紹巢狀迴圈的觀念。

回到我們一開始舉的生活例子開始談,想像你在一間的學校操場跑步,每天都要跑五圈,但跑到B點時,要做完3個回合B的子任務,才可以繼續往C點前進。
如果把這件事規格化,那麼就可以拆成跑步的順序跟次數,所以就寫成:
- 執行動作:從某點移動至某點
- 執行順序:A-B(執行3個回合)-C
- 執行次數:5個回合
用Python程式語法來表示,請參考以下範例:
```` python=
for i in range (0, 5, 1):
#執行A行為
for j in range (0, 2, 1):
#執行B行為
#執行C行為
````
請注意執行A,B,C三個行為,程式碼其實是被分成三個區塊來看待,你必須非常了解每一個區塊,是怎麼透過你寫的for語法來決定執行次數,以及正確地被縮排,電腦才會幫你正確地執行程式。
```` python=
for i in range (0, 5, 1):
#執行A行為
````
```` python=
for j in range (0, 2, 1):
#執行B行為
````
```` python=
#執行C行為
````
當你無法掌握迴圈的控制時,請善用`print()`,掌握迴圈執行情況,例如
```` python=
for i in range (0, 5, 1):
#執行A行為
print(i)
for j in range (0, 2, 1):
#執行B行為
print(j)
#執行C行為
````
透過i,j值的輸出變化,你應該就會很清楚程式執行的順序,是否如你預期發生。
### 巢狀迴圈的應用:電腦動畫
在程式設計中,是使用一個不斷執行的迴圈來更換一張又一張的圖,也就是`Frame`,來進行動畫繪製,一個典型的動畫迴圈如下所示:
```
while(true) {
繪製Frame
暫停指定秒數
改變動畫狀態
}
```
其中改變動畫狀態視不同的程式而有所不同,也許只是單純的載入下一張影像,也許是由於使用者的操作而改變狀態。
請使用List宣告管理所有micro:bit LED,並且利用迴圈,畫出一個笑臉,如下圖所示

> 解決方案解析:
> 1. 宣告List來管理所有LED的亮度,注意每個LED座標對應List的位置,
> 2. 使用迴圈,根據宣告的LED亮度,點亮所有LED
參考程式碼如下:
```python=
from microbit import *
led_brightness = [
[0, 9, 0, 9, 0],
[0, 0, 0, 0, 0],
[9, 0, 0, 0, 9],
[0, 9, 9, 9, 0],
[0, 0, 0, 0, 0],
]
x = 0
y = 0
for i in range(0, 5, 1):
for j in range(0, 5, 1):
display.set_pixel(x, y ,led_brightness[y][x])
y += 1
sleep(1000)
x += 1
y = 0
```
## 未來持續學習
請充分理解語法,迴圈是程式設計中不可或缺的一環,因為電腦的主要工作,就是幫助人類進行重複性的工作。
很多人學習程式語言,遇到這個單元會陷入瓶頸,請多熟練迴圈次數的控制,分清楚**計數用**跟真正要**處理**的變數。
多看別人的程式,並且動手練習,是最好的方法。
## 參考資料
Python官方文件 https://www.python.org/
###### tags: `Python程式設計入門`