讓不懂程式設計的人愛上iPhone開發(2018秋iOS12+Swift4.2+Xcode10版)-08
又到了繼續學習iPhone開發的時間了。
計算玩家得分
在之前的學習裡面,我們已經用隨機數來設定了目標數值,同時也知道如何來讀取滑動條結點對應的數值,現在就可以來計算玩家的得分了。滑動條上結點對應的數值和目標數值越接近,玩家的得分就越高。
為了計算當前回合的玩家得分,我們需要比較滑動條的數值和目標數值之間的差距:

最簡單的方法當然就是直接用currentValue(滑動條的當前數值)減去targetValue(目標數值)。
不過, 當滑動條的結點位置的數值小於目標數值時,得到的差值就是負數。
這個時候我們就得把負數轉換成整數。那麼如果用targetValue減去currentValue可以嗎?一樣的,如果這樣來計算,當滑動條的結點位置的數值大於目標數值時,得到的差值就是負數。
小練習 :想想看,如果我們用人類的語言來描述這個問題,該如何接近呢?先不要想怎麼用程式碼實現,先用普通話來描述一下怎麼來解決這個問題。
好吧,哥又要嘮叨一回了。在寫程式碼之前,先想想在現實生活中會怎麼解決這個問題,先用自己的語言來描述一下問題的解決方式,不管是四川話,普通話,廣東話還是英語。如果你都沒想清楚,那麼寫下來的程式碼肯定也是邏輯混亂一團糟。
我是這樣來想的:
1.“如果滑動條的當前數值大於目標數值,那麼它們之間的差值應該是滑動條的當前數值減去目標數值。
2.反過來,如果目標數值大於滑動條的當前數值,那麼它們之間的差值應該是目標數值減去滑動條的當前數值。
3.最後,如果兩個數值是相同的,那麼它們之間的差值就等於零。”
用上面的方式來計算,無論兩個數值的關係如何,最終的結果總是正數或0,因為我們始終用較大的數值減去較小的數值。
好吧,現在可以來點小學數學計算了。如果滑動條結點的位置在60,目標數值是40,那麼差值就是60-40= 20。如果滑動條結點的位置在10,而目標值為30,那麼差值就是30-10 = 20。
看,就這麼簡單。
術語黨科普:演算法
看到這兩個字,很多人都要心驚膽戰。莫說是產品和設計人員,哪怕是個資深的程式猿,聽到演算法這兩個字都要肅然起敬,敬之如鬼神。傳說中很多程式猿在面試的時候都因為演算法題目不過關而被拒之門外。那麼,作為非程式猿的你,是否看到這兩個字就要打道回府,從此不再學程式設計了呢?
腫麼辦?不要忘了,在 《程式猿生存指南》 這本書的第1頁和最後1頁都有同樣的一句話。Don’t Panic~不要恐慌!
正如很多絕症患者是看到醫院的診斷書後自己被自己嚇死的一樣,很多準程式猿也是被程式碼世界裡面的各種看似高深無比的術語給活活嚇死的,從此和程式碼世界無緣。
那麼,究竟神馬是演算法?如果哥告訴你剛才我們討論的東西就是演算法你會信我嗎?不管你信不信,我反正是相信。通俗點說,演算法就是用來計算某個計算問題的數學步驟。從這個定義出發,我們剛才說的加減法就是演算法,只不過是比較簡單的演算法而已。
聽到演算法二字,你可能立馬會想到當下非常火爆的人工智慧演算法,什麼CNN,RNN,總之沒有個計算機學科的博士想都不要想。

這個當然屬於演算法,而且是對小白來說比較高深的演算法。但生活不僅僅是恐慌,也有輕鬆一刻~
為了讓你不再恐懼,下面再給個簡單的演算法流程示意圖:

