Как выбрать свойство структуры динамически для передачи в качестве параметра в функции в Swift 4? - PullRequest
2 голосов
/ 22 апреля 2019

Я пытаюсь уменьшить количество строк в написанной мной функции.Для этого мне нужно выбрать свойство структуры на основе некоторого условия и передать это свойство в качестве параметра, чтобы сравнить это свойство среди других элементов в массиве того же типа структуры.Вот мой гигантский код с повторением одного и того же для разных свойств.

Я пробовал следующий код.Хотя это работает как очарование, но я чувствую, что одна и та же работа была проделана несколько раз.

func checkContentsForMatching(forIndex: Int) {
    var cards = [SetCard]()
    for index in game.indicesOfChosenCards.indices {
        cards.append(cardTitles[testCards[game.indicesofChosenCards[index]]]!)


    }

    if (cards[0].color == cards[1].color) && (cards[1].color == cards[2].color) && (cards[0].color == cards[2].color) {
        game.playingCards[game.indicesOfChosenCards[0]].color = true
        game.playingCards[game.indicesOfChosenCards[1]].color = true
        game.playingCards[game.indicesOfChosenCards[2]].color = true

    }
    else if cards[0].color == cards[1].color {
        game.playingCards[game.indicesOfChosenCards[0]].color = true
        game.playingCards[game.indicesOfChosenCards[1]].color = true

    }
    else if cards[1].color == cards[2].color {
        game.playingCards[game.indicesOfChosenCards[1]].color = true
        game.playingCards[game.indicesOfChosenCards[2]].color = true

    }
    else if cards[0].color == cards[2].color {
        game.playingCards[game.indicesOfChosenCards[0]].color = true
        game.playingCards[game.indicesOfChosenCards[2]].color = true
    }

    if (cards[0].shape == cards[1].shape) && (cards[1].shape == cards[2].shape) && (cards[0].shape == cards[2].shape) {
        game.playingCards[game.indicesOfChosenCards[0]].shape = true
        game.playingCards[game.indicesOfChosenCards[1]].shape = true
        game.playingCards[game.indicesOfChosenCards[2]].shape = true
    }
    else if cards[0].shape == cards[1].shape {
        game.playingCards[game.indicesOfChosenCards[0]].shape = true
        game.playingCards[game.indicesOfChosenCards[1]].shape = true
    }
    else if cards[1].shape == cards[2].shape {
        game.playingCards[game.indicesOfChosenCards[1]].shape = true
        game.playingCards[game.indicesOfChosenCards[2]].shape = true
    }
    else if cards[0].shape == cards[2].shape {
        game.playingCards[game.indicesOfChosenCards[0]].shape = true
        game.playingCards[game.indicesOfChosenCards[2]].shape = true
    }

Ответы [ 3 ]

4 голосов
/ 22 апреля 2019

Что вам нужно, так это Swift KeyPath .

В моей реализации Sets (Zotz!) ​​Это то, что я делаю. Во-первых, я использую перечисления с необработанными значениями Int для четырех атрибутов карты. Это позволяет мне представлять любой атрибут как общий тип (Int). Я выражаю эти необработанные значения в виде вычисляемых свойств и продаю список всех четырех вычисляемых свойств в виде массива ключевых путей (обратите внимание, это Swift 5):

public struct Card: Codable, CustomStringConvertible {

    let itsColor : Color
    let itsNumber : Number
    let itsShape : Shape
    let itsFill : Fill

    var itsColorRaw : Int { return itsColor.rawValue }
    var itsNumberRaw : Int { return itsNumber.rawValue }
    var itsShapeRaw : Int { return itsShape.rawValue }
    var itsFillRaw : Int { return itsFill.rawValue }
    public static let attributes : [KeyPath<Card, Int>] = [
        \itsColorRaw, \itsNumberRaw, \itsShapeRaw, \itsFillRaw
    ]
    // ...
}

Хорошо, теперь легко определить, является ли данная тройка карт действительным совпадением:

private func isCorrectCards(_ cards:[Card]) -> Bool {
    func evaluateOneAttribute(_ nn:[Int]) -> Bool {
        let allSame = (nn[0] == nn[1]) && (nn[1] == nn[2])
        let allDiff = (nn[0] != nn[1]) && (nn[1] != nn[2]) && (nn[2] != nn[0])
        return allSame || allDiff
    }
    return Card.attributes.allSatisfy { att in
        evaluateOneAttribute(cards.map{$0[keyPath:att]})
    }
}
1 голос
/ 22 апреля 2019

Не уверен, что вы пытаетесь сделать, но если вы пытаетесь обобщить if -s и else -s, я бы сделал что-то вроде этого:

var allColorsMatch = cards[0].color == cards[1].color) && (cards[1].color == cards[2].color) && (cards[0].color == cards[2].color

var zeroAndOneMatch = cards[0].color == cards[1].color
var oneAndTwoMatch = cards[1].color == cards[2].color
var zeroAndTwoMatch = cards[0].color == cards[2].color

game.playingCards[game.indicesOfChosenCards[0]].color = allColorsMatch || zeroAndOneMatch || zeroAndTwoMatch
game.playingCards[game.indicesOfChosenCards[1]].color = allColorsMatch || zeroAndOneMatch || oneAndTwoMatch
game.playingCards[game.indicesOfChosenCards[2]].color = allColorsMatch || zeroAndTwoMatch || oneAndTwoMatch

Вот и все, вывам не нужны if -s или else -s для color, вы можете заменить блоки color if-else приведенным выше кодом.

Теперь вы можете спросить, каквы делаете то же самое для shape.shape как цвет также может быть true или false, насколько я могу видеть.Таким образом, вы можете захотеть обернуть вышеуказанный код в функцию с тремя параметрами и выполнить те же операции.

0 голосов
/ 22 апреля 2019

Вы можете использовать функции более высокого порядка Swift для фильтрации массива карт вместо использования цикла for для запуска.

Вам, вероятно, следует создать отдельные объекты модели, чтобы избежать необходимости выполнять вложенные вызовы нижних индексов, например cardTitles[testCards[game.indicesOfChosenCards[index]]]!.

Кроме того, почему ваше свойство цвета в game.playingCards[game.indicesOfChosenCards[i]].color является логическим? Кажется немного запутанным, когда свойство с именем color возвращает true или false.

Попробуйте разбить свою функцию на несколько функций. Вы пытаетесь сделать слишком много в этом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...