在這里,我們將介紹一個新游戲--Pond Tutor

在Pond Tutor(https://blockly-games.appspot.com/pond-tutor)這個游戲中,我們將扮演黃色的鴨子,通過不斷的發炮彈去攻擊紅色的鴨子,當紅色的鴨子血條減為0時則玩家獲勝。
在這個游戲中為我們提供了四個功能模塊:
Swim模塊:向給定方向游動;
Scan模塊:向給定方向掃描,掃描到敵方時返回二者相距的距離;
Cannon模塊:向給定方向和距離發射炮彈;
Stop模塊:配合swim模塊,使我方停止。
通過結合這幾個模塊,我們可以想到:首先我們需要朝敵方游動,同時不斷的進行掃描;當掃描到敵方時,我們應該停止,同時用掃描到的距離設定炮口的攻擊距離。
這里唯一的問題是如何重復不斷的進行掃描,所以也就牽出了我們接下來要講的問題--循環。


?循環是一種基本的程序結構,凡是需要通過不斷重復執行才能得到答案的許多問題中需要用到循環控制。循環結構是結構化程序設計的基本結構之一,它和順序結構、選擇結構共同作為各種復雜程序的基本構造單元。因此熟練掌握選擇結構和循環結構的概念及使用是程序設計的最基本的要求。本章將介紹四種形式的循環,都是程序中基本的用于表示重復動作的結構。在本章學習結束后,學生應當具備的能力有:分析一個循環的重復執行次數和終止條件,并能在自己的程序中應用到重復次數,重復,步長,列表循環循環。
5.1 基本概念
迭代:通過包括重復序列允許通過一個簡短的程序來代替一系列的重復的步驟程序中重復執行的一段指令叫做循環。
每一個循環由兩部分組成:
條件: 控制循環重復次數 ?循環體: 循環執行時始終運行的代碼段。 ?我們稱一個無休止運行的程序為死循環,下圖所示的就是一個典型的死循環塊。死循環將會阻止一個程序完成其執行,所以含有死循環的程序通常是不可取的。 在瀏覽器內,一個死循環甚至可以導致程序對鼠標點擊失去響應或無限輸出對話框,因此要避免出現死循環,控制循環執行次數的程序必須編寫正確。

5.2 重復次數模塊
?重復次數模塊用來實現計數循環,通過在模塊中修改次數來規定重復執行的次數。

例如我們要循環三次輸出“Hello World”,則只要在重復次數模塊的數字塊中寫入“3”即可。

5.3 重復模塊
重復模塊中包含了兩種不同類型的循環模式:重復-當和重復-直到。


重復-當模塊用來實現“當型”循環結構,只要程序的執行條件為真,就會重復執行語句的一系列程序。在未運行前,實際的重復次數是未知的。

?它需要與邏輯語句組合使用,當條件滿足時它將重復不斷的執行直到條件不滿足,所以可能出現的情況是:由于一個邏輯錯誤,循環將相應代碼段重復運行無數次,這對初學者來說是很常見的。
當檢查一個循環條件時循環將會執行。如果循環條件為真,將執行循環體中的代碼并重復執行這些步驟,在每次循環前將額外檢查循環條件。條件為假時退出循環。
循環程序都包涵了三個內容:
一個清晰的起始條件
一個循環條件,指示程序是否應該繼續執行循環部分
*一個條件改變最終導致循環條件變為假。
例如,我們使用重復-當模塊來實現一個非常常見的問題:從1一直加到100。對于這問題同學們一定不陌生,甚至能有多種不同的技巧去解這個問題。但在這里,我們使用循環就可以用最笨的方法:從1一個一個的加起來,一直加到100。

?而對于重復-直到這個模塊來說則與重復-當模塊剛好相反:它是當條件滿足時就結束循環。

?所以同樣針對上面從1加到100的例子,我們只需要將條件i<=100改為i>100即可。

5.4 步長循環模塊
?步長循環模塊使用最為靈活,不僅可以用于循環次數已經確定的情況,而且可以用于循環次數不確定而只給出循環結束條件的情況,它完全可以替代重復模塊。

?在固定增量下有著固定循環次數的一段程序使用步長循環模塊為宜。下面的循環將輸出三次單詞“Hello”。

?如果你已經接觸過一些高級程序設計語言如:C/C++/Java等,你會發現步長循環模塊其實就是其中的For循環語句。
?步長循環模塊中“使用”后的k為循環的控制變量,這個k可以自己命名并且可以在循環塊內充當變量使用;“從范圍”后的數字代表循環控制變量k的初始值;“到”后的數值表示循環的結束條件:當k大于這個值時退出循環;“每隔”后的數字為k的步長,表示每循環一次,k增加多少。以上所有的數值都是可以根據自己的實際需要進行修改的。
?下面我們大家都很熟悉的一道應用題來使用步長模塊:一球從100米高度自由落下,每次落地后反跳回原高度的一半,再落下。求它在第10次落地時,共經過多少米?第10次反彈多高?

?在這里我們并沒有從第一次下落開始就使用循環,而是以落點-上升-落點為過程進行的,由于落點-上升這一過程與上升-落點的過程所經過的距離相同,所以總路程直接加二倍的反彈距離;而反彈距離直接除2即可直接變為原來的一半。
5.5 列表循環模塊
?列表循環模塊是對列表(list)中每一個元素進行循環迭代的模塊,也可以稱為是對列表元素的遍歷。所謂列表,是相同數據類型的元素按一定順序排列的集合。使用列表循環模塊的循環在達到列表的最后一個值后將自動結束。所以使用列表循環模塊是不太可能錯誤地寫成死循環的,或許唯一可以的方式是為循環使用一個含有無限元素的列表!

如下圖所示,通過使用列表循環模塊可以輸出列表numList中的每一個元素。

?雖然使用重復、步長模塊也能實現循環輸出每一個元素,但用這種方法不但需要知道列表的長度,而且無法像列表循環模塊一樣直接就定義好了變量去代表列表的元素。
例如求一個列表中的最大元素,我們可以用列表循環模塊來實現:

在這里我們定義了一個變量tmp去保存最大的值,將tmp初始化為0保證tmp剛開始為最小,之后用列表循環模塊循環拿出列表中的元素不斷的與tmp相比較,一旦當前值大于tmp則修改tmp為這個值。最終在tmp中的值將是最大的值。
5.6 中斷/繼續模塊
?中斷模塊可以用來從循環體內跳出循環體,即提前結束循環,接著執行循環下面的語句。

?中斷模塊適用于當我們不知道循環次數,只有在程序執行過程中滿足一定條件的情況下要結束循環的時候。
我們現在嘗試使用循環和中斷模塊來寫一個程序:輸入一個數,判斷這個數是否為素數。

?在這里我們讓m被2到根號m除,如果m能被2到根號m之中的任何一個整數整除,則提前結束循環,此時i必然小于或等于k(即根號m);如果m不能被2到k(即根號m)之間的任一整數整除,則在完成最后一次循環后,i還要加1,因此i=k+1,然后才終止循環。在循環之后判別i的值是否大于或等于k+1,若是,則表明未曾被2到k之間任一整數整除過,因此輸出“是素數”。
?繼續模塊其作用為結束本次循環,即跳過循環體中下面尚未執行的語句,接著進行下一次是否執行循環的判定。

?繼續模塊與中斷模塊的區別是:繼續模塊只結束本次循環,而不是終止整個循環的執行。而中斷模塊則是結束整個循環過程,不再判斷執行循環的條件是否成立。
如把100-200之間的不能被3整除的數輸出來:

當n能被3整除時,執行繼續模塊,結束本次循環(即跳過print模塊),只有n不能被3整除時才執行print模塊輸出數字。
5.7 嵌套循環
一個循環體內又包含另一個完整的循環結構,稱為循環的嵌套。內嵌的循環中還可以嵌套循環,這就是多層循環。各種語言中關于循環的嵌套的概念都是一樣的。
四種循環(重復次數,重復,步長,列表循環)可以互相嵌套,當循環嵌套在循環中,一個程序可以創建一個重復的重復。
5.7.1 內循環和外循環
當使用嵌套循環時,內外循環扮演著不同的角色:
外循環是先開始后結束的運行順序。它在程序運行中開始一次結束一次。內循環是比外循環后開始先結束的運行。它可以反復地重復運行。
內循環快速運行,每一次外循環,都會完成一個完整的內循環。外循環循環的偏慢。
內部和外部的循環類似時鐘指針的運轉。例如,一個時鐘的秒針就像內部循環同時分針就像外循環.對于每一次分針的轉動,秒針都需要轉一圈,轉動60整秒.當分針轉動一整個小時時,秒針將轉動60*60 = 3600秒。里程表和日歷的都是用這樣相似的工作方式。
5.7.2 非獨立的內循環
?有時,內部循環的工作方式取決于外部循環的哪一步運行。例如,創建一個程序打印在一年中所有的日期,您可以使用嵌套循環去打印月份的每天,但內部循環的次數取決于外部循環,這是因為每個月有不同的天數。

?在這里,內部循環重復的是不同的次數,這取決于它在哪個月份上,因為它的結束條件是 j<days[i].
對于月份,我們繪制了一個依賴于存放每一月的天數的數組的內循環,但是對于給一個非獨立內循環構思一個規則需要更加的泛化:這樣一個程序員需要考慮使用的特殊情況,同時要嘗試泛化這個規則。
由于內部循環和外部循環的關系,嵌套循環可以使具有挑戰性的程序正確。設計嵌套循環的一個很好的策略是在一個例子中仔細地找出你想要的運行效果,然后找到一個方法來歸納它。
課后練習
?1. 寫一個判斷素數的函數,在主函數輸入一個整數,輸出是否是素數。
2. 設計定義一個自己的工具塊。
3. 編寫函數,給出年、月、日,計算該日是該年的第n天,并嘗試將其導出的代碼在其他語言環境中調試運行。
知識梳理
