第 18 章 程序中的決策:條件塊

2018-02-24 15:51 更新

即使是像口袋里的手機(jī)這樣小型的電腦,也可以在短短幾秒鐘內(nèi)完成超過(guò)數(shù)千次的操作。更令人驚奇的是,它們可以基于內(nèi)存中的數(shù)據(jù)以及程序員編寫(xiě)的邏輯進(jìn)行決策。這種決策能力在人們所思考的人工智能問(wèn)題中是極為關(guān)鍵的要素,當(dāng)然也是創(chuàng)建有趣的智能應(yīng)用的重要組成部分。本章將探索如何在應(yīng)用中編寫(xiě)判斷選擇邏輯。

{%}

正如我們?cè)诘?4章所討論的,應(yīng)用的行為由一系列的事件處理程序所定義。每個(gè)事件處理程序針對(duì)某個(gè)特定事件進(jìn)行響應(yīng),并實(shí)現(xiàn)特定的功能。然而,這種響應(yīng)的過(guò)程未必是按線性順序來(lái)實(shí)現(xiàn)各項(xiàng)功能,有些功能只能在一定條件下才能執(zhí)行。像游戲類(lèi)的應(yīng)用可能就會(huì)判斷分?jǐn)?shù)是否已經(jīng)達(dá)到了100,而位置感知類(lèi)的應(yīng)用可能會(huì)問(wèn)“某個(gè)手機(jī)是否在某個(gè)建筑物的范圍之內(nèi)”。你的應(yīng)用也可以詢(xún)問(wèn)類(lèi)似的問(wèn)題,然后根據(jù)答案,繼續(xù)執(zhí)行不同的程序分支。

如圖18-1,當(dāng)事件(Event1)發(fā)生時(shí),無(wú)論如何A功能都會(huì)被執(zhí)行;然后進(jìn)行一個(gè)檢測(cè)判斷:如果檢測(cè)結(jié)果為真,則執(zhí)行B1分支;如果結(jié)果為假,則執(zhí)行B2分支;無(wú)論執(zhí)行哪個(gè)分支,該事件處理程序的其余部分(C)都將被執(zhí)行。

由于像圖18-1這樣的決策圖看起來(lái)像一棵樹(shù),因此通常會(huì)將這種根據(jù)判斷結(jié)果而選擇執(zhí)行的一段程序稱(chēng)為“分支”。在這種情況下,你會(huì)說(shuō), “如果測(cè)試結(jié)果為真,則執(zhí)行包含B1的分支。”

{%}

圖 18-1 事件處理程序中,根據(jù)條件測(cè)試的結(jié)果執(zhí)行不同分支

用if及ifelse進(jìn)行條件測(cè)試

App Inventor提供了兩類(lèi)條件塊(如圖18-2):if塊和ifelse塊??梢詮腃ontrol抽屜里拖出一個(gè)if塊,然后點(diǎn)擊上面的藍(lán)色圖標(biāo),彈出可擴(kuò)充的塊,可以根據(jù)需要添加任意多個(gè)“else”分支。

{%}

圖 18-2 條件塊if及ifelse

可以將任何邏輯表達(dá)式(Boolean)插入到if右側(cè)的測(cè)試插槽中。邏輯表達(dá)式是一個(gè)用數(shù)學(xué)等式,它的返回值要么是真(true),要么是假(false)。如圖18-3,邏輯表達(dá)式使用關(guān)系運(yùn)算符(藍(lán)色)以及邏輯運(yùn)算符(綠色),對(duì)屬性值或變量值進(jìn)行檢測(cè)。

{%}

圖 18-3 用于條件判斷的關(guān)系及邏輯運(yùn)算符

無(wú)論是if塊還是ifelse塊,只有“if”后面的測(cè)試結(jié)果為真時(shí),將執(zhí)行“then”右側(cè)插槽中的塊。對(duì)于if塊,如果測(cè)試結(jié)果為假,程序?qū)⑻鰅f塊,繼續(xù)執(zhí)行if后面的塊;而對(duì)于ifelse塊,如果測(cè)試結(jié)果為假,將執(zhí)行“else”右側(cè)插槽中的塊。

