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. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
42 lines
1.4 KiB
Swift
42 lines
1.4 KiB
Swift
import Foundation
|
|
|
|
enum MoveValidator {
|
|
/// True if the two cards have alternating colors (one red, one black).
|
|
static func isAlternatingColor(_ card: Card, with other: Card) -> Bool {
|
|
card.color != other.color
|
|
}
|
|
|
|
/// True if both cards share the same suit.
|
|
static func isSameSuit(_ card: Card, as other: Card) -> Bool {
|
|
card.suit == other.suit
|
|
}
|
|
|
|
/// True if card's rank is exactly one higher than target (for foundation building A→K).
|
|
static func isAscending(_ card: Card, onto target: Card) -> Bool {
|
|
card.rank.rawValue == target.rank.rawValue + 1
|
|
}
|
|
|
|
/// True if card's rank is exactly one lower than target (for tableau stacking K→A).
|
|
static func isDescending(_ card: Card, onto target: Card) -> Bool {
|
|
card.rank.rawValue == target.rank.rawValue - 1
|
|
}
|
|
|
|
/// True if the card is an Ace.
|
|
static func isAce(_ card: Card) -> Bool {
|
|
card.rank == .ace
|
|
}
|
|
|
|
/// True if the card is a King.
|
|
static func isKing(_ card: Card) -> Bool {
|
|
card.rank == .king
|
|
}
|
|
|
|
/// True if the card can be placed on a foundation pile (same suit, ascending).
|
|
static func canPlaceOnFoundation(_ card: Card, topCard: Card?) -> Bool {
|
|
guard let topCard else {
|
|
return isAce(card)
|
|
}
|
|
return isSameSuit(card, as: topCard) && isAscending(card, onto: topCard)
|
|
}
|
|
}
|