新Swiftで行こう…第61回「トランプ3解説」 田部井保

目次 通常版

 無限ループを防ぐ方法、カードの残り枚数を数える。

//
//  ViewController.swift
//  Card
//
//  Created by 保 Tabei on 2024/09/25.
//

import UIKit

class ViewController: UIViewController {
    ///カード表示用ラベル
    @IBOutlet weak var lblCard: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    ///マーク保持配列
    let mark: [String] = ["♣️","♦️","❤️","♠️"]
    ///ナンバー保持配列
    let number: [String] = ["A","2","3","4","5","6","7","8","9","T","J","Q","K"]

    ///カード枚数保持定数
    enum EnumCard {
        static let Count = 53
    }

    ///残り枚数
    var rest = EnumCard.Count

    ///既に出ているかチェックする、出ていたらtrue
    ///出ていなかったらfalse、とりあえず
    ///EnumCard.Count枚分falseで埋める
    var check = [Bool](repeating: false, count: EnumCard.Count)

    ///ボタン押下時処理
    @IBAction func btnGoTouch(_ sender: Any) {
        //残り枚数0なら初期化
        if rest == 0 {
            //check配列を全部falseに
            for i in 0 ..< EnumCard.Count
            {
                check[i] = false
            }
            //残り枚数をEnumCard.Countに
            rest = EnumCard.Count
            //アラート
            let alert = UIAlertController()
            alert.title = "初期化"
            alert.message = "カードを配り直します"
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            present(alert, animated: true, completion: nil)
        }

        //カード番号保持変数
        var card:Int
        repeat {
            //カード乱数発生(0〜EnumCard.Count - 1)
            card = Int.random(in: 0 ..< EnumCard.Count)
        //既に出ていたら繰り返す
        } while check[card]
        
        //新たに出たカード既に出ているとマークする
        check[card] = true

        //残り枚数を−1
        rest -= 1

        //ジョーカーの場合
        if card == 52 {
            lblCard.text = "JK"
        //ジョーカー以外の場合
        } else {
            //カード表示用ラベルにマークとナンバーを表示
            lblCard.text = mark[card / 13] + number[card % 13]
        }
    }
    
}

 30行目で、残り枚数を数える rest という変数を定義しています。ここには、最初 EnumCard.Count が入ります。そして、1枚引く毎に68行目で、−1しています。そして rest が0になったら、40〜54行目で初期化してメッセージを出しています。42行目ですが、for i in 0 ..< EnumCard.Count となっています。これもループ(繰り返し)の一種で、i が0からEnumCard.Count – 1 まで44行目を繰り返します。このループは、一番分かり易いと思います。

 68行目の rest -= 1 ですが、これは rest = rest – 1 と書いたのと同じになります。Swiftの以前のバージョンでは、同じ意味で rest– とも書けたのですが、現在この書き方はエラーになります。

 2巡目の最初のカードが初期化アラートが出た時にもう出てしまっているのを防ぐ書き方です。

//
//  ViewController.swift
//  Card
//
//  Created by 保 Tabei on 2024/09/25.
//

import UIKit

class ViewController: UIViewController {
    ///カード表示用ラベル
    @IBOutlet weak var lblCard: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    ///マーク保持配列
    let mark: [String] = ["♣️","♦️","❤️","♠️"]
    ///ナンバー保持配列
    let number: [String] = ["A","2","3","4","5","6","7","8","9","T","J","Q","K"]

    ///カード枚数保持定数
    enum EnumCard {
        static let Count = 53
    }

    ///残り枚数
    var rest = EnumCard.Count

    ///既に出ているかチェックする、出ていたらtrue
    ///出ていなかったらfalse、とりあえず
    ///EnumCard.Count枚分falseで埋める
    var check = [Bool](repeating: false, count: EnumCard.Count)