因此,對(duì)于一個(gè)游戲來(lái)說(shuō),可能會(huì)插入一個(gè)與成績(jī)有關(guān)的邏輯表達(dá)式,如圖18-4所示。

{%}

圖 18-4 用于測(cè)試成績(jī)值的邏輯表達(dá)式

在本例中,如果成績(jī)到達(dá)100,則播放一個(gè)聲音文件。注意,如果測(cè)試結(jié)果為假,不執(zhí)行任何塊。如果需要在測(cè)試結(jié)果為假時(shí)執(zhí)行某些操作,可以使用ifelse塊。

編寫(xiě)一段二選一的決策程序

考慮這樣一個(gè)應(yīng)用,無(wú)聊的時(shí)候也許會(huì)用到它:在手機(jī)上點(diǎn)擊一個(gè)按鈕,就可以隨機(jī)地?fù)艽蛞粋€(gè)朋友的電話。如圖18-5,使用一個(gè)random integer(隨機(jī)整數(shù))塊來(lái)生成一個(gè)數(shù)字,然后用ifelse對(duì)生成的數(shù)字進(jìn)行判斷,來(lái)決定即將撥打的電話號(hào)碼。

{%}

圖 18-5 用ifelse塊判斷隨機(jī)生成的整數(shù)來(lái)選擇要撥打的號(hào)碼

在這個(gè)例子中,random integer的參數(shù)為1和2,意味著將以相等的幾率產(chǎn)生1或2,所產(chǎn)生的隨機(jī)數(shù)保存在變量randomNum中。

一旦取得了變量randomNum的值,在ifelse塊中將變量值與1進(jìn)行比較:如果randomNum的值為1,程序?qū)?zhí)行第一個(gè)分支(then),將電話號(hào)碼設(shè)置為“111-1111”;如果變量值不為1,測(cè)試結(jié)果為假,程序執(zhí)行第二個(gè)分支(else),電話號(hào)碼被設(shè)置為“222-2222”。無(wú)論測(cè)試結(jié)果如何,程序都將拔打電話,因?yàn)槭窃谡麄€(gè)ifelse塊的下面調(diào)用了MakePhoneCall過(guò)程。

多重條件判斷

許多情況下不只是雙重選擇,即,可選擇的結(jié)果不僅僅是兩個(gè)。例如,也許你希望可以給更多的朋友隨機(jī)撥打電話,因此就需要在原來(lái)的else分支中,再加入一個(gè)ifelse,如圖18-6所示。

{%}

圖 18-6 外層條件判斷的else分支中加入另一個(gè)ifelse條件判斷

在這些塊中,如果第一個(gè)檢測(cè)條件結(jié)果為真,程序?qū)?zhí)行第一個(gè)“then”分支并撥打號(hào)碼“111-1111”;如果第一個(gè)測(cè)試結(jié)果為假,則執(zhí)行外層的else分支,此時(shí)將立即進(jìn)行另一個(gè)測(cè)試。因此,如果第一個(gè)測(cè)試結(jié)果(randomNum=1)為假,而第二個(gè)測(cè)試結(jié)果(randomNum=2)為真,則執(zhí)行第二個(gè)(內(nèi)層的)“then”分支,并撥打號(hào)碼“222-2222”;如果前面兩個(gè)測(cè)試的結(jié)果都為假,則執(zhí)行最下面的內(nèi)層的else分支,并撥打第三個(gè)號(hào)碼333-3333。

注意,在修改過(guò)的程序中,隨機(jī)整數(shù)生成器(random integer)中的參數(shù)2變成了3,因此,將以相等的幾率生成結(jié)果1、2或3。

這種在一個(gè)條件判斷中加入另一個(gè)判斷的方式稱(chēng)為“嵌套”,在本例中,可以稱(chēng)為“嵌套的if-else塊”,使用這種嵌套的邏輯,可以為隨機(jī)撥打電話的程序提供更多的選擇。一般來(lái)說(shuō),任何程序中都可以使用任意多層的嵌套。

