2017-05-09 36 views
0

我正在用一个数组收集到的卡片编写纸牌游戏。Swift - 对已过滤的数组结构进行重新排序并不会改变原始数组

卡的数据结构相同,但数据不同。

注:我的洗牌确实有效。

我想过滤这个数组,只洗牌我已经过滤的牌。

但是,虽然我可以洗牌,但我注意到,我原来的扑克牌阵列根本没有改变。

我相信这个问题是由于我的卡模型是一个结构而不是类。

更多背景信息。

虽然每张卡的数据不同,但结构完全相同;这两种类型都有一个名称和一个数字值。

这是模拟如此;

enum FSCardType: Int { 
    case property 
    case anotherType 
    case yetAnotherType 
} 

// Card Model 
struct FSCard { 
    let type: FSCardType 
    let name: String 
    let value: Int 

    var description: String { 
     return ("Name: \(self.name) Value: \(self.value), Type: \(self.type)") 
    } 
} 

我在这样的静态函数来创建我的卡片:

class FSCardAPI: NSObject { 

    public static func createCards() -> [FSCard] { 
     var cards:[FSCard] = [FSCard]() 
     let properties:[FSCard] = FSCardAPI.createProperties() 

     cards.append(contentsOf: properties) 

     return cards 
    } 

    public static func shuffleCards(cards:[FSCard]) -> [FSCard] { 
     let shuffled:[FSCard] = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: cards) as! [FSCard] 
     return shuffled 
    } 

    fileprivate static func createProperties() -> [FSCard] { 
     var properties:[FSCard] = [FSCard]() 
     for idx in 1...30 { 
      let property:FSCard = FSCard(type: .property, name: "Property #\(idx)", value: idx, owner: nil) 
      properties.append(property) 
     } 
     return properties 
    } 
} 

好了,现在我只这个卡阵列内的洗牌我的产权证。

XCTest文件

所以首先过滤那些类型的所有卡:property

func testShuffleProperties() { 
     var propertyCards = gameModel.cards.filter { (fs:FSCard) -> Bool in 
      return (fs.type == .property) 
     } 

     propertyCards = FSCardAPI.shuffleCards(cards: propertyCards) 

     print(propertyCards) 
     print(" ---- ") 
     print(gameModel.cards)  
} 

这就要求:

// Inside my FSCardAPI 
public static func shuffleCards(cards:[FSCard]) -> [FSCard] { 
    let shuffled:[FSCard] = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: cards) as! [FSCard] 
    return shuffled 
} 

问题:

当我跑我的XCTest ,我注意到虽然propertyCards被洗牌,但我的gameModel.cards不是shuf逃跑。

Test Case 'testShuffleProperties' started. 