    ///ボタン押下時処理
    @IBAction func btnGoTouch(_ sender: Any) {
        //残り枚数0なら初期化
        if rest == 0 {
            //check配列を全部falseに
            for i in 0 ..< EnumCard.Count
            {
                check[i] = false
            }
            //残り枚数をEnumCard.Countに
            rest = EnumCard.Count
            //アラート
            let alert = UIAlertController()
            alert.title = "初期化"
            alert.message = "カードを配り直します"
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            present(alert, animated: true, completion: nil)
        }
        //残り枚数0以上
        else {
            //カード番号保持変数
            var card:Int
            repeat {
                //カード乱数発生(0〜EnumCard.Count - 1)
                card = Int.random(in: 0 ..< EnumCard.Count)
                //既に出ていたら繰り返す
            } while check[card]
            
            //新たに出たカード既に出ているとマークする
            check[card] = true
            
            //残り枚数を−1
            rest -= 1
            
            //ジョーカーの場合
            if card == 52 {
                lblCard.text = "JK"
                //ジョーカー以外の場合
            } else {
                //カード表示用ラベルにマークとナンバーを表示
                lblCard.text = mark[card / 13] + number[card % 13]
            }
        }
    }
    
}

 if 文の後に書かれていたものを else の中に移すだけで大丈夫です。

 全部使っているかチェックするバージョンです。

//
//  ViewController.swift
//  Card
//
//  Created by 保 Tabei on 2024/09/25.
//

import UIKit

class ViewController: UIViewController {
    ///カード表示用ラベル
    @IBOutlet weak var lblCard: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    ///マーク保持配列
    let mark: [String] = ["♣️","♦️","❤️","♠️"]
    ///ナンバー保持配列
    let number: [String] = ["A","2","3","4","5","6","7","8","9","T","J","Q","K"]

    ///カード枚数保持定数
    enum EnumCard {
        static let Count = 53
    }

    ///既に出ているかチェックする、出ていたらtrue
    ///出ていなかったらfalse、とりあえず
    ///EnumCard.Count枚分falseで埋める
    var check = [Bool](repeating: false, count: EnumCard.Count)

    ///ボタン押下時処理
    @IBAction func btnGoTouch(_ sender: Any) {
        //チェックをするbool変数を定義
        var chk: Bool = true
        //全カードを調べる
        for i in 0 ..< EnumCard.Count {
            //chkにcheck配列の値を入れる
            chk = check[i]
            //chkがfalseなら、まだ出ていないカードがある
            if chk == false {
                //chk が false でループを抜ける
                break
            }
        }
        //全カードがtrueなら
        if chk {
            //check配列を全部falseに
            for i in 0 ..< EnumCard.Count
            {
                check[i] = false
            }
            //アラート
            let alert = UIAlertController()
            alert.title = "初期化"
            alert.message = "カードを配り直します"
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            present(alert, animated: true, completion: nil)
        }
        //1枚でも false (出ていない)があれば
        else {
            //カード番号保持変数
            var card:Int
            repeat {
                //カード乱数発生(0〜EnumCard.Count - 1)
                card = Int.random(in: 0 ..< EnumCard.Count)
                //既に出ていたら繰り返す
            } while check[card]
            
            //新たに出たカード既に出ているとマークする
            check[card] = true
            
            //ジョーカーの場合
            if card == 52 {
                lblCard.text = "JK"
                //ジョーカー以外の場合
            } else {
                //カード表示用ラベルにマークとナンバーを表示
                lblCard.text = mark[card / 13] + number[card % 13]
            }
        }
    }
    
}

 rest 関連を削除しました。

 37行目

        var chk: Bool = true

としましたが、

        var chk = true

で大丈夫です。

 39行目から47行目で、全 check 配列を調べて、まだ出ていない false があったら、break でループを抜けています。

 カードの残り枚数を数えて表示するようにしました。

//
//  ViewController.swift
//  Card
//
//  Created by 保 Tabei on 2024/09/25.
//

import UIKit

class ViewController: UIViewController {
    ///カード表示用ラベル
    @IBOutlet weak var lblCard: UILabel!
    ///残り枚数表示用ラベル
    @IBOutlet weak var lblCount: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    ///マーク保持配列
    let mark: [String] = ["♣️","♦️","❤️","♠️"]
    ///ナンバー保持配列
    let number: [String] = ["A","2","3","4","5","6","7","8","9","T","J","Q","K"]

    ///カード枚数保持定数
    enum EnumCard {
        static let Count = 53
    }
    
    ///既に出ているかチェックする、出ていたらtrue
    ///出ていなかったらfalse、とりあえず
    ///EnumCard.Count枚分falseで埋める
    var check = [Bool](repeating: false, count: EnumCard.Count)

    ///残り枚数を保持する変数
    var count = EnumCard.Count