復(fù)雜條件判斷

除了嵌套,還可以設(shè)定更為復(fù)雜的檢測(cè)條件,即,多于一個(gè)等式的檢測(cè)條件。例如這樣一個(gè)應(yīng)用,當(dāng)你(或你的手機(jī))離開(kāi)某棟建筑或某個(gè)邊界時(shí),手機(jī)會(huì)發(fā)出震動(dòng)。這樣的應(yīng)用適用于那些受控人員,警告他們不要遠(yuǎn)離法定的邊界;也可以用于家長(zhǎng)監(jiān)視孩子們的行蹤;教師可以用它來(lái)做自動(dòng)點(diǎn)名(條件是學(xué)生們都配有Android手機(jī)?。?/p>

例如,我們提出這樣的問(wèn)題:手機(jī)是否在“舊金山大學(xué)哈尼科學(xué)中心”范圍內(nèi)?這樣的應(yīng)用要對(duì)4個(gè)不同的問(wèn)題進(jìn)行一個(gè)復(fù)雜的檢測(cè):

  • 手機(jī)所在的緯度低于邊界緯度的最大值(37.78034)嗎?

  • 手機(jī)所在的經(jīng)度低于邊界經(jīng)度的最大值(-122.45027)嗎?

  • 手機(jī)所在的緯度高于邊界緯度的最小值(37.78016)嗎?

  • 手機(jī)所在的經(jīng)度高于邊界經(jīng)度的最小值(-133.45059)嗎?

本例中使用了位置傳感器(LocatinSensor)組件,即便你沒(méi)用過(guò)這個(gè)組件,也能夠理解這些程序,在第23章中將有更多講解。

使用邏輯運(yùn)算符and、or及not可以構(gòu)造出更為復(fù)雜的測(cè)試條件,可以從Logic抽屜中找到它們。在本例中,先拖出一個(gè)if塊以及三個(gè)and塊,并將and塊放在if塊的測(cè)試插槽中,如圖18-7所示。

{%}

圖 18-7 放在if塊測(cè)試插槽中的“and”塊(選擇“External Input/外展式輸入”以免塊的排列過(guò)寬)

然后拖出幾個(gè)塊來(lái)組成第一個(gè)測(cè)試問(wèn)題,并將其放在and塊的第一個(gè)測(cè)試插槽中,如圖18-8所示。

{%}

圖 18-8 and塊中放入了第一個(gè)測(cè)試問(wèn)題塊

如法炮制出其他幾個(gè)測(cè)試條件,填入其他幾個(gè)and的測(cè)試插槽中,并將整個(gè)if塊放入事件處理程序LocationSensor.LocationChanged中,這樣就寫(xiě)成了一個(gè)檢測(cè)邊界的程序,如圖18-9所示。

{%}

圖 18-9 每次位置更新時(shí),觸發(fā)該事件處理程序,來(lái)檢測(cè)是否在邊界之內(nèi)

這些塊的功能是,在每次位置傳感器讀數(shù)更新時(shí)做出判斷,如果手機(jī)的位置在邊界之內(nèi),則發(fā)出震動(dòng)。

OK,到目前為止,應(yīng)用已經(jīng)相當(dāng)酷了,但現(xiàn)在我們來(lái)嘗試更為復(fù)雜的功能,以便你能充分地了解程序中決策的威力。如何才能讓手機(jī)僅在越出邊界時(shí)才發(fā)出震動(dòng)呢?繼續(xù)學(xué)習(xí)之前,自己先想想如何來(lái)寫(xiě)這樣的程序。

我們的方法是定義一個(gè)變量withinBoundary,目的是記住傳感器上一次的讀數(shù)是否在邊界內(nèi),并根據(jù)每一次后續(xù)讀數(shù)的測(cè)試結(jié)果對(duì)變量值進(jìn)行修改。withinBoundary是一個(gè)布爾(Boolean)類(lèi)型的變量,與保存數(shù)字或文本的變量相比,它保存的值為true(真)或false(假)。舉例來(lái)說(shuō),如果將變量初始值設(shè)為false,如圖18-10所示,這意味著設(shè)備不在舊金山大學(xué)的哈尼科學(xué)中心范圍內(nèi)。

{%}

圖 18-10 變量withinBoundary為初始化為false

對(duì)塊做出修改,以便在每次位置信息變化時(shí),對(duì)變量withinBoundary進(jìn)行設(shè)置,并且只有當(dāng)手機(jī)越出邊界時(shí),才會(huì)發(fā)出震動(dòng)。說(shuō)的更明確一些,手機(jī)產(chǎn)生震動(dòng)的必備條件是(1)變量withinBoundary的值為真,即意味著上一次讀數(shù)還在邊界內(nèi);(2)新的傳感器讀數(shù)超出了邊界。圖18-11中是修改后的塊。

{%}

圖 18-11 這些塊的功能是:只有當(dāng)手機(jī)從界內(nèi)移動(dòng)到界外時(shí),手機(jī)才會(huì)震動(dòng)

我們來(lái)仔細(xì)地分析一下。當(dāng)位置傳感器(LocationSensor)獲得讀數(shù)時(shí),首先判斷讀數(shù)是否在邊界內(nèi),如果是,將withinBoundary設(shè)置為true。由于我們希望只有在手機(jī)越出邊界時(shí)才震動(dòng),因此在第一個(gè)分支中不發(fā)生震動(dòng)。

如果執(zhí)行的是else分支,我們知道新的讀數(shù)已經(jīng)超出了邊界。此時(shí),我們需要檢查上一次的讀數(shù):盡管這次讀數(shù)超出了邊界,但我們希望僅當(dāng)上次讀數(shù)在邊界內(nèi)時(shí),才讓手機(jī)發(fā)出震動(dòng)。withinBoundary變量會(huì)告訴我們上一次的讀數(shù),因此我們會(huì)檢查這個(gè)變量,如果檢查結(jié)果為真,則讓手機(jī)震動(dòng)。

一旦確認(rèn)手機(jī)從界內(nèi)移動(dòng)到了界外,還有一件事必須要做,你能猜到是什么嗎?對(duì),需要重新設(shè)置withinBoundary為false,這樣,在下一次收到傳感器讀數(shù)時(shí),手機(jī)才不會(huì)再次震動(dòng)。

關(guān)于布爾型變量,還有一點(diǎn)需要提示:檢查一下這兩個(gè)if測(cè)試,如圖18-12,它們的效果一樣嗎?

{%}

圖 18-12 你能說(shuō)出這兩個(gè)if測(cè)試的結(jié)果一樣嗎?

答案是“一樣”!唯一的差別在于下邊的提問(wèn)方式實(shí)際上更加老練,而上邊的測(cè)試還要將一個(gè)布爾型的變量(其值只能是true或false)與true進(jìn)行比較。如果withinBoundary的值為true,將true與true比較,結(jié)果一定是true;如果變量值為false,將false與true比較,結(jié)果為false。因此,只需要對(duì)withinBoundary的值進(jìn)行檢測(cè),像右邊那樣,其結(jié)果相同,而且編碼更加簡(jiǎn)潔。

小結(jié)

頭暈了嗎?尤其是最后的部分相當(dāng)復(fù)雜!但這類(lèi)決策方法是高級(jí)應(yīng)用中必須具備的。如果你能一步一步(或者說(shuō)一個(gè)分支一個(gè)分支)地實(shí)現(xiàn)這些行為,并做到邊做邊測(cè)試,我們敢斷言,你會(huì)發(fā)現(xiàn),即便是人工智能也不是不可能的。它讓你頭疼,也讓你的大腦獲得了些許邏輯思維的鍛煉,但無(wú)疑也是充滿樂(lè)趣的。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)