iOS App 程式系列 # BullsCows

Rennen Choong
Sep 9, 2018 · 11 min read

Code-breaking mind games/1A2B

相信大家都知道可能有聽過 1A2B,它是一個猜數字的小遊戲,而「Bulls and Cows」 其實就是 1A2B 的別名。想說利用「Bulls and Cows」比較有畫面而且動物很可愛,遊戲基本上的規則就是猜 4 個不同的數字,然後根據 “Bulls” 和 “Cows” 的線索去猜測 4 個數字, “Bulls” 代表數字在對的位置;而 “Cows” 則代表數字在錯的位置,進而去推斷密碼。

了解「Bulls and Cows」的基本規則以後就可以開始製作 App 嘍!基本上就只有 5 個畫面,從左邊第 1 張就是 LaunchScreen,只會出現 3 秒的頁面,其實就是廢廢的頁面,再來就是第 2 頁是首頁,只有兩個按鈕一個是 “START” 開始遊戲,另一個是 “i” 解說遊戲,都是利用Button 再用 segue 連至指定的頁面。第 3 頁則是「Bulls and Cows」的基本解說,看完解說及可以進入遊戲頁面啦,重點的程式都著重在這頁和最後結果的頁面。以下的解說就是針對最後兩個頁面進行說明。

從以上的遊戲畫面中,分別使用了 5 個 UIKit 的元件,包括文字標籤 UILabel 、 輸入多行文字 UITextView 以及最常用到的按鈕 UIButton,分別設定 TimeLabel、ChanceLabel 、InputLabel 和 R esultTextView 為 IBOutlet 輸出口,另外將 NumbeButtons 在 ViewDidLoad 下拉為 IBAction 操作口。完成元件設定後,即可以開始進入程式的部分。

首先,遊戲頁面的流程基本是從點擊 “START” 後,遊戲頁面跳出後時間開始計算,在輸入 4 個數字後點擊 “OK”,ResultTextView就會出現輸入的數字+ “Bulls” + “Cows” 的結果,而且每次點擊 “OK” 左上角的機會次數就會減少 1 個直到答對或沒有機會為止。以下就是每個動作的仔細解說:

  1. 設定時間:
  • 畫面點擊 “START” 後,進入遊戲頁面,並開始計時。
  • 利用 scheduledTimer 類別設定時間。
  • 主要的參數包括 timeInterval =每間隔幾秒執行一次、self =執行的對象、selector = 執行哪一個 func、userInfo = 傳入nil即可以及repeats =是否重複執行。
//設定時間func timerStart(){timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.updateTime), userInfo: nil, repeats: true)}@objc func updateTime(){totalTime += 1
timeLabel.text = String(totalTime/60) + ":" + String(format:"%02d", totalTime%60)
}

2. 設定遊戲規則

  • 「Bulls and Cows」遊戲中最主要就是猜測數字,遊戲開始時每一回合都需要產生亂數 (randon number) 才能開始遊戲,所以首先需要知道如何產生亂數。
  • 產生亂數的指令如下:arc4random_uniform函數求一個0~9的隨機數,而它只能接受 UInt32 類型的參數。
//設定遊戲規則func initial(){var nums = Array(0...9)
for i in 0...3 {
let index = Int(arc4random_uniform(UInt32(nums.count)))
answer[i] = nums[index]
nums.remove(at: index)
} while !input.isEmpty {let letter = input.popLast() //popLast 返回 nil
numberButtons[letter!].isEnabled = true
let
index = inputLabel.text?.index(inputLabel.text!.startIndex,
offsetBy: input.count*3)
//startIndex 第一个字符的位置
//offsetBy 偏移量,可以是正数或者负數

inputLabel.text?.remove(at: index!)
inputLabel.text?.insert("_", at: index!)
}
}

3. 設定警告⚠️提示框

請忽略錯字
  • 遊戲當中,如果沒有輸入 4 個數字,再按 “OK” 系統可能會壞掉。因此可以使用 UIAlertController,產生警告提示框。
  • 創建的步驟首先是需要創建 UIAlertController,指定警報控制器樣式。這裡的 preferredStyle: 參數有UIAlertControllerStyleAlert 和 UIAlertControllerStyleActionSheet 兩種,這裡我們要創建的是 Alert View,所以使用第一種。
  • 再來就是向警告提示框添加按鈕,最後再顯示 UIAlertController。
