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

相關問題