Итерируемый массив перечислений - PullRequest
0 голосов
/ 06 июля 2018

Я пытаюсь инициализировать колоду карт. У меня есть атрибуты карты в моей структуре карт. Мой подход состоит в том, чтобы попытаться создать массив «перечисляемых состояний», а затем перебрать их для инициализации каждой карты. У меня проблемы с этим.

Игровой класс

import Foundation

struct Set{
    var cards = [Card]()

    init(){
        let properties : [Any] = 
            [cardShape.self, cardColor.self, cardNumber.self, cardShading.self]
        for prop in properties{
        // Not really sure how to iterate through this array... 
        // Ideally it would be something like this.
        // Iterate through array, for property in array, 
        // card.add(property)
        }
    }
}

Класс карты

import UIKit
import Foundation

struct Card{
    var attributes : properties = properties()

    mutating func addProperty(value : Property){
        if value is cardShape{
            attributes.shape = value as! cardShape
        } else if value is cardColor{
            attributes.color = value as! cardColor
        } else if value is cardNumber{
            attributes.number = value as! cardNumber
        }else if value is cardShading{
            attributes.shading = value as! cardShading
        }else{
            print("error")
        }
    }
}

protocol Property{
    static var allValues : [Property] {get}
}

struct properties{
    var shape : cardShape = cardShape.none
    var color : cardColor = cardColor.none
    var number : cardNumber = cardNumber.none
    var shading : cardShading = cardShading.none
}

enum cardShape : String,Property{
    case Square = "■"
    case Triangle = "▲"
    case Circle = "●"
    case none
    static var allValues : [Property]{ return [cardShape.Square,cardShape.Triangle,cardShape.Circle]}
}

enum cardColor:Property  {
    case Red
    case Purple
    case Green
    case none

    static var allValues : [Property] {return [cardColor.Red,cardColor.Purple,cardColor.Green]}
}

enum cardNumber : Int,Property{
    case One = 1
    case Two = 2
    case Three = 3
    case none

    static var allValues : [Property] {return [cardNumber.One,cardNumber.Two,cardNumber.Three]}
}

enum cardShading: Property {
    case Solid
    case Striped
    case Outlined
    case none

    static var allValues : [Property] {return [cardShading.Solid,cardShading.Striped,cardShading.Outlined]}
}

Итак, подведем итог: моя главная проблема - попытаться создать массив перечислений, а затем циклически переключаться между состояниями перечислений, чтобы инициализировать карту с конкретными состояниями атрибутов.

1 Ответ

0 голосов
/ 06 июля 2018

Вы хотите убедиться, что вы охватили все комбинации атрибутов и убедитесь, что каждая карта имеет один из четырех типов атрибутов. Я бы предложил использовать вложенные циклы:

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)
    }
}

Как это работает:

  1. properties.map { $0.allValues } вызывает allValues для каждого элемента массива properties, создавая [[Property]] с [[.square, .triangle, .circle], [.red, .purple, .green], [.one, .two, .three], [.solid, .striped, .outlined]]
  2. Это передается в combinations, который создает последовательность со всеми 81 комбинациями этих свойств: [[.square, .red, .one, .solid], ..., [.circle, .green, .three, .outlined]].
  3. map выполняется в этой последовательности для вызова Card.init с каждой комбинацией, что приводит к [Card] с 81 картой.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...