在我們的python課程中,用到的森林一關(guān),地牢里的關(guān)卡主要是偏向鍛煉用戶的基本語法結(jié)構(gòu)和計算機思維,讓大家熟悉極客戰(zhàn)記的操作與代碼的使用。來到了森林,關(guān)卡將會變得更多更難,同樣,到了森林,大家就正式開始接觸編程的幾大重要知識點:條件判斷、運算符、函數(shù)、對象屬性。
一、關(guān)卡簡介
「目光短淺的警衛(wèi)」本關(guān)涉及的編程知識點還是函數(shù)及函數(shù)參數(shù),但僅僅懂得“寫代碼”,還不能通過這一關(guān),我們還需要掌握“修代碼”的能力——觀察程序運行過程,自主完善程序邏輯的計算思維。
這一關(guān)有些特殊,一進入本關(guān),什么都還沒做,系統(tǒng)就彈出了一個紅色錯誤提示框(圖1),看起來十分嚇人。
二、知識點:代碼查錯與修正(一)
當(dāng)我們遇到系統(tǒng)彈出報錯時,保持冷靜,大家可以使用以下三步來解決問題:查看報錯類型,閱讀報錯代碼,定位錯誤位置,看到報錯彈窗(圖2):
彈窗說明,錯誤發(fā)生在第16行,錯誤類型是ReferfenceError,是引用錯誤的意思,后方則指出了產(chǎn)生這個錯誤的具體代碼段,如果不明白ReferfenceError是什么意思,沒關(guān)系,在最后還有中文具體解釋這個錯誤——“未定義”。
那么閱讀第16行的錯誤代碼:在這一行,程序調(diào)用了checkTakeRun函數(shù),并傳入了參數(shù)coin。結(jié)合報錯提示,我們就能知道在程序的第16行,調(diào)用checkTakeRun函數(shù)的這段代碼,發(fā)生了未定義錯誤。什么叫未定義錯誤呢?在上一篇關(guān)卡教學(xué)里,我們有詳細(xì)講過函數(shù)的相關(guān)知識,里面有提到我們在程序里創(chuàng)建一個函數(shù),在計算機里面,這個動作就叫做定義函數(shù),不太熟悉的同學(xué),可以回到上一篇文章復(fù)習(xí)復(fù)習(xí):極客戰(zhàn)記[森林]:遠(yuǎn)程除法-通關(guān)代碼及講解,那么此處未定義錯誤的意思就很明確了:
你當(dāng)前調(diào)用的checkTakeRun函數(shù),還沒有創(chuàng)建出來,沒有創(chuàng)建的東西,你要讓程序去使用它,而程序找不到這個函數(shù),自然就會發(fā)生報錯,因此查看我們的代碼(圖3):
可以看到,在這個程序里,我們只創(chuàng)建了takeItem函數(shù),而并沒有創(chuàng)建checkTakeRun函數(shù)。因此解決問題的思路也清晰了:根據(jù)注釋要求,創(chuàng)建checkTakeRun函數(shù)。
那么我們根據(jù)關(guān)卡要求,來定義checkTakeRun函數(shù)。在第16行,我們能夠看到,系統(tǒng)在調(diào)用checkTakeRun函數(shù)時,傳入了一個變量,從這里能夠得知,我們要定義的checkTakeRun函數(shù),是帶有一個參數(shù)的函數(shù),用于接收英雄發(fā)現(xiàn)的物品并處理。那么我們在定義函數(shù)的時候,也需要為這個函數(shù)帶上一個參數(shù):
參數(shù)的名字我們可以任意設(shè)置一個便于識別的名字。然后根據(jù)注釋要求,完成函數(shù)的內(nèi)容,如果傳入的物品存在,則調(diào)用takeItem函數(shù)拾取物品,如果不在,就返回初始點。設(shè)置好以后,就能看到,原來的報錯提示消失了,此時我們的代碼已經(jīng)沒有了任何錯誤(圖4)。然而,點擊運行,你會發(fā)現(xiàn)我們的英雄還是不能按要求完成任務(wù),通過關(guān)卡。
這是為什么呢?明明代碼已經(jīng)按注釋要求填寫,并且沒有產(chǎn)生任何錯誤了,為什么我們的英雄還是沒法完成關(guān)卡?想一想,本關(guān)的名字叫做“目光短淺的警衛(wèi)”,這個“目光短淺”指的可不僅僅是在守護寶藏的大怪物。
誠然,你的代碼已經(jīng)沒有任何問題了,但在現(xiàn)實中,我們的程序常常需要根據(jù)現(xiàn)實的情況,來做相應(yīng)的調(diào)整,以應(yīng)對各種情況,這就是我們代碼查錯的第二個內(nèi)容了,我們還需要根據(jù)程序運行時發(fā)生的特殊情況,來調(diào)整我們的程序。
三、 知識點:代碼查錯與修正(二)
既然錯誤是游戲中的突發(fā)情況導(dǎo)致的,那么我們就需要觀察游戲過程,分析問題所在:可以發(fā)現(xiàn),我們英雄失敗的原因是,在來到右上方X標(biāo)記點時,撿到了寶藏,隨后直接從上方小路穿過,碰到了守衛(wèi),直接被擊敗(圖5)。
我們的函數(shù)里,有編寫當(dāng)英雄沒有發(fā)現(xiàn)金幣時,立即返回初始點的代碼,但發(fā)現(xiàn)金幣后,我們只是調(diào)用了takeItem函數(shù),拾取了金幣,隨后函數(shù)就結(jié)束了,再沒有其他動作了,那么再看到我們的循環(huán):
這段代碼,大家此刻都已經(jīng)明白,它是讓英雄先前往左側(cè)(18行代碼),調(diào)用checkTakeRun函數(shù),函數(shù)運行結(jié)束,回到了初始點,然后執(zhí)行21行代碼,去往右側(cè),調(diào)用函數(shù)。
當(dāng)我們的英雄前往右側(cè)時,調(diào)用了checkTakeRun函數(shù),發(fā)現(xiàn)了寶藏,并拾取了寶藏,函數(shù)結(jié)束,那么此時英雄的下一步是什么?
23行代碼結(jié)束,根據(jù)循環(huán),英雄將執(zhí)行第18行代碼,直接前往左側(cè)X標(biāo)記點。那么這樣就會導(dǎo)致英雄和敵人正面相遇,發(fā)生戰(zhàn)斗。這就是問題的所在,因此,我們就需要解決問題,思路如下:
要避免戰(zhàn)斗,就要避免英雄和敵人相遇,那么我們就不能直接從右側(cè)標(biāo)記點前往左側(cè),應(yīng)該是先回到初始點,再前往左側(cè)標(biāo)記點。因此過關(guān)方法也就清晰明了了,我們只需要在checkTakeRun函數(shù)內(nèi)略作修改:
當(dāng)英雄發(fā)現(xiàn)并拾取了寶藏后,新增一條代碼,讓英雄返回初始點,如此便可順利通關(guān),通關(guān)代碼見(圖6)。