    ///ボタン押下時処理
    @IBAction func btnGoTouch(_ sender: Any) {
        //チェックをするbool変数を定義
        var chk = true
        //全カードを調べる
        for i in 0 ..< EnumCard.Count {
            //chkにcheck配列の値を入れる
            chk = check[i]
            //chkがfalseなら、まだ出ていないカードがある
            if chk == false {
                //chk が false でループを抜ける
                break
            }
        }
        //全カードがtrueなら
        if chk {
            //check配列を全部falseに
            for i in 0 ..< EnumCard.Count
            {
                check[i] = false
            }
            //アラート
            let alert = UIAlertController()
            alert.title = "初期化"
            alert.message = "カードを配り直します"
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            present(alert, animated: true, completion: nil)
            //残り枚数をリセット
            count = EnumCard.Count
        }
        //1枚でも false (出ていない)があれば
        else {
            //残り枚数を1減算
            count -= 1
            //残り枚数表示用ラベルに残り枚数を表示
            lblCount.text = count.description
            
            //カード番号保持変数
            var card:Int
            repeat {
                //カード乱数発生(0〜EnumCard.Count - 1)
                card = Int.random(in: 0 ..< EnumCard.Count)
                //既に出ていたら繰り返す
            } while check[card]
            
            //新たに出たカード既に出ているとマークする
            check[card] = true
            
            //ジョーカーの場合
            if card == 52 {
                lblCard.text = "JK"
                //ジョーカー以外の場合
            } else {
                //カード表示用ラベルにマークとナンバーを表示
                lblCard.text = mark[card / 13] + number[card % 13]
            }
        }
    }
    
}

 ここは、そんなに難しくは無いのではないでしょうか。

 この場合は、カードの残り枚数を数えていた方がすんなりいきます。

//
//  ViewController.swift
//  Card
//
//  Created by 保 Tabei on 2024/09/25.
//

import UIKit

class ViewController: UIViewController {
    ///カード表示用ラベル
    @IBOutlet weak var lblCard: UILabel!
    ///残り枚数表示用ラベル
    @IBOutlet weak var lblCount: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    ///マーク保持配列
    let mark: [String] = ["♣️","♦️","❤️","♠️"]
    ///ナンバー保持配列
    let number: [String] = ["A","2","3","4","5","6","7","8","9","T","J","Q","K"]

    ///カード枚数保持定数
    enum EnumCard {
        static let Count = 53
    }
    
    ///既に出ているかチェックする、出ていたらtrue
    ///出ていなかったらfalse、とりあえず
    ///EnumCard.Count枚分falseで埋める
    var check = [Bool](repeating: false, count: EnumCard.Count)

    ///残り枚数を保持する変数
    var count = EnumCard.Count

    ///ボタン押下時処理
    @IBAction func btnGoTouch(_ sender: Any) {
        //残り枚数0なら初期化
        if count == 0 {
            //check配列を全部falseに
            for i in 0 ..< EnumCard.Count
            {
                check[i] = false
            }
            //アラート
            let alert = UIAlertController()
            alert.title = "初期化"
            alert.message = "カードを配り直します"
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            present(alert, animated: true, completion: nil)
            //残り枚数をリセット
            count = EnumCard.Count
        }
        //残り枚数0以上
        else {
            //残り枚数を1減算
            count -= 1
            //残り枚数表示用ラベルに残り枚数を表示
            lblCount.text = count.description
            
            //カード番号保持変数
            var card:Int
            repeat {
                //カード乱数発生(0〜EnumCard.Count - 1)
                card = Int.random(in: 0 ..< EnumCard.Count)
                //既に出ていたら繰り返す
            } while check[card]
            
            //新たに出たカード既に出ているとマークする
            check[card] = true
            
            //ジョーカーの場合
            if card == 52 {
                lblCard.text = "JK"
                //ジョーカー以外の場合
            } else {
                //カード表示用ラベルにマークとナンバーを表示
                lblCard.text = mark[card / 13] + number[card % 13]
            }
        }
    }
    
}

 ここも、そんなに難しくないと思います。回り回って、最初に戻った様な感じです。

 とりあえず♣️だけ、全13枚が配られるか分かるソースコードにしてみます。

//
//  ViewController.swift
//  Card
//
//  Created by 保 Tabei on 2024/09/25.
//

