CasinoGames/Baccarat/Models/Shoe.swift

72 lines
1.9 KiB
Swift

//
// Shoe.swift
// Baccarat
//
// A shoe containing multiple decks of cards, used in baccarat.
//
import Foundation
import CasinoKit
/// Represents a shoe containing multiple decks of cards.
/// Standard baccarat uses 6-8 decks shuffled together.
struct Shoe {
private var cards: [Card] = []
/// The number of decks in this shoe.
let deckCount: Int
/// Number of cards remaining in the shoe.
var cardsRemaining: Int {
cards.count
}
/// Whether the shoe needs to be reshuffled (less than 20% remaining).
var needsReshuffle: Bool {
let totalCards = deckCount * 52
return cards.count < totalCards / 5
}
/// Creates a new shoe with the specified number of decks.
/// - Parameter deckCount: Number of decks to include (default: 8).
init(deckCount: Int = 8) {
self.deckCount = deckCount
shuffle()
}
/// Shuffles all decks together to create a fresh shoe.
mutating func shuffle() {
cards = []
for _ in 0..<deckCount {
for suit in Suit.allCases {
for rank in Rank.allCases {
cards.append(Card(suit: suit, rank: rank))
}
}
}
// Fisher-Yates shuffle for true randomness
for i in stride(from: cards.count - 1, through: 1, by: -1) {
let j = Int.random(in: 0...i)
cards.swapAt(i, j)
}
}
/// Deals a single card from the top of the shoe.
/// - Returns: The dealt card, or nil if shoe is empty.
mutating func deal() -> Card? {
guard !cards.isEmpty else { return nil }
return cards.removeFirst()
}
/// Burns (discards) a specified number of cards from the shoe.
/// - Parameter count: Number of cards to burn.
mutating func burn(_ count: Int) {
for _ in 0..<min(count, cards.count) {
_ = cards.removeFirst()
}
}
}