Episode 47 — 21 點
完整操作
下注
lkj玩家在叫牌前要先下賭金,賭金會從本金拿取
var total = 5000
var bet = 0@IBOutlet weak var betLabel: UILabel!
@IBOutlet weak var totalLabel: UILabel!
先宣告兩個變數跟標籤改變本金跟賭金
@IBAction func changeBet(_ sender: UIStepper) {
betLabel.text = "\(Int(sender.value))"
bet = Int(sender.value)
total = Int(sender.maximumValue)-bet
totalLabel.text = "\(total)"
}
利用 stepper 的值來改變賭金與本金
發牌
發牌分發給玩家跟發給莊家,把這兩根拆開會比較好寫,但發牌前要先洗牌
洗牌
var nums = [Int]()
var suits = [String]()// d = spade, c = heart, b = diamond, a = club
let codes = ["d", "c", "b", "a"]
我除了宣告數字跟花色外,還另外給花色一個代碼
func shuffleCards(){
for suit in 0...3 {
for num in 1...13 {
nums.append(num)
suits.append(codes[suit])
}
}
nums.shuffle()
suits.shuffle()
}
分別把數字跟花色變成 52 個,然後在洗牌
發牌給莊家
var banker = [String]()
宣告一個花色加數字的矩陣給莊家、假如 “4a” 就是梅花四
//發牌給莊家
func serveBanker(image: Int, time: Int){ banker.append("\(suits[0]+String(nums[0]))")
bankerCardImageViews[image].image = UIImage(named: "\(banker[image])")
//蓋牌
let animator = UIViewPropertyAnimator(duration: TimeInterval(time), curve: .linear) {
self.bankerCardImageViews[image].alpha = 1
}
animator.startAnimation()
//人像為十點
if nums[0] == 13 || nums[0] == 12 || nums[0] == 11 {
nums[0] = 10
}
//一點為十一點
if nums[0] == 1 {
if bankerValue < 11 {
nums[0] = 11
}
}
bankerValue += nums[0]
nums.removeFirst()
suits.removeFirst()
}
每發一次牌,數字矩陣跟花色矩陣的第一個會給出去,假設數字為[1,2,3],花色為[“a”, “b”, “c”],發的牌就是 “a1” 梅花 A。
因為發出去了所以最後數字跟花色記得除去第一個值。
發牌給玩家
var player = [String]()
宣告一個花色加數字的矩陣給玩家、假如 “4a” 就是梅花四
func servePlayer(image: Int, time: Int) {
//補足卡牌
if nums.count < 10 {
shuffleCards()
}
player.append("\(suits[0]+String(nums[0]))")
playerCardImageViews[image].image = UIImage(named: "\(player[image])")
let animator = UIViewPropertyAnimator(duration: TimeInterval(time), curve: .linear) {
self.playerCardImageViews[image].alpha = 1
}
animator.startAnimation()
//人像為十點
if nums[0] == 13 || nums[0] == 12 || nums[0] == 11 {
nums[0] = 10
}
//一點為十一點
if nums[0] == 1 {
if bankerValue < 11 {
nums[0] = 11
}
}
playerValue += nums[0]
nums.removeFirst()
suits.removeFirst()
playerValueLabel.text = "\(playerValue)"
}
跟莊家做法大同小異,只是這邊我多判斷如果牌數不夠要再補牌。
叫牌
下完注較第一次牌會各給莊家跟玩家兩張牌,且莊家的第一張牌會蓋住。玩家如果一直加牌可能會爆牌、過五關或21點。
//叫牌
@IBAction func call(_ sender: Any) {
betStepper.isHidden = true
callButton.isHidden = false
giveUPButton.isHidden = false
stopButton.isHidden = false
//蓋牌
let animator = UIViewPropertyAnimator(duration: 0.5, curve: .linear) {
self.backCardImageView.alpha = 1
}
animator.startAnimation()
//首次發牌
if image == 0 {
firstServe()
image += 2
checkPlayer()
} else if image < 5 {
servePlayer(image: image, time: 1)
image += 1
checkPlayer()
//過五關
if image == 5 && playerValue <= 21 {
playerResult(win: true,times: 3)
resultLabel.text = "玩家過五關!"
hideButtons()
readyToAgain()
}
}
當image 為零代表發的是第一張牌的話,就連發兩次。再如果小於五張則發一張給玩家,如果玩家拿到五張就過五關。
//首輪發牌
func firstServe(){
var cardImage = 0
var time = 0
for _ in 0...1 {
time += 1
serveBanker(image: cardImage,time: cardImage+1)
time += 1
servePlayer(image: cardImage, time: time)
cardImage += 1
}
}
第一次發牌要連續發兩張
爆牌
//檢查玩家手牌狀況
func checkPlayer(){
if playerValue > 21 {
resultLabel.text = "玩家爆牌"
callButton.isHidden = true
readyToAgain()
playerResult(win: false, times: 0)
hideButtons()
} else if playerValue == 21 {
resultLabel.text = "玩家 Black Jack!"
callButton.isHidden = true
readyToAgain()
playerResult(win: true, times: 2.5)
hideButtons()
}
}
玩家的手牌超過 21 點即爆牌
//玩家輸贏賭金結果
func playerResult(win: Bool, times: Float){
//贏的話根據倍數獲得獎金
if win == true {
total += Int(times*Float(bet))
totalLabel.text = "\(total)"
resultLabel.text! += "\n玩家獲得 $\(Int(times*Float(bet)))"
} else {
if resultLabel.text != "平手" {
resultLabel.text! += "\n玩家損失 $\(bet)"
}
}
bet = 0
betLabel.text = "\(bet)"
betStepper.maximumValue = Double(total)
betStepper.value = 0
}
玩家爆牌賭金會直接歸零,本金自然也就少了。
停牌
玩家如果沒爆牌,可以選擇停牌來看莊家的牌況是怎樣以決定輸贏。但基本上小於 17 點就會輸,因為莊家的點數一定超過 17 點。
//停牌
@IBAction func stop(_ sender: Any) {
image = 2
hideButtons()
//開莊家首張牌
let animator = UIViewPropertyAnimator(duration: 0.5, curve: .linear) {
self.backCardImageView.alpha = 0
}
animator.startAnimation()
//莊家點數不足17點時需補發牌
if bankerValue < 17 {
while bankerValue < 17 && image != 5 {
serveBanker(image: image, time: 1)
image += 1
}
checkBanker()
} else {
checkBanker()
}
checkIsBankrupt()
}
當莊家牌不足17點會用 while 加牌直到超過 17點五張牌為止。
//檢查莊家手牌狀況
func checkBanker(){
//爆牌
if bankerValue > 21 {
resultLabel.text = "莊家爆牌"
playerResult(win: true, times: 2)
//黑傑克
} else if bankerValue == 21 {
resultLabel.text = "莊家 Black Jack!"
playerResult(win: false, times: 0)
} else {
//莊家手牌大
if bankerValue > playerValue {
resultLabel.text = "莊家獲勝"
playerResult(win: false, times: 0)
//玩家手牌大
} else if bankerValue < playerValue {
resultLabel.text = "玩家獲勝"
playerResult(win: true, times: 2)
//平手
} else {
resultLabel.text = "平手"
total += bet
totalLabel.text = "\(total)"
bet = 0
betStepper.maximumValue = Double(total)
betStepper.value = 0
betLabel.text = "\(bet)"
}
}
hideButtons()
readyToAgain()
bankerValueLabel.text = "\(bankerValue)"
}
最後階段就是用莊家的點數跟玩家點數比較。或看莊家點數是 21 點或爆牌。
保險
當莊家的第二張牌為 Ace 時,玩家可以選擇買保險。如果莊家是 21 點,玩家可以獲得兩倍理賠,當莊家不是 21 點,保金就會被收走。
//叫牌
@IBAction func call(_ sender: Any) {
betStepper.isHidden = true
callButton.isHidden = false
giveUPButton.isHidden = false
stopButton.isHidden = false
//蓋牌
let animator = UIViewPropertyAnimator(duration: 0.5, curve: .linear) {
self.backCardImageView.alpha = 1
}
animator.startAnimation()
//首次發牌
if image == 0 {
firstServe()
image += 2
checkPlayer()
} else if image < 5 {
servePlayer(image: image, time: 1)
image += 1
checkPlayer()
//過五關
if image == 5 && playerValue <= 21 {
playerResult(win: true,times: 3)
resultLabel.text = "玩家過五關!"
hideButtons()
readyToAgain()
}
}
//加注
if playerValue == 11 {
doubleButton.isHidden = false
}
//保險
if resultLabel.text?.contains("點") == true {
insuranceButton.isHidden = true
} else if banker[1].contains("1") && banker[1].count == 2 && total > 500 && playerValue < 21 {
insuranceButton.isHidden = false
}
checkIsBankrupt()
}
在玩家第一次叫牌時,就能判斷使否需要投保。
//使用保險
@IBAction func insure(_ sender: Any) {
insuranceView.isHidden = false
okButton.isHidden = true
insuranceStepper.maximumValue = Double(total)
}
//調整保險金
@IBAction func makeInsurance(_ sender: UIStepper) {
total = Int(insuranceStepper.maximumValue) - Int(insuranceStepper.value)
totalLabel.text = "\(total)"
insuranceLabel.text = "\(Int(insuranceStepper.value))"
if sender.value == 0 {
okButton.isHidden = true
} else {
okButton.isHidden = false
}
}
//使用保險金檢查是否莊家為黑傑克
@IBAction func checkIsBlackJack(_ sender: Any) {
if bankerValue == 21 {
insuranceStepper.value *= 2
total += Int(insuranceStepper.value)
resultLabel.text = "莊家為 21 點\n玩家獲得 $\(Int(insuranceStepper.value))"
} else {
resultLabel.text = "莊家非 21 點\n玩家損失 $\(Int(insuranceStepper.value))"
insuranceStepper.value = 0
}
insuranceLabel.text = "0"
insuranceStepper.maximumValue = 0
insuranceView.isHidden = true
insuranceButton.isHidden = true
}
按下保險會跳出保金視窗,選定保金後可以查看莊家是否為 21 點。
加注
當玩家目前點數總和為 11 點,可以選擇加注賭金。但加注後只會發一張牌且立即開結果。
//叫牌
@IBAction func call(_ sender: Any) {
betStepper.isHidden = true
callButton.isHidden = false
giveUPButton.isHidden = false
stopButton.isHidden = false
//蓋牌
let animator = UIViewPropertyAnimator(duration: 0.5, curve: .linear) {
self.backCardImageView.alpha = 1
}
animator.startAnimation()
//首次發牌
if image == 0 {
firstServe()
image += 2
checkPlayer()
} else if image < 5 {
servePlayer(image: image, time: 1)
image += 1
checkPlayer()
//過五關
if image == 5 && playerValue <= 21 {
playerResult(win: true,times: 3)
resultLabel.text = "玩家過五關!"
hideButtons()
readyToAgain()
}
}
//加注
if playerValue == 11 {
doubleButton.isHidden = false
}
//保險
if resultLabel.text?.contains("點") == true {
insuranceButton.isHidden = true
} else if banker[1].contains("1") && banker[1].count == 2 && total > 500 && playerValue < 21 {
insuranceButton.isHidden = false
}
checkIsBankrupt()
}
每次叫牌時可以知道玩家是否為 11 點且跳出加注按鈕。
//加注
@IBAction func double(_ sender: Any) {
hideButtons()
total -= bet
bet *= 2
totalLabel.text = "\(total)"
betStepper.maximumValue = Double(total)
betStepper.value = 0
betLabel.text = "\(bet)"
servePlayer(image: 2, time: 1)
checkPlayer()
if playerValue < 21 {
stop((Any).self)
}
}
加注後賭金多一倍,本金會減少。玩家如果不是 21 點或爆牌,就開莊家的牌比較。