Swiftでブラックジャックカウンティングアプリを作ってみた。

初めて作ってみたブラックジャックカウンティングアプリについて今後使えそうな箇所を技術メモとして残しておこうと思います。
こちらからダウンロードできます👇👇👇
https://apps.apple.com/jp/app/blackjackcounting/id6471584119

コード👇👇👇
https://github.com/haruki-mochida/BlackJackCounting
発表資料👇
https://docs.google.com/presentation/d/1yKoN3GZTnIQOAFu3Sf6iVEF8u6AnL7kPPCjqydroJ6s/edit#slide=id.p

# 条件演算子
```Swift:Swift
Image("card_heart_\(card < 10 ? "0" : "")\(card)")
```
- card の値に応じて、適切な画像名を生成しています。

- card < 10 ? "0" : "" は条件演算子です。
card が10未満の場合、つまり1桁の数値の場合は "0" を返します。
card が10以上の場合、つまり2桁以上の数値の場合は空文字列 "" を返します。
\(card) は、カードの数値を文字列に変換しています。

これにより、カード番号が1桁の場合には "card_heart_01" のようなファイル名が生成され、2桁以上の場合には "card_heart_10" のようなファイル名が生成されます。

# @StateObject
```Swift:Swift
Image("card_heart_\(card < 10 ? "0" : "")\(card)")
```
SwiftUIで状態を管理するための特殊なプロパティラッパーです。このプロパティラッパーを使用することで、オブジェクトの状態を保持し、その変更を自動的に監視することができます。




# 範囲演算子
```Swift:Swift
           switch probability {
            case ...0.30: return .blue // 0.30以下なら青
            case 0.30..<0.33: return .black // 0.30以上0.33未満なら黒
            case 0.33..<0.34: return .yellow // 0.33以上0.34未満なら黄色
            case 0.34...: return .red // 0.34以上なら赤
            default: return .black // それ以外なら黒
            }
```
##### ... 範囲演算子:

- ... 範囲演算子は、範囲の終点を含む範囲を表現するために使用されます。
例えば、1...5 は1から5までの範囲を表し、1, 2, 3, 4, 5という要素を含みます。
終点の値も範囲に含まれるため、上限を含むループや処理を行う際に利用されることがあります。
##### ..< 範囲演算子:

- ..< 範囲演算子は、範囲の終点を含まない範囲を表現するために使用されます。
例えば、1..<5 は1から5未満の範囲を表し、1, 2, 3, 4という要素を含みますが、5は含まれません。
終点の値を含まない範囲を指定する際に使用されます。通常、ループやインデックスの指定などに利用されます。


# @Published
```Swift:Swift
      @Published var deckCount: Int = 1 {
//省略
        }
```

- 簡単に言うと@Published はプロパティの変更を伝える手段であり、他のオブジェクトがその変更を検知して必要な処理を行うことができるようにする役割を持っています。
- 今回はデフォルトの値を1に設定しており、プロパティの変更が自動的に他のオブジェクトに通知されるようになっています。

# 辞書型
```Swift:Swift
private var cards: [Int: Int] = [:]
```
- [Int: Int] は、キーと値のペアを持つ辞書型（Dictionary）を表しています。
[:] は、空の辞書を初期値として設定しています。

###### 辞書の役割
- cards は、カードの数値とその在庫数を管理するための辞書です。
キー（Int型）はカードの数値を表し、値（Int型）はそのカードの在庫数を表します。
例えば、カード1の在庫数は cards[1] で取得できます。


# init() メソッド
```Swift:Swift
 class DeckViewModel: ObservableObject {
        @Published var deckCount: Int = 1 {
            didSet {
                reset()
            }
        }

        init() {
            reset()
        }
```

###### init() メソッド
- init() メソッドは、オブジェクトが初期化される際に**自動的に呼び出される特殊なメソッド**です。
このメソッドは、DeckViewModel クラスのインスタンスが作成されるときに実行される初期化処理を定義します。
init() メソッド内のコードは、オブジェクトのプロパティや状態を初期化するための処理を含むことが一般的です。

###### reset() メソッドの呼び出し:
- init() メソッドの中で、reset() メソッドが呼び出されています。
reset() メソッドは、デッキのリセットを行うためのメソッドです。
リセット処理は、showResetAlert プロパティを変更することによってトリガーされます。
つまり、init() メソッドはオブジェクトの初期化時に呼び出され、reset() メソッドを実行してデッキのリセットを行います。これにより、DeckViewModel インスタンスが作成された直後にデッキがリセットされます。

# reduce(_:_:) 関数
```Swift:Swift
var totalCount: Int {
            cards.values.reduce(0, +)
        }
```
- reduce(_:_:) は、配列やコレクションの要素を結合（畳み込み）して単一の値を生成するために使用される関数です。
- 一般的な構文は collection.reduce(initialResult, combine) です。ここで collection は対象の配列やコレクション、initialResult は初期値、combine は畳み込み操作を行うクロージャです。
###### 例
以下のような配列 [1, 2, 3, 4, 5] がある場合、 reduce(0, +) を使用すると次のような計算が行われます:

初期値 0 が設定されます。
0 + 1 の結果は 1 となり、新しい合計値として利用されます。
1 + 2 の結果は 3 となり、新しい合計値として利用されます。
3 + 3 の結果は 6 となり、新しい合計値として利用されます。
6 + 4 の結果は 10 となり、新しい合計値として利用されます。
10 + 5 の結果は 15 となり、最終的な合計値として返されます。
したがって、reduce(0, +) は要素の合計を計算するための便利な方法となります。

# .values プロパティ
```Swift:Swift
var totalCount: Int {
            cards.values.reduce(0, +)
        }
```

- .values プロパティは、辞書内の全ての値を取得するために使用されます。
辞書はキーと値のペアを保持するデータ構造であり、.values プロパティはその辞書内の値のコレクションを返します。
- .values プロパティは、キーの順序に関係なく辞書内の値を取得するため、値の順序は保証されません。
###### 使用例:
```Swift:Swift
let dictionary = ["apple": 5, "banana": 3, "orange": 2]
let values = dictionary.values
print(values) // 出力: [5, 3, 2]
```
- .values プロパティを使うことで、辞書内の全ての値を簡単に取得できます。これにより、辞書内の値に対して反復処理を行ったり、集計を行ったりすることが可能になります。



# 辞書のサブスクリプト
```Swift:Swift
func cardsCount(card: Int) -> Int {
            cards[card, default: 0]
        }
```

- 辞書のサブスクリプトを利用することで、辞書内の特定のキーに対応する値を取得することができます。
- cards[card, default: 0] という式は、cards 辞書内でキーが card の値に対応する値を取得します。
もし辞書内に指定されたキーの値が存在しない場合は、デフォルト値として 0 を返します。これはオプショナル型であり、辞書内に指定されたキーの値が存在しない場合に備えて安全性を高めています。