XCode-Claude-Workflow/SoliCards/Views/Menu/RulesView.swift
idev2025 0f989f5c86 feat: SoliCards v1.2.0 — native SwiftUI solitaire for iOS, iPadOS, macOS
Complete native rewrite of the web-based SoliCards game as a SwiftUI
multiplatform app targeting iOS 17+, iPadOS 17+, and macOS 14+.

Three solitaire variants (Klondike, Spider, FreeCell) with full game
rules, drag & drop, smart zoom layout, 6 themes, 4 difficulty levels,
SwiftData persistence, VoiceOver accessibility, and 57 unit tests.

Key features:
- MVVM + Protocol-Oriented Strategy architecture
- DragGesture with coordinate-space hit-testing (long press + drag)
- Smart zoom: cards auto-size to fit screen based on deepest column
- Landscape: 30% bigger cards with scrollable overflow (iOS)
- macOS: 120pt card cap, 92% height buffer for window resizing
- Auto-save, game resume, statistics tracking via SwiftData
- Privacy manifest, app icon, String Catalog, zero dependencies

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 07:33:52 -04:00

73 lines
3.3 KiB
Swift

import SwiftUI
struct RulesView: View {
let variant: GameVariant
@Environment(\.dismiss) private var dismiss
var body: some View {
NavigationStack {
ScrollView {
VStack(alignment: .leading, spacing: 16) {
switch variant {
case .klondike:
klondikeRules
case .spider:
spiderRules
case .freeCell:
freeCellRules
}
}
.padding()
}
.navigationTitle("\(variant.displayName) Rules")
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
#endif
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button("Done") { dismiss() }
}
}
}
}
private var klondikeRules: some View {
VStack(alignment: .leading, spacing: 12) {
ruleSection("Objective", "Move all 52 cards to the four foundation piles, building each from Ace to King in the same suit.")
ruleSection("Tableau", "Build downward in alternating colors (red on black, black on red). Only Kings can be placed on empty columns.")
ruleSection("Foundation", "Build upward by suit from Ace to King.")
ruleSection("Stock & Waste", "Draw cards from the stock pile. The number drawn depends on difficulty (1 or 3 cards).")
ruleSection("Moving Groups", "You can move a properly sequenced group of face-up cards as a unit.")
}
}
private var spiderRules: some View {
VStack(alignment: .leading, spacing: 12) {
ruleSection("Objective", "Build eight complete King-to-Ace sequences of the same suit. Completed sequences are automatically removed to the foundation.")
ruleSection("Tableau", "Build downward regardless of suit. However, only same-suit sequences can be moved as a group.")
ruleSection("Stock", "Deal one card to each of the 10 columns. All columns must have at least one card before dealing.")
ruleSection("Completing", "When a complete K through A sequence of the same suit is formed on a tableau, it automatically moves to a foundation pile.")
}
}
private var freeCellRules: some View {
VStack(alignment: .leading, spacing: 12) {
ruleSection("Objective", "Move all 52 cards to the four foundation piles, building each from Ace to King in the same suit.")
ruleSection("Tableau", "Build downward in alternating colors. Any card can go on an empty column.")
ruleSection("Free Cells", "Four temporary storage cells. Each holds one card at a time.")
ruleSection("Power Moves", "The number of cards you can move at once depends on empty free cells and empty columns: (1 + empty cells) \u{00D7} 2^(empty columns).")
ruleSection("Foundation", "Build upward by suit from Ace to King.")
}
}
private func ruleSection(_ title: String, _ body: String) -> some View {
VStack(alignment: .leading, spacing: 4) {
Text(title)
.font(.headline)
Text(body)
.font(.body)
.foregroundStyle(.secondary)
}
}
}