CasinoGames/Baccarat/Baccarat/Models/RoadMapModels.swift

231 lines
6.4 KiB
Swift

//
// RoadMapModels.swift
// Baccarat
//
// Models for Baccarat road map displays including Big Road and derived roads.
//
import Foundation
import SwiftUI
// MARK: - Road Types
/// The available road map display types.
enum RoadType: String, CaseIterable, Identifiable, Codable {
case bead = "bead"
case big = "big"
case bigEyeBoy = "bigEyeBoy"
case smallRoad = "smallRoad"
case cockroachPig = "cockroachPig"
var id: String { rawValue }
/// Localized display name for the road type.
var displayName: String {
switch self {
case .bead: return String(localized: "Bead Road")
case .big: return String(localized: "Big Road")
case .bigEyeBoy: return String(localized: "Big Eye Boy")
case .smallRoad: return String(localized: "Small Road")
case .cockroachPig: return String(localized: "Cockroach Pig")
}
}
/// Short description for tooltips.
var shortDescription: String {
switch self {
case .bead:
return String(localized: "Simple grid showing all results in order.")
case .big:
return String(localized: "Shows streaks. New column when winner changes.")
case .bigEyeBoy:
return String(localized: "Compares current streak to previous. Red = repeating pattern.")
case .smallRoad:
return String(localized: "Like Big Eye Boy, but looks 2 columns back.")
case .cockroachPig:
return String(localized: "Finest pattern detection. Looks 3 columns back.")
}
}
/// Icon for the road type.
var icon: String {
switch self {
case .bead: return "circle.grid.3x3"
case .big: return "chart.bar.xaxis"
case .bigEyeBoy: return "eye.fill"
case .smallRoad: return "road.lanes"
case .cockroachPig: return "ant.fill"
}
}
/// Whether this is a derived road (Big Eye Boy, Small Road, Cockroach Pig).
var isDerived: Bool {
switch self {
case .bead, .big: return false
case .bigEyeBoy, .smallRoad, .cockroachPig: return true
}
}
/// The column offset used for derived road calculations.
/// Big Eye Boy compares to 1 column back, Small Road to 2, Cockroach Pig to 3.
var columnOffset: Int {
switch self {
case .bead, .big: return 0
case .bigEyeBoy: return 1
case .smallRoad: return 2
case .cockroachPig: return 3
}
}
/// The starting column requirement for derived roads.
/// Big Eye Boy starts after column 2, Small Road after column 3, Cockroach Pig after column 4.
var startingColumn: Int {
switch self {
case .bead, .big: return 1
case .bigEyeBoy: return 2
case .smallRoad: return 3
case .cockroachPig: return 4
}
}
}
// MARK: - Big Road Entry
/// An entry in the Big Road grid.
/// Represents a single result positioned in the column-based streak layout.
struct BigRoadEntry: Identifiable, Equatable {
let id: UUID
/// The game result (Player wins or Banker wins).
/// Ties are tracked separately via `tieCount`.
let result: GameResult
/// The column position (0-indexed).
let column: Int
/// The row position (0-indexed, 0 is top).
let row: Int
/// Number of ties that occurred after this result.
let tieCount: Int
/// Whether this result was a natural (8 or 9).
let isNatural: Bool
/// Whether a pair occurred in this hand.
let hasPair: Bool
/// The original round result for additional data access.
let roundResult: RoundResult?
init(
id: UUID = UUID(),
result: GameResult,
column: Int,
row: Int,
tieCount: Int = 0,
isNatural: Bool = false,
hasPair: Bool = false,
roundResult: RoundResult? = nil
) {
self.id = id
self.result = result
self.column = column
self.row = row
self.tieCount = tieCount
self.isNatural = isNatural
self.hasPair = hasPair
self.roundResult = roundResult
}
// MARK: - Equatable (custom implementation excluding roundResult)
static func == (lhs: BigRoadEntry, rhs: BigRoadEntry) -> Bool {
lhs.id == rhs.id &&
lhs.result == rhs.result &&
lhs.column == rhs.column &&
lhs.row == rhs.row &&
lhs.tieCount == rhs.tieCount &&
lhs.isNatural == rhs.isNatural &&
lhs.hasPair == rhs.hasPair
}
/// The color for this entry based on the result.
var color: Color {
result.color
}
/// Label for display (P or B).
var label: String {
switch result {
case .playerWins: return "P"
case .bankerWins: return "B"
case .tie: return "T"
}
}
}
// MARK: - Derived Road Entry
/// An entry in a derived road (Big Eye Boy, Small Road, or Cockroach Pig).
/// Uses hollow circles: red indicates pattern repeating, blue indicates pattern breaking.
struct DerivedRoadEntry: Identifiable, Equatable {
let id: UUID
/// Whether this entry is red (pattern repeating) or blue (pattern breaking).
let isRed: Bool
/// The column position (0-indexed).
let column: Int
/// The row position (0-indexed, 0 is top).
let row: Int
init(
id: UUID = UUID(),
isRed: Bool,
column: Int,
row: Int
) {
self.id = id
self.isRed = isRed
self.column = column
self.row = row
}
/// The color for this entry.
var color: Color {
isRed ? .red : .blue
}
}
// MARK: - Big Road Column
/// A column in the Big Road, containing multiple entries.
/// Used internally by the road map builder for layout calculations.
struct BigRoadColumn: Identifiable, Equatable {
let id: UUID
/// The column index (0-indexed).
let index: Int
/// The entries in this column (top to bottom).
var entries: [BigRoadEntry]
/// The result type for this column (all entries have the same result).
var result: GameResult? {
entries.first?.result
}
/// The depth (number of entries) in this column.
var depth: Int {
entries.count
}
init(id: UUID = UUID(), index: Int, entries: [BigRoadEntry] = []) {
self.id = id
self.index = index
self.entries = entries
}
}