上圖是個簡單的決策樹分類演算法,用於判斷某個人會否購買某件產品。
這也叫演算法?是的,不要把演算法看成洪水猛獸,它只是為了幫助我們解決某個特定的問題。
事實上,今天的苦逼程式猿要比上世紀的程式猿幸福的多。原因在於,在電腦科學的發展過程中,已經有很多NB人物為我們研究了各種各樣的或高深或淺顯的演算法。實際上,大學裡面搞計算機研究的大致分兩派,一派專門研究計算機的硬體設計與開發,一派美其名曰計算機軟體工程,實際上都是在研究新的演算法。
然在大學計算機系的課程裡面,演算法和資料結構算得上是真正的掛科屠夫了,但如果你不是想搞研究,或是進行一些大型的科學計算,大可以直接運用現成的很多演算法。而且這些演算法都有對應主流程式語言的原始碼可供參考。
比較著名的演算法有冒泡法,貪心演算法,遞迴法,迭代法,分治法,動態規劃法,分支限界法,回溯法,A*尋路演算法等等。當然,現在人工智慧火熱的時代,演算法更是一下子成了武林絕學中最受歡迎的一類。
在實際使用的過程中,通常我們要做的不是發明一套自己的全新演算法,而是根據所遇到的問題選擇使用已有的演算法,或是在已有的演算法基礎上進行改良和優化。當然,一些比較簡單的問題,比如我們這裡的加減運算,我們可以直接繪製一個流程圖來理順自己的思路。
當然,我的意思不是說演算法不重要,而是說要循序漸進,即便是研究演算法也是 。目前學校教育的錯誤方式是,先塞給你一些東西,然後讓你學習怎麼用,然後就沒有然後了。
個人覺得真正重要的是 瞭解這些演算法是怎麼產生的 ,如果你不清楚這個思維的過程,就是懂1萬種演算法也沒有用。因為實際生活中會遇到無數種在課本上碰不到的問題,面對小毛賊砍過來的一刀,你是該用落英繽紛掌還是大日如來掌?真正有效的做法是根據實際情況見招拆招,把現有的演算法結合起來,甚至需要創造出新的演算法。
那麼,當我們遇到某個需要通過計算才能解決的問題時,該如何下手呢?還是那句話,在開始 寫程式碼之前,先動腦筋思考一下 。先試著用自己的語言把這個問題描述清楚(當然是在大腦裡面,不是讓你對著mm說出來),然後在紙上把解決問題的思路用流程圖的方式畫下來。如果一時想不出來,可以去看看NB人物已經設計好的演算法。客觀的講,太陽底下沒有新鮮事,以我們目前水平所遇到的問題,前人百分99.99999都已經遇到過,大可以去直接借鑑。當然有一個前提是,即便是借鑑別人的演算法和解決思路,我們自己也需要完全理解,起碼要能看懂。
所以,寫程式碼和寫長篇小說有點類似,如果你在哪一塊卡住了,不要對著電腦發呆崩潰,而應該轉過身來看看窗外的風景,或者開個小視窗看看mm。同時在你的大腦裡面想想應該怎樣一步步解決這個問題,最好是拿出一張紙,把自己想到的思路用流程圖的方式畫出來。雖然程式猿的工作價值表面看起來似乎是體現在一行行的程式碼上,其實真正高效的程式猿更需要思考和在紙上寫寫畫畫。當你頭腦中和紙上有了解決問題的方法之後,轉換成程式碼就是輕而易舉的事情了。
記住, 程式猿的工作不是體力活,而是腦力活,除非你想一輩子當碼農。 一個高效的程式猿可以在很短的時間內通過思考,通過寫寫畫畫,通過借鑑前人解決問題的思路來處理所遇到的問題,效率堪比苦逼程式猿的10倍甚至更高。如果恰恰相反,你不幸就真成了所謂的碼農。如果你認為自己是碼農,那是因為你在偷懶,不是在鍵盤上敲打偷懶,而是自己在思考上偷懶了。
記得有個科技界大佬說過一句話,不要用戰術上的勤奮替代戰略上的懶惰,這一點對程式猿同樣適用~
打住打住,話說還能跟得上哥的思維嗎?
現在我們要回到正事了。回到當前這個遊戲,我們需要計算玩家的得分。剛才哥已經用說話的方式解決了這個問題,現在該用程式碼來體現出來了。
對這個問題,可以用兩種方式來具體實現,讓我一一道來。
第一個:
var difference: Int if (currentValue > targetValue) { difference = currentValue - targetValue } else if (targetValue > currentValue) { difference = targetValue - currentValue } else { difference = 0 }
這裡我們遇到了一個和if有關的新程式碼邏輯。if就是如果的意思,else if 就是如果不是這樣,而是如果... 其實你也猜到了,這種類似英語的描述方式告訴我們如何來進行判斷。
通常來說它的結構是這樣的:
if (something is true) { //then do this } else if (something else is true) { //then do that instead } else { //do something when neither of the above are true }
我們在if後面的()括號裡面放上了一個條件判斷語句。
如果判斷的結果是true,也就是說currentValue的數值大於targetValue,那麼就會執行花括號裡面緊跟的程式碼。如果判斷的結果不是true,程式就會檢視else if條件,然後再次進行判斷。很可能我們會使用多個else if,而程式就會從頭到尾逐一進行判斷,直到遇到某個判斷結果是true的情況。如果沒有一個結果是true,就會執行最後的else裡面的語句。
在剛才的這段程式碼裡面,首先我們建立了一個本地變數difference,用它來儲存計算結果。我們希望這個數值是整數或者0,所以int型別的變數是符合要求的:
var difference: Int
接著我們判斷currentValue和targetValue之間的關係。
首先判斷currentValue是否大於targetValue:
if (currentValue > targetValue) {
這裡的>就是大於號的意思,江湖人稱大於操作符。當currentValue裡面所儲存的數值大於targetValue裡面儲存的數值時,currentValue > targetValue的判斷結果就是true。
此時就會執行下面的語句:
difference = currentValue - targetValue
我想這句程式碼基本上人人都能看懂吧,我們用currentValue的數值減去targetValue的數值,然後把結果儲存在difference裡面。和小學數學的表達一模一樣,只是兩邊不是具體的數字,而是變數。
還要廢話一句,你會看到這裡哥用的變數名稱其實是有選擇的。
很多程式猿寫的程式碼會是這樣的:
a = b - c
然後下一個接手的程式猿就會感謝你八百輩子祖宗,或者在幾個月後的某個深夜,你需要自己對著電腦螢幕發呆,顧不上和mm的溫情約會了。
這個涉及到所謂的編碼規範和編碼習慣的問題。如果我們把程式碼世界裡面的一切都看做生命體,那麼起碼你要給人家起個好聽和有意義的名字吧。你爸媽給你取名字會隨便用小三,小二,小十九這樣簡單但卻毫無意義的名字嗎?當然,不排除部分人的名字是這樣的,比如張三很可能在家裡排行老三。又或者周星星同學在《唐伯虎點秋香》和《千王之王》中都適用9527的代號~
無論是本地變數,例項變數,還是屬性,包括方法名稱,函式名稱,我們都儘可能用一眼看起來就大概知道什麼意思的名稱。 當然本地變數的命名可以稍微放鬆一點,但這樣做也是沒有壞處的。如果你把語言和程式中的所有東西看做有生命的個體,相信你會從中找到更多的樂趣。
繼續回到我們的if條件語句。如果currentValue和targetValue的數值相同或是略小,那麼currentValue > targetValue 的結果就是false(Objective-C裡面的術語,表示不正確),這個時候我們會忽略花括號緊跟的語句,而是直接切換到下一個條件語句:
} else if (targetValue > currentValue) {
同樣的事情會再次發生,只不過這次targetValue和currentValue的角色顛倒過來了。只有當targetValue的數值更大的時候,才會執行下面的語句:
difference = targetValue - currentValue
用targetValue裡面儲存的數值減去currentValue裡面儲存的數值,然後把結果儲存在difference裡面。
最後還有一種情況,就是兩個變數裡面的數值相等。也就是說我們的玩家太NB了,一發命中。這個時候的差值就是0.
} else { difference = 0 }
好了,到目前為止,我們已經搞定了人生中的第一個演算法。
現在可以把這個演算法放到動作方法裡面了。
在Xcode裡面切換到ViewController.swift,然後修改showAlert()方法的程式碼:
@IBAction func showAlert(){ //1.定義y一個用來儲存差值的變數 var difference: Int //2.計算差值的具體數值 if currentValue > targetValue { difference = currentValue - targetValue }else if targetValue > currentValue { difference = targetValue - currentValue }else{ difference = 0 } //3.設定訊息體的內容 let message = "滑動條的當前數值是: \(currentValue)" + "\n目標數值是: \(targetValue)" + "\n兩者的差值是: \(difference)" let alert = UIAlertController(title:"科瓦奇您好", message:message, preferredStyle: .alert) let action = UIAlertAction(title:"OK",style: .default, handler: nil) alert.addAction(action) present(alert, animated: true, completion: nil) startNewRound() }
在以上程式碼中,我們更改的是對應註釋編號1,2,3的程式碼,並且把差值的資訊也放到了提示對話方塊裡面。
需要注意的是:
Swift語言對空格拼寫的要求非常嚴格 ,所以在變數和操作符(比如+)之間必須新增空格,否則你的程式碼裡面可能會提示出錯~
敲黑板時間:
再次強調一下,在整個學習過程中,請大家切記一定千萬確保不要直接拷貝貼上程式碼,而是要自己親自一個個字母敲上去。如果你做不到這一點,那麼建議從現在開始立即下船。因為不這樣做的話,船翻了你根本都不知道是怎麼翻的。
現在點選Run執行一下看看。

看著這個小小的應用一步步接近自己預設的目標,是不是有那麼一點小激動呢~
苦了一天,又到發放福利的時間了。明天再見。

本人聯絡方式:
微信:iseedo
郵件: ofollow,noindex" target="_blank">[email protected]
QQ討論群: 375143733
示例專案:
iOSCourse" target="_blank" rel="nofollow,noindex">eseedo/iOSCourse如有疑問,請先發送郵件到我的郵箱: [email protected] eseedo/iOSCourse 如有疑問,請先發送郵件到我的郵箱: [email protected]
我會在收到郵件後儘早答覆。
也可以加微信,但可能不是很合適的答疑途徑。
另外,為了節省大家的寶貴時間,提高溝通效率,請在提問的時候儘量附上 專案原始碼以及以下資訊 :
1.開發環境(系統版本,Xcode和iOS版本)
2.問題描述及重現(想實現什麼效果,結果是怎樣的,具體涉及到什麼操作)
3.為解決問題所做的努力(做了哪些嘗試,分別是怎樣的結果)