问题:
我正在开发游戏Set,因此我必须在棋盘上选择3张卡片。 这些卡中的每一个都有四个不同的属性:
现在,我想将3张选定的牌相互比较,并计算它们是否匹配。我不能只是想办法解决这个问题,因为我也想以一种不错的方式编写它,而不是使用数十个for循环。
因此,如果符合条件,我们将有一个匹配项
分配
因此,现在我应该发明一个解决方案,使“根据老师”非常简单,并且我为此应用程序设计的模型不应超过100行代码。现在,我有近100行代码,还需要做更多的事情。因此,我应该以非常干燥的方式实现这一点。
您将如何解决此问题
我需要一些指导以指导我朝正确的方向发展。 在Swift中缺少一些用于数组的内置方法吗?还是我需要实现某种协议
答案 0 :(得分:3)
(备注:以下解决方案是针对以下情况的特殊情况而量身定制的: Set游戏,其中三个值均为0、1或2。这无济于事 检查三个任意值是否相等或全部不同。)
一些数学帮助。如果您有三个整数x,y,z,其范围为 0到2,则x + y + z是(且仅)在3的倍数时
可以用
检查if (x + y + z) % 3 == 0 {
// x, y, z are all equal or all different.
}
因此,如果将Card
类型定义为
struct Card {
let number: Int // 0, 1, 2
let symbol: Int // 0, 1, 2
let shade: Int // 0, 1, 2
let color: Int // 0, 1, 2
}
然后使用以下方法非常有效地完成对有效集合的检查:
func isValidMatch(c1: Card, c2: Card, c3: Card) -> Bool {
return (c1.number + c2.number + c3.number) % 3 == 0
&& (c1.symbol + c2.symbol + c3.symbol) % 3 == 0
&& (c1.shade + c2.shade + c3.shade) % 3 == 0
&& (c1.color + c2.color + c3.color) % 3 == 0
}
或者,为各种属性定义原始值在0、1、2范围内的枚举:
struct Card {
enum Number: Int {
case one, two, three
}
enum Symbol: Int {
case diamond, squiggle, oval
}
enum Shade: Int {
case solid, striped, open
}
enum Color: Int {
case red, green, purple
}
let number: Number
let symbol: Symbol
let shade: Shade
let color: Color
}
func isValidMatch(c1: Card, c2: Card, c3: Card) -> Bool {
return (c1.number.rawValue + c2.number.rawValue + c3.number.rawValue) % 3 == 0
&& (c1.symbol.rawValue + c2.symbol.rawValue + c3.symbol.rawValue) % 3 == 0
&& (c1.shade.rawValue + c2.shade.rawValue + c3.shade.rawValue) % 3 == 0
&& (c1.color.rawValue + c2.color.rawValue + c3.color.rawValue) % 3 == 0
}
答案 1 :(得分:0)
您的Card
类应符合Equatable协议:
class Card : Equatable {
let color: Int
let shape: Int
let shade: Int
let number: Int
//This is a failable initializer (https://developer.apple.com/swift/blog/?id=17) since we haven't used enums like in another answer, which are safer.
init?(color: Int, shape: Int, shade: Int, number: Int) {
//make sure that all properties are between 0 and 2
guard 0...2 ~= color, 0...2 ~= shape, 0...2 ~= shade, 0...2 ~= number else {
fatalError("All properties should be integers between 0 and 2")
}
self.color = color
self.shape = shape
self.shade = shade
self.number = number
}
static func == (lhs: Card, rhs: Card) -> Bool {
return lhs.color == rhs.color && lhs.shape == rhs.shape && lhs.shade == rhs.shade && lhs.number == rhs.number
}
}
因此,当所有四个属性都相等时,您将具有相等性。如 @MartinR 所述:在Swift 4.1及更高版本中,编译器将自动合成==
运算符,并足以声明符合Equatable协议。
要符合Equatable协议,您要做的就是实现此功能:
static func == (lhs: Card, rhs: Card) -> Bool
现在,如果您要检查3张卡是否相等,请使用==
运算符:
let c1 = Card(color: 2, shape: 1, shade: 0, number: 1)
let c2 = Card(color: 2, shape: 1, shade: 0, number: 1)
let c3 = Card(color: 2, shape: 1, shade: 0, number: 1)
let c4 = Card(color: 2, shape: 1, shade: 0, number: 2)
(c1 == c2) && (c2 == c3)
最后,如果您想要一次比较三张卡片的功能,可以将此代码添加到Card
类中:
class func compareThreeCards(firstCard: Card, secondCard: Card, thirdCard: Card) -> Bool {
return (firstCard == secondCard) && (secondCard == thirdCard)
}
您可以像这样使用它:
Card.compareThreeCards(firstCard: c1!, secondCard: c2!, thirdCard: c3!)
答案 2 :(得分:0)
从Swift 4.1开始,结构和枚举可以免费使用Equatable和Hashable(不适用于Class)。
例如,如果您具有Card结构,只需将此类型设为可散列的,使用您的卡片创建一个集合,然后对其进行比较即可。
struct Card: Hashable {
var color: Int
var shape: Int
var shade: Int
var number: Int
}
let card1 = Card(color: 2, shape: 2, shade: 2, number: 0)
let card2 = Card(color: 2, shape: 2, shade: 2, number: 1)
let card3 = Card(color: 3, shape: 1, shade: 0, number: 2)
print(card1 == card2 && card2 == card3) // Prints false, all different.
let card4 = Card(color: 1, shape: 2, shade: 0, number: 0)
let card5 = Card(color: 1, shape: 2, shade: 0, number: 0)
let card6 = Card(color: 1, shape: 2, shade: 0, number: 0)
print(card4 == card5 && card5 == card6) // Prints true, all the same.
注意(感谢Leo Dabus):将其设置为无序集合。