iOS App 程式系列 # BullsCows

--

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.

--

--