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