231 lines
6.4 KiB
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
|
|
}
|
|
}
|