// contents of `propertyCards` 
[FSCard(type: FSCardType.property, name: "Property #4", value: 4, owner: nil), 
FSCard(type: FSCardType.property, name: "Property #16", value: 16, owner: nil), 
// .. etc 

// contents of `gameModel.cards` 
[FSCard(type: FSCardType.property, name: "Property #1", value: 1, owner: nil), 
FSCard(type: FSCardType.property, name: "Property #2", value: 2, owner: nil), 
// .. etc 

摘要

  • 我有卡的阵列(即:30卡)
  • 卡由类型分开(即:属性)
  • 我要筛选的属性卡和洗牌只有这些卡
  • 我想原始数组反映这些变化

在我的测试中,数组被洗牌;但原始数组保持不变。

我可以想到的一种方式是我做所有的洗牌,然后通过卡片类型对数组进行排序,然后更新gameModel.cards,但这似乎有点超过顶部。

我可以考虑解决这个问题的另一个显而易见的方法是将我的struct更改为class或;也许我需要在结构之间的另一层?

所以我的查询是:

如何过滤结构的数组,只有那些洗牌的结果和改变原始阵列的状态?

非常感谢


编辑:

属性阵列是洗牌的唯一项目。

如果我添加另一个数组到列表中,它不应该洗牌整个内容。

IE;如果我这样做:

public static func createCards() -> [FSCard] { 
     var cards:[FSCard] = [FSCard]() 
     let properties:[FSCard] = FSCardAPI.createProperties() 
     let cheqs:[FSCard] = FSCardAPI.createCheques() 

     cards.append(contentsOf: properties) 
     cards.append(contentsOf: cheqs) 

     return cards 
    } 

我应该只在自己内部洗牌而不会影响cheqs。

我想我可以更容易,只有2个数组,但同时我认为没有理由这样做,因为数据结构是相同的。

+0

请显示'FSCardAPI.createCards代码()'。在FSGameModel你在哪里调用shuffle? – Scriptable

+0

我已经添加了createCards()位 – zardon

+0

我试图使用类而不是我的卡模型的结构,但结果是相同的;我相信它是因为我永远不会更改'gameModel.cards'的内容 - 理想情况下我想过滤这些卡片,将它们洗牌并更新此卡片数组。 – zardon

回答

1

您没有分配到gameModel.cards,也没有实际更改数组。所以我不希望gameModel.cards被洗牌。

您应该只是洗牌后的阵列分配回gameModel.cards像这样:

func testShuffleProperties() { 
    var propertyCards = gameModel.cards.filter { (fs:FSCard) -> Bool in 
     return (fs.type == .property) 
    } 

    propertyCards = FSCardAPI.shuffleCards(cards: propertyCards) 
    gameModel.cards = propertyCards 

    print(propertyCards) 
    print(" ---- ") 
    print(gameModel.cards)  
} 

或者,如果你想变异阵列直接,你应该看看通过引用传递卡,或在斯威夫特。 。使用inout参数。 inout参数通过引用将值传递给函数,或者传递值的内存地址,以便可以直接修改它。勾选下方的洗牌功能(它是如何定义和使用)

(I替换为迅速扩展的易用性在操场随机播放功能)

extension MutableCollection where Indices.Iterator.Element == Index { 
    /// Shuffles the contents of this collection. 
    mutating func shuffle() { 
     let c = count 
     guard c > 1 else { return } 

     for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) { 
      let d: IndexDistance = numericCast(arc4random_uniform(numericCast(unshuffledCount))) 
      guard d != 0 else { continue } 
      let i = index(firstUnshuffled, offsetBy: d) 
      swap(&self[firstUnshuffled], &self[i]) 
     } 
    } 
} 

extension Sequence { 
    /// Returns an array with the contents of this sequence, shuffled. 
    func shuffled() -> [Iterator.Element] { 
     var result = Array(self) 
     result.shuffle() 
     return result 
    } 
} 

enum FSCardType: Int { 
    case property 
    case anotherType 
    case yetAnotherType 
} 

// Card Model 
struct FSCard { 
    let type: FSCardType 
    let name: String 
    let value: Int 

    var description: String { 
     return ("Name: \(self.name) Value: \(self.value), Type: \(self.type)") 
    } 
} 

class FSCardAPI: NSObject { 

    public static func createCards() -> [FSCard] { 
     var cards:[FSCard] = [FSCard]() 
     let properties:[FSCard] = FSCardAPI.createProperties() 

     cards.append(contentsOf: properties) 

     return cards 
    } 

    public static func shuffleCards(cards:inout [FSCard]) { 
     cards = cards.shuffled() 
    } 

    fileprivate static func createProperties() -> [FSCard] { 
     var properties:[FSCard] = [FSCard]() 
     for idx in 1...30 { 
      let property:FSCard = FSCard(type: .property, name: "Property #\(idx)", value: idx) 
      properties.append(property) 
     } 
     return properties 
    } 
} 

var cards = FSCardAPI.createCards() 

FSCardAPI.shuffleCards(cards: &cards) 

输出:

Output

在In-Out参数部分阅读inout参数here

从文档中执行:

默认情况下,函数参数是常量。试图从该函数体内更改函数参数的值会导致编译时错误。这意味着你不能错误地改变参数的值。如果您想要一个函数来修改参数的值,并且希望这些更改在函数调用结束后保持不变,请将该参数定义为输入输出参数。

通过将inout关键字放在参数的类型之前,可以编写一个in-out参数。输入输出参数具有传递给函数的值,由函数修改并从函数返回以替换原始值。有关输入输出参数和相关编译器优化的详细讨论,请参阅输入输出参数。

您只能传递一个变量作为输入输出参数的参数。您不能传递常量或文字值作为参数,因为常量和文字不能被修改。当您将一个&符号(&)作为参数传入一个输入输出参数时,它将直接放在变量的名称前面,以表明它可以被该函数修改。

编辑:试试这个更新的shuffle函数,传入整个数组,看看你是否需要。

public static func shuffleCards(cards:inout [FSCard]) { 
    let propertyCards = cards.filter({ $0.type == .property }) 
    let indexes = propertyCards.map { Int(cards.index(of: $0)!) } 
    let shuffledCards = propertyCards.shuffled() 

    for (idx, val) in indexes.enumerated() { 
     cards[val] = shuffledCards[idx] 
    } 
} 
+0

这是有道理的,我感谢帮助 – zardon

+0

这是好的,但我注意到,如果我试图追加另一个数组到卡的尾部,它会洗牌数组的整个内容;它应该只洗牌在他们各自的位置,并保留任何其他卡,因为它们。 – zardon

+0

啊......这不会像调用随机播放一样简单。你需要知道可用的索引。让我看看我能否解决问题 – Scriptable

1

问题是,在你洗牌后,你没有对他们做任何事情。您应该将原始卡列表中的财产卡替换为洗牌财产卡清单中的财产卡。

var propertyCardsShuffledOriginalArray = originalArray.map { 

    var card = $0 

    if $0.type == .property { 
     card = shuffledPropertyCards.first as! FSCard 
     shuffledPropertyCards.removeFirst() 
    } 

    return card 
} 

​​是你所需要的

+0

我试着把这个放到我的操场文件中,但它遗憾地抱怨没有解决的标识符'propertyCardsShuffledOriginalArray。我不知道为什么我需要删除卡片。遍历数组创建所有项目的临时数组? – zardon

+0

'propertyCardsShuffledOriginalArray'只是一个变量名。你应该把它设置为你的'gameModel.cards' – dilaver

+0

好吧,非常感谢 – zardon

相关问题