新Swiftで行こう…第71回「ポーカー8解説」 田部井保
ストレートの判定の拡張です。
//
// ViewController.swift
// Poker
//
// Created by 保 Tabei on 2024/10/03.
//
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//5枚分のラベルを配置する
for i in 0 ..< 5 {
//ラベルを生成する
let lbl = UILabel(frame: CGRectMake(0, 0, 50, 21))
//ラベルの中心を指定する
lbl.center = CGPointMake(100 + 50 * CGFloat(i), 250)
//ラベルのテキスト配置を中央にする
lbl.textAlignment = NSTextAlignment.center
//ラベルの表示をカードが裏になっている様にする
lbl.text = "⬛️"
//ラベル配列に追加する
eachCard += [lbl]
//ラベルを画面上に配置する
self.view.addSubview(lbl)
//選択ボタンを生成する
let btn = UIButton(frame: CGRectMake(0, 0, 50, 21)) as UIButton
//ボタンの中心を指定する
btn.center = CGPointMake(100 + 50 * CGFloat(i), 300)
//ボタンのタイトルを「off」にする
btn.setTitle("off", for: .normal)
//ボタンのタイトルの色をグレーにする
btn.setTitleColor(UIColor.systemGray, for: .normal)
//ボタンが押された時に「btnTapped」関数が呼ばれるようにする
btn.addTarget(self, action: #selector(btnTapped), for: .touchUpInside)
//ボタンのタグに0から4の目印を付ける
btn.tag = i
//選択ボタン配列に追加する
eachButton += [btn]
//選択ボタンを画面上に配置する
self.view.addSubview(btn)
}
}
///選択ボタンが押された時に動作する関数
@objc func btnTapped(sender: UIButton) {
//もしタイトルが「off」なら
if sender.currentTitle == "off" {
//タイトルを「on」にして
sender.setTitle("on", for: .normal)
//選択ボタンの所のカードを裏にする
eachCard[sender.tag].text = "⬛️"
//もしタイトルが「on」なら
} else {
//タイトルを「off」にして
sender.setTitle("off", for: .normal)
//選択ボタンの所のカードを表にする
//カード番号はタグに入れてある
let card = eachCard[sender.tag].tag
//カード一時保持変数
var strCard: String
//ジョーカーの場合
if card == 52 {
strCard = "JK"
//ジョーカー以外の場合
} else {
//カード一時保持変数にマークとナンバーを保持
strCard = mark[card / 13] + number[card % 13]
}
//選択ボタンの所のカードを表示
eachCard[sender.tag].text = strCard
}
}
///マーク保持配列
let mark: [String] = ["♣️","♦️","❤️","♠️"]
///ナンバー保持配列
let number: [String] = ["A","2","3","4","5","6","7","8","9","T","J","Q","K"]
///カード枚数保持定数
enum EnumCard {
static let Count = 52
}
///既に出ているかチェックする、出ていたらtrue
///出ていなかったらfalse、とりあえず
///EnumCard.Count枚分falseで埋める
var check = [Bool](repeating: false, count: EnumCard.Count)
///残り枚数を保持する変数
var count = EnumCard.Count
///ラベル配列
var eachCard: [UILabel] = []
///選択ボタン配列
var eachButton: [UIButton] = []
///カードを引いてiで指定した位置に出す
func put(i: Int) {
//今回引いたカードを特定する変数
var card = 0
//乱数を0から残り枚数−1の範囲で発生させる
let randInt = Int.random(in: 0 ..< count)
//発生させた乱数分ループ
for j in 0 ... randInt {
//カードが既に出ていたらcard + 1
while check[card] {
card += 1
}
//jがrandIntに達していなければcard + 1
if j < randInt {
card += 1
}
}
//新たに出たカード既に出ているとマークする
check[card] = true
//残り枚数を1減算
count -= 1
//カード一時保持変数
var strCard: String
//ジョーカーの場合
if card == 52 {
strCard = "JK"
//ジョーカー以外の場合
} else {
//カード一時保持変数にマークとナンバーを保持
strCard = mark[card / 13] + number[card % 13]
}
//iの値によって表示位置にカード表示
eachCard[i].text = strCard
//表示したラベルのtagにcardを保存しておく
eachCard[i].tag = card
}
///役判定関数
func flush() {
//チェック変数
var ck = 0
//基準カード
for i in 0 ..< 4 {
//比較カード
for j in i + 1 ..< 5 {
//ナンバーが同じなら
if eachCard[i].tag % 13 == eachCard[j].tag % 13 {
//チェック変数を+1する
ck += 1
}
}
}
//ペアのメッセージ保持変数
var msg: String
//チェック変数の値によりペア名を指定する
switch ck {
case 1:
msg = "ワンペア"
case 2:
msg = "ツーペア"
case 3:
msg = "スリーカード"
case 4:
msg = "フルハウス"
case 6:
msg = "フォーカード"
default:
msg = ""
}
//ペアなら
if ck > 0 {
//ペアダイアログを表示
let alert = UIAlertController()
alert.title = "ペア"
alert.message = msg + "です"
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true, completion: nil)
//ペア以外
} else {
//フラッシュ変数とりあえずフラッシュ
var chk = true
//1番目(0の位置)のマークを取得(0〜3)
let mark: Int = eachCard[0].tag / 13
//2番目から5番目の位置のマークと比較
for i in 1 ..< 5 {
//1番目のマークと2〜5番目のマークを比較して違っていたら
if mark != eachCard[i].tag / 13 {
//フラッシュ変数をfalse(フラッシュではない)に
chk = false
//ループを終了
break
}
}
//エースがあるか
var isAce = false
//キングがあるか
var isKing = false
//5枚のカードについて調べる
for i in 0 ..< 5 {
//エースがあったら
if eachCard[i].tag % 13 == 0 {
isAce = true
}
//キングがあったら
if eachCard[i].tag % 13 == 12 {
isKing = true
}
}
//エースとキング両方あったらup変数をtrueに
let up = isAce && isKing
//最小値変数を宣言
var min = 0
//最大値変数を宣言
var max = 0
//1番目から5番目までループ
for i in 0 ..< 5 {
//変数にそのカードのナンバーを入れる
var val = eachCard[i].tag % 13
//エースとキング両方があった場合
if up {
//4以下のカードに
if val < 4 {
//13加える
val = val + 13
}
}
//1番目ならmin,maxにvalを入れる
if i == 0 {
min = val
max = val
//2番目以降
} else {
//変数が最小値より小さい時
if val < min {
//最小値を変数に
min = val
}
//変数が最大値より大きい時
if max < val {
//最大値を変数に
max = val
}
}
}
//ストレート変数とりあえずストレートでない
var chk2 = false
//ロイヤル判定とりあえずロイヤルでない
var chk3 = false
//最大値と最小値の差が丁度4の時
if max - min == 4 {
//ストレート変数、ストレートに
chk2 = true
//最大がエースなら
if max == 13 {
//ロイヤル
chk3 = true
}
}
//メッセージ保持変数
var msg: String = ""
//ロイヤルなら
if chk3 {
msg = "ロイヤル"
}
//ストレートなら
if chk2 {
//メッセージ変数にストレートを追加する
msg += "ストレート"
}
//フラッシュなら
if chk {
//メッセージ変数にフラッシュを追加する
msg += "フラッシュ"
}
//フラッシュ変数がtrueまたはストレート変数がtrue
if chk || chk2 {
//ストレート、フラッシュダイアログを表示
let alert = UIAlertController()
alert.title = msg
alert.message = msg + "です"
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true, completion: nil)
}
}
}
///開始ボタン押下時処理
@IBAction func btnGoTouch(_ sender: Any) {
//リセット
//全カード出ていない事に
for i in 0 ..< EnumCard.Count {
check[i] = false
}
//残り枚数52枚
count = EnumCard.Count
//5枚引く
for i in 0 ..< 5 {
//カードを引いてiの位置に出力する
put(i: i)
}
//役判定
flush()
}
///再配布ボタン押下時処理
@IBAction func btnReTouch(_ sender: Any) {
//5枚分調べる
for i in 0 ..< 5 {
//選択ボタンのタイトルがonなら
if eachButton[i].currentTitle == "on" {
//カードを引いてiの位置に出力する
put(i: i)
//選択ボタンのタイトルをoffにする
eachButton[i].setTitle("off", for: .normal)
}
}
//役判定
flush()
}
}
エースとキングがあるか調べ、両方あったらAから4を13から16にします。こうすれば、最大と最小の差が4ならストレートという事になります。❤️K♠️A♣️2♣️3♦️4、これは12から16となるので16−12=4です。
最初1枚目のカードナンバーを min と max に入れて、2枚目以降のカードと比較していましたが、今回はループを1枚目からにして、1枚目だった時は比較ではなく、min と max にカードナンバーを入れ、2枚目以降なら比較するというロジックにしてあります。最初通常版では、最初1枚目のカードナンバーを min と max に入れて、エースとキングが両方あってもAから4に13を足していませんでした。そこで、1枚目がAから4の時、ストレートと判定されないバグがありました。今回は、そこを修正してあります。
ストレート(最大と最小の差が4)で、最大が13(Aを示す0に13足したもの)の場合は、ロイヤルとなります。♣️T❤️J♣️Q♦️K♠️Aでナンバーは9から13となります。単に最大が13だとブタも含んでしまう為、ストレートで最大が13の場合に限ります。
ロイヤルならロイヤル、そしてストレートならストレートを足し、そしてフラッシュなら更にフラッシュを足す、というロジックにしておけば、ロイヤルストレートフラッシュ、ロイヤルストレート、ストレートフラッシュ、フラッシュ、ストレートに対応できます。ロイヤルやロイヤルフラッシュという役はありません。ロイヤルの場合必ずストレートが付きます。