//創建 UIAlertController
let optionMenu = UIAlertController(title: nil, message: "Please insert 4 differnt digits", preferredStyle: .alert)
//添加按鈕
let cancelAction = UIAlertAction(title: "Comfirm", style: .cancel, handler: nil)
optionMenu.addAction(cancelAction)//顯示 UIAlertController
present(optionMenu, animated: true, completion: nil)

4. TextView 出現結果

  • 結果 UITextView 拉出 IBOutlet 以後,在輸入 4 個數字以後,點擊 “OK” 後在 TextView 出現結果。
  • 利用 「\()」 來輸出變量,主要是可以在 String 中插入值的方法,再利用 Swift 文字型字面量的特殊符號,如水平 Tab (Horizontal Tab) 「\t」 以及換行(Line Feed)「\n」
  • 最後再用用 scrollRangeToVisible 函數進行滾動,可以跳動到最後一行內容上。
//設定TextView的Outlet@IBOutlet weak var resultRecord: UITextView!//ViewDidLoad下產生,點擊“OK”後在TextView出現resultRecord.text! += "\(input[0])\(input[1])\(input[2])\(input[3])\t\t\(acount)\t\t\t\(bcount)\n"resultRecord.font = UIFont.systemFont(ofSize: 25)resultRecord.scrollRangeToVisible(NSMakeRange(resultRecord.text.characters.count-1, 0))

5. 機會等於0時,轉移至成績頁面

  • 機會的 UILabel 拉出 IBOutlet 以後,在輸入 4 個數字以後,點擊 “OK” 後 10 個機會中就會減少一個,知道等於 0 以後,跳至結果頁面,並出現正確的答案。
  • 因為換至下一頁沒有特定的按鈕,而是依機會數目的條件作為進入下一頁的條件,因此沒有辦法以建立 Segue 的方法進入下一頁,因此可以使用 instantiateViewController 建立 controller。
  • 利用 instantiateViewController 建立 Controller,主要分為兩個步驟, 第一設定 Storyboard ID。在 Storyboard 點選該畫面的 View Controller,則可在 Show The Identity Inspector 內的Inspector設定 Storyboard ID。第二從程式產生 Storyboard 上的 Controller,利用 storyboard?.instantiateViewController() 產生 Controller。
設定Storyboard ID
//設定Chance的Outletvar chance = 10
@IBOutlet weak var chanceLabel: UILabel!
//ViewDidLoad下產生,點擊“OK”後Chance -1chance -= 1
chanceLabel.text = "\(chance)"
if chance == 0 {timer.invalidate()
over = true
addRecord(win: false, time: totalTime)
let controller = self.storyboard?.instantiateViewController(withIdentifier: "ResultViewController") as! ResultViewController
controller.win = false
controller.time = totalTime
controller.answer = self.answer
self.present(controller, animated: false, completion: nil)
}

6. 遊戲成績顯示

  • 跳至成績頁面後,如果贏了會產生 “win” 的圖片和所需的時間,輸了則會產生 “lose” 的圖片,並且在 resultLabel 中出現正確的答案。
class ResultViewController: UIViewController {var win:Bool?
var time:Int?
var answer:[Int]?
var resultRecord:String?
@IBOutlet weak var resultImage: UIImageView!
@IBOutlet weak var resultLabel: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
if win! == true {resultImage.image = UIImage(named: "win")
resultLabel.text = "Time:" + String(time!/60) + ":" + String(format: "%02d", time!%60)
}else {resultImage.image = UIImage(named: "lose")
resultLabel.text = "Correct Answer:\n\(answer![0])\(answer![1])\(answer![2])\(answer![3])"
}

以上為總結,當然參考了許多前輩的資料,還有很多需要學習,有興趣可以下載玩一玩,以下為 Github 網址:

參考資料:

Here’s Come iOS App Newbie.

彼得潘的 Swift iOS App 開發教室

學習 Swift iOS App 開發的學生作品集

    Rennen Choong

    Written by

    "Don't let the fear of striking out keep you from playing the game."

    彼得潘的 Swift iOS App 開發教室

    學習 Swift iOS App 開發的學生作品集