Вы хотите убедиться, что вы охватили все комбинации атрибутов и убедитесь, что каждая карта имеет один из четырех типов атрибутов. Я бы предложил использовать вложенные циклы:
for shape in cardShape.allValues {
for color in cardColor.allValues {
for number in cardNumber.allValues {
for shading in cardShading.allValues {
var card = Card()
card.addProperty(shape)
card.addProperty(color)
card.addProperty(number)
card.addProperty(shading)
cards.append(card)
}
}
}
}
Я считаю, что ваши Card
struct
слишком сложны. Если вы измените свое представление, вам будет проще создавать карточки.
Пусть ваша карта представляет различные атрибуты как собственное свойство:
struct Card {
let shape: CardShape
let color: CardColor
let number: CardNumber
let shading: CardShading
}
Затем используйте вложенные циклы для создания своих карт:
for shape in CardShape.allValues {
for color in CardColor.allValues {
for number in CardNumber.allValues {
for shading in CardShading.allValues {
cards.append(Card(shape: shape, color: color, number: number, shading: shading))
}
}
}
}
Примечания:
- Ваши перечисления должны начинаться с заглавных букв, а значения перечисления должны начинаться со строчных букв.
- Использование отдельных свойств для каждого атрибута значительно облегчит проверку соответствия атрибутов между карточками.
- По умолчанию вы получаете инициализатор, который инициализирует все свойства. Инициализируя их вложенными циклами, вы сможете создавать все возможные карты.
- Измените свойства
allValues
, чтобы они возвращали массивы определенного типа атрибута (например, [CardShape]
).
Альтернативный ответ:
Вместо использования вложенных массивов, вы можете использовать MartinR's combinations
функцию для создания списка комбинаций свойств. Добавив init
к Card
, который занимает [Property]
, вы можете создать карты в две строки кода:
struct Card {
var shape = CardShape.none
var color = CardColor.none
var number = CardNumber.none
var shading = CardShading.none
init(properties: [Property]) {
for property in properties {
switch property {
case let shape as CardShape:
self.shape = shape
case let color as CardColor:
self.color = color
case let number as CardNumber:
self.number = number
case let shading as CardShading:
self.shading = shading
default:
break
}
}
}
}
// https://stackoverflow.com/a/45136672/1630618
func combinations<T>(options: [[T]]) -> AnySequence<[T]> {
guard let lastOption = options.last else {
return AnySequence(CollectionOfOne([]))
}
let headCombinations = combinations(options: Array(options.dropLast()))
return AnySequence(headCombinations.lazy.flatMap { head in
lastOption.lazy.map { head + [$0] }
})
}
struct SetGame {
let cards: [Card]
init(){
let properties: [Property.Type] = [CardShape.self, CardColor.self, CardNumber.self, CardShading.self]
cards = combinations(options: properties.map { $0.allValues }).map(Card.init)
}
}
Как это работает:
properties.map { $0.allValues }
вызывает allValues
для каждого элемента массива properties
, создавая [[Property]]
с [[.square, .triangle, .circle], [.red, .purple, .green], [.one, .two, .three], [.solid, .striped, .outlined]]
- Это передается в
combinations
, который создает последовательность со всеми 81 комбинациями этих свойств: [[.square, .red, .one, .solid], ..., [.circle, .green, .three, .outlined]]
.
map
выполняется в этой последовательности для вызова Card.init
с каждой комбинацией, что приводит к [Card]
с 81 картой.