import UIKit

class ViewController: UIViewController {
    ///カード表示用ラベル
    @IBOutlet weak var lblCard: UILabel!
    ///残り枚数表示用ラベル
    @IBOutlet weak var lblCount: UILabel!

    ///♣️の分、ラベルを定義
    @IBOutlet weak var lblKA: UILabel!
    @IBOutlet weak var lblK2: UILabel!
    @IBOutlet weak var lblK3: UILabel!
    @IBOutlet weak var lblK4: UILabel!
    @IBOutlet weak var lblK5: UILabel!
    @IBOutlet weak var lblK6: UILabel!
    @IBOutlet weak var lblK7: UILabel!
    @IBOutlet weak var lblK8: UILabel!
    @IBOutlet weak var lblK9: UILabel!
    @IBOutlet weak var lblKT: UILabel!
    @IBOutlet weak var lblKJ: UILabel!
    @IBOutlet weak var lblKQ: UILabel!
    @IBOutlet weak var lblKK: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    ///マーク保持配列
    let mark: [String] = ["♣️","♦️","❤️","♠️"]
    ///ナンバー保持配列
    let number: [String] = ["A","2","3","4","5","6","7","8","9","T","J","Q","K"]

    ///カード枚数保持定数、今回は♣️限定
    enum EnumCard {
        static let Count = 13
    }
    
    ///既に出ているかチェックする、出ていたらtrue
    ///出ていなかったらfalse、とりあえず
    ///EnumCard.Count枚分falseで埋める
    var check = [Bool](repeating: false, count: EnumCard.Count)

    ///残り枚数を保持する変数
    var count = EnumCard.Count

    ///ボタン押下時処理
    @IBAction func btnGoTouch(_ sender: Any) {
        //残り枚数0なら初期化
        if count == 0 {
            //check配列を全部falseに
            for i in 0 ..< EnumCard.Count
            {
                check[i] = false
            }
            
            //♣️ラベルを初期化
            lblKA.text = ""
            lblK2.text = ""
            lblK3.text = ""
            lblK4.text = ""
            lblK5.text = ""
            lblK6.text = ""
            lblK7.text = ""
            lblK8.text = ""
            lblK9.text = ""
            lblKT.text = ""
            lblKJ.text = ""
            lblKQ.text = ""
            lblKK.text = ""

            //アラート
            let alert = UIAlertController()
            alert.title = "初期化"
            alert.message = "カードを配り直します"
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            present(alert, animated: true, completion: nil)
            //残り枚数をリセット
            count = EnumCard.Count
        }
        //残り枚数0以上
        else {
            //残り枚数を1減算
            count -= 1
            //残り枚数表示用ラベルに残り枚数を表示
            lblCount.text = count.description
            
            //カード番号保持変数
            var card:Int
            repeat {
                //カード乱数発生(0〜EnumCard.Count - 1)
                card = Int.random(in: 0 ..< EnumCard.Count)
                //既に出ていたら繰り返す
            } while check[card]
            
            //新たに出たカード既に出ているとマークする
            check[card] = true
            
            //ジョーカーの場合
            if card == 52 {
                lblCard.text = "JK"
                //ジョーカー以外の場合
            } else {
                //カード表示用ラベルにマークとナンバーを表示
                lblCard.text = mark[card / 13] + number[card % 13]
            }

            //カードによって定められた位置に表示
            switch card {
            case 0: lblKA.text = lblCard.text
            case 1: lblK2.text = lblCard.text
            case 2: lblK3.text = lblCard.text
            case 3: lblK4.text = lblCard.text
            case 4: lblK5.text = lblCard.text
            case 5: lblK6.text = lblCard.text
            case 6: lblK7.text = lblCard.text
            case 7: lblK8.text = lblCard.text
            case 8: lblK9.text = lblCard.text
            case 9: lblKT.text = lblCard.text
            case 10: lblKJ.text = lblCard.text
            case 11: lblKQ.text = lblCard.text
            default: lblKK.text = lblCard.text
            }
        }
    }
    
}

 今回は、ラベルを並べて、名前を付けるのが大変でしたね。♣️限定にするのに、43行目を53から13にするだけで済むのは非常に楽ですね。今回は面倒くさいだけで、内容的には簡単だったと思います。

目次 通常版

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA