SwiftUI开发Set游戏:如何重构有效牌组校验重复代码
Set卡牌游戏有效牌组通用校验实现方案
你不需要为形状、颜色、数量、填充样式四类特征分别写结构完全重复的校验函数,用Swift原生的KeyPath+泛型就能实现一套逻辑覆盖所有特征校验,完全不需要硬编码枚举分支、也不需要给不同特征单独写计数逻辑。
核心实现思路
Set游戏的单特征校验规则非常统一:三张牌的同一个特征要么完全相同,要么完全不同,不需要针对具体枚举case做计数。通过泛型约束保证传入的特征类型支持相等判断,再通过KeyPath指定要读取的Card属性,就能解决你遇到的「传入不同特征类型访问对应属性」的问题。
具体代码实现
首先写单特征通用校验函数:
/// 单特征有效性校验 /// - Parameters: /// - cards: 待校验的三张牌 /// - feature: Card结构体对应特征的KeyPath,支持所有遵守Equatable协议的属性类型 private func isFeatureValid<T: Equatable>(for cards: [Card], feature: KeyPath<Card, T>) -> Bool { // 有效牌组固定为3张,数量不对直接返回false guard cards.count == 3 else { return false } // 通过KeyPath读取三张牌对应特征的值 let first = cards[0][keyPath: feature] let second = cards[1][keyPath: feature] let third = cards[2][keyPath: feature] // 判断是否满足「全相同」或「全不同」规则 let allEqual = (first == second) && (second == third) let allDistinct = (first != second) && (second != third) && (first != third) return allEqual || allDistinct }
基于这个通用函数,整组牌的有效性判断只需要依次校验四个特征即可:
/// 判断选中的三张牌是否为有效Set牌组 func isSelectedCardsValid(cards: [Card]) -> Bool { guard cards.count == 3 else { return false } return isFeatureValid(for: cards, feature: \.color) && isFeatureValid(for: cards, feature: \.shape) && isFeatureValid(for: cards, feature: \.filling) && isFeatureValid(for: cards, feature: \.number) }
方案优势
- 完全消除重复代码:不需要为每个特征单独写计数、switch分支逻辑,代码量缩减80%以上
- 避免低级错误:不会出现你原有代码里「匹配紫色case时给blue计数变量+1」这类笔误
- 扩展性极强:后续如果要给Card新增其他校验特征,只要属性遵守
Equatable协议,直接传入对应KeyPath即可复用整套校验逻辑,不需要修改核心校验代码
内容的提问来源于stack exchange,提问作者Real Analysis Noob
相关产品推荐
相关产品推荐

