金凡 陳凱
記事本里的大兔子和小兔子
假設有一對小兔子,它們用一個月時間長大變成大兔子,然后再過一個月,生下一對小兔子,生下的一對小兔子也用一個月時間長大,再過一個月后又生下一對小兔子,并且假設之后每對大兔子每個月都要生一對小兔子,那么——這里并不是問幾個月后總共有幾對兔子,那其實就是求斐波那契數列了,這里的問題是,如果生下的每對小兔子都在大兔子的右側成長并且絕不隨便和大兔子交換位置——經過特定時間后,大兔子和小兔子的序列會是怎樣的?順便說一下,假設有誰特別糾結于兔子近親繁殖的倫理問題,也可以把問題情境中的兔子改成能夠單姓繁殖的大理石紋螯蝦。
這個問題在紙上就能演算出來,假設一對小兔子用符號a表示,一對大兔子用符號b表示(把現實中的事物用符號來表示,是為了其后計算上的方便,如何合理設定符號,其實和計算思維技能有關),一開始的時候,人們看到的就是a,一個月后a變成了b,再一個月后,b生下a,因為a總是在b的右側成長,所以人們看到的就是ba,再下一個月,因為a變成b,b變成ba,所以人們看到的就是bab,以此類推,再往后一個月,看到的就是babba,再往后是bababbab。可以發現,從第二個月開始,序列的開頭是不變化的,而尾巴在不斷地變長:
a
b
ba
bab
babba
babbabab
在記事本中,可以通過不停地進行三步“全部替換”功能來自動生成序列:先把a全部替換成t,再把b全部替換成ba,最后把t全部替換成a就可以了。不用動太多腦筋,反復做這三步“全部替換”就能使得符號序列越來越長。這就體現出用迭代來實現自動化奧妙了。
畫圖軟件里的兔子序列
類似的迭代思想可以用到其他地方,例如,可以用畫圖軟件來生成兔子序列,方法很有趣。
首先,畫一個深色的框,如圖1。
然后,隨便畫條豎線,把框一分為二(分的位置不用太在意),在右側部分填上比較淺的顏色,如圖2。
接著,在深色框內再畫豎線,這條豎線要比剛才的稍微長一些,然后同樣在右側部分填上比較淺的顏色,如圖3。
再接著,把當前第二短的豎線的右側框的顏色變成深色,如圖4。
這個工作可以繼續下去,注意分割的豎線越來越長,每一次新分割出來的框,都將右側填上淺色,然后不要忘記,將當前第二長的豎線的右側框填上深色,反復進行,很快就能得到兔子序列了,如上頁圖5。設深色為b,淺色為a,從左往右讀,就是兔子序列。
電子表格中的兔子序列
在電子表格中,可以有很多種方法來生成兔子序列,這里仍然借用在畫圖軟件中所使用的方法,將迭代過程變得更自動一些。
第一步:在第一行第一列的單元格中寫入b,然后在右側單元格中寫入公式“=b”,用拖曳功能,在第一行填充若干b,如圖6。
第二步:在中間某處相鄰的兩個單元格中連續填入1和a,于是右側部分就自動全部變成a,如圖7。
第三步:在鋪滿b的序列中間相鄰兩個單元格中填入2和a,于是2的右側部分變成a,如圖8。
第四步:找到比當前序列中最大的數字小1的數字,在這里正是2減1得到1,在這個數字右側鋪滿a的序列最左側單元格中填入b,于是跟隨其后的符號都變成了b,如圖9。
第五步:從第三步開始重復此過程,但填寫的數字要逐漸變大。于是就逐漸生成兔子序列了。注意在讀數據的時候,連續的符號要當成一個符號來讀。這個過程做熟練以后,可以用相當快的速度生成兔子序列。
在Scratch里用兔子序列來畫樹
如果將小兔子a看成細樹枝,大兔子b看成粗樹枝,那么就可以應用兔子序列模擬一棵樹的自動生長過程了(如上頁圖10)。
首先,在Scratch中添加tree鏈表,用來存放兔子序列。最初該鏈表中只有1項,存放著字符a,也就是樹的第一層。然后,制作“生長樹”“替換”和“分叉”三個模塊(如上頁圖11)。當主程序運行一次“生長樹”時,將三次執行“替換”模塊,完成前面所提到的三步“全部替換”。最后,利用“分叉”模塊將tree鏈表中所有值為“ba”的項分解為兩項。反復運行“生長樹”便可生成更長的兔子序列。例如,運行四次“生長樹”后,tree鏈表就增加到5項,它們分別為babba。
接著,添加一個小圓點角色并制作一個“畫樹枝”的模塊,讓小圓點以x1、y1為起始位置畫線段(如上頁圖12)。該模塊將會遍歷當前的tree鏈表,遇到a,則畫長度為len的垂直線段,遇到b,則分叉畫兩條斜線段。畫好線段后,將小圓點當前的位置分別存入x、y鏈表,它們將成為下一輪畫樹枝的初始位置。
再接著,制作“初始化”的積木,將程序中涉及到的鏈表設置為初始值,并設置畫筆大小和顏色,清空舞臺上所有畫線。最后,編寫主程序,根據用戶輸入的高度h來畫樹(如上頁圖13)。在畫完第一層之后,后續的h-1層就是一個重復迭代的“畫樹枝”過程。其中每一層樹枝的長度和樹的高度h以及當前層數i存在一定關系,這個關系式可以自己進行調整。每畫完一層,就會再運行“生長樹”模塊,使樹的鏈表即兔子序列再變長,也就意味著樹又長高了一層。
當然還可以繼續優化程序,讓線段變得有粗細之分,并使角度發生隨機變化(如圖14),甚至可以讓每個節點是否繼續生長也有隨機變化的可能,讓某些節點長出樹葉、花果。通過不斷地優化程序,可以使得這個程序所畫的樹更像大自然的樹。
為了給大家更多思考和想象的空間,本文沒有列出所有代碼,需要教師自己研究補充完整。因為代碼量比較大,在實際上課時,教師可將講課重點放在實現迭代過程的實現思路上,部分代碼可以直接提供給學生,如怎么分解符號串、以何種形式畫樹枝等,不必過多糾纏于代碼的實現細節。
面對同樣的兔子序列,可以使用各種軟件玩出很多花樣,哪怕只是簡單的記事本或畫圖軟件。因為計算思維是一種建立在計算機科學概念基礎上的思維方式,它并不局限于某類或某種軟件,甚至它也不局限于計算機,關鍵在于我們思維的方式:能否分解問題,通過抽象化、符號化,運用迭代、遞歸等方法將其轉化成為可以解決的問題。其實,在工作、生活和學習中,許多地方都隱含著用計算思維解決問題的策略,等待著大家去探索挖掘。