巢狀結構
還記得第一週講解迴圈時,我們曾經介紹過巢狀迴圈(迴圈中有另一個迴圈)這個技巧嗎?藉由巢狀結構,我們可以簡化大量的程式碼,不只是對迴圈這種控制指令的語法如此,對陣列這種控制資料的語法,也同樣如此!
考慮一個設計需求:我們要撰寫一個基本的3x3
圈圈叉叉小遊戲,為了記憶每個方格內目前是畫了圈圈還是叉叉,並且顯示在螢幕上給使用者看,必須設計一個資料結構。我們決定使用一個整數陣列來記錄這些方格的狀態,0
代表空格,1
代表叉叉,2
代表圈圈,並且使用for-in
迴圈做顯示的工作,用switch-case
處理整數轉為圖案的工作:
var 方格 = [0,0,0,0,0,0,0,0,0] for i in 1...3 { for j in 1...3 { // 列印方格狀態的程式碼? } }
之所以會寫成巢狀迴圈,是因為圈圈叉叉的遊戲板塊是一個長為3
、寬為3
的矩形,因此我們列印三個方格之後才要換一行,而列印每一行必然只伴隨一次print()
指令,所以我們撰寫程式前初步的線索是:print()
這個指令將會進行三次。
為了將問題簡化,我們不妨先印出前三個方格就好了...
var line = "" // 用來記憶一行狀態的字串,初始為空白字串 for j in 1...3 { switch 方格[j-1] { // 記得,陣列的索引由0開始,這邊把1...3轉換成0...2 case 0: line = line + " " // 0代表空格 case 1: line = line + "×" // 1代表叉叉 case 2: line = line + "o" // 2代表圈圈 default: print("應該不可能出現0,1,2以外的數值才對...") } } print(line) // 印出一行
藉由取得索引為0,1,2
的陣列元素,我們可以成功印出遊戲盤上第一行的方格狀態,以此類推的話,我們只要將目前的程式碼包在第二層迴圈裡面,也執行三次,就應該能印出全部三行的方格狀態了。
var 方格 = [0,1,0,2,1,2,0,1,2] var line:String for i in 1...3 { line = "" // 用來記憶一行狀態的字串,畫每行之前先清除 for j in 1...3 { switch 方格[ (j-1) + (i-1)*3 ] { // 每一次外層迴圈分別會計算出..[0,1,2], [3,4,5], [6,7,8]的結果 case 0: line = line + " " // 0代表空格 case 1: line = line + "×" // 1代表叉叉 case 2: line = line + "o" // 2代表圈圈 default: print("應該不可能出現0,1,2以外的數值才對...") } } print(line) // 印出一行 }
果然!完全正確的執行,但你是否覺得方格[ (j-1) + (i-1)*3 ]
這樣的語法很礙眼?而且在撰寫這些算式的時候,腦筋稍微不清楚一點就會造成錯誤(比方說,不小心把i-1
寫成i
,跑到i=3, j=1
這圈的時候,計算結果是9
,而電腦是找不到索引為9
的方格的,因為圈圈叉叉的遊戲版只需要0
到8
的索引。)
我們在想要取得某一方格內的狀態時,其實心中的想像是「我要取得第i
欄、第j
列的元素」,而目前的寫法方格[k]
其實意義是「我要取得第k
個元素」,因此有了i
與j
的乘法來算出k
這個多此一舉的轉換。這時我們不禁想像...
var 方格 = ? print(方格[1][2])
有這種語法就太好了是吧,實際上是有的!就如同巢狀for-in
迴圈是怎麼構成的一樣,我們也可以回想一下陣列的意義:它是一系列同類型元素的集合,這些元素可以是Int
、Float
、String
,甚至是自訂的struct 角色
,那麼可不可能某個陣列,是一系列陣列的集合呢?
var 一個整數的陣列 = [1,2,3] var 一個陣列的陣列 = [陣列1, 陣列2, 陣列3]
產生這種想法之後,很快就會覺得巢狀陣列也不是那麼複雜了(吧?)
var 方格 = [ [0,0,0], [1,1,1], [2,2,2] ] print(方格[0]) // 方格[0]是一個整數陣列 [0,0,0] print(方格[0][1]) // 先取得方格[0]這個陣列,接著印出其索引為1的元素
使用巢狀陣列配上巢狀迴圈,並且把for-in
迴圈改成0...2
來索引,程式碼瞬間就好讀多了!
var 方格 = [ [0,1,0] , [2,1,2] , [0,1,2] ] var line:String for i in 0...2 { line = "" // 用來記憶一行狀態的字串,畫每行之前先清除 for j in 0...2 { switch 方格[i][j] { case 0: line = line + " " // 0代表空格 case 1: line = line + "×" // 1代表叉叉 case 2: line = line + "o" // 2代表圈圈 default: print("應該不可能出現0,1,2以外的數值才對...") } } print(line) // 印出一行 }