IOS随机卡片游戏 - 火环

时间:2016-06-22 23:04:44

标签: ios swift

所以我正在制作纸牌游戏,Ring of Fire。我存储了这样的图像:

var picture:[UIImage] = [
        UIImage(named: "Card2")!,
        UIImage(named: "Card3")!,
        UIImage(named: "Card4")!,
        UIImage(named: "Card5")!,
        UIImage(named: "Card6")!,
        UIImage(named: "Card7")!,
        UIImage(named: "Card8")!,
        UIImage(named: "Card9")!,
        UIImage(named: "Card10")!,
        UIImage(named: "CardJack")!,
        UIImage(named: "CardQueen")!,
        UIImage(named: "CardKing")!,
        UIImage(named: "CardAce")!,
        ]

每张卡片都有当前卡片下方显示的文字:

var name:String = ""

    var files = ["Velg en som må drikke", // 2
                 "Drikk selv", // 3
                 "Alle jenter må drikke", // 4
                 "Tommelen", // 5
                 "Alle gutter må drikke", // 6
                 "Pek på himmelen", // 7
                 "Drikkepartner", // 8
                 "Rim", // 9
                 "Kategori", // 10
                 "Lag en regel", // Jack
                 "Spørsmålsrunde", // Queen
                 "Hell drikke i koppen", // King
                 "Fossefall"] // Ace

这就是我选择随机卡的方式:

func imageTapped(img: AnyObject){
        if(cardsleftLabel.text != "0") {

            let randomNumber = Int(arc4random_uniform(UInt32(files.count)))
            let image = picture[randomNumber]

            cardImage.image = image
            name = files[randomNumber]
        }
        else{
            print("No more cards")
        }
    }

问题是该卡可能会多次出现,这是错误的。每张卡有4张,所以如何在游戏中控制它?那么CardJack不会出现6次?

4 个答案:

答案 0 :(得分:5)

一种方法是生成代表您的卡片的索引数组。随机播放该数组,然后在绘制卡片时从该数组中删除索引。

// generate random list of indices from 0...12 four each
var cardIndices = (0...51).map {($0 % 13, arc4random())}.sort{$0.1 < $1.1}.map{$0.0}

// To get a card, remove last card from deck    
let last = cardIndices.removeLast()

// use the index to look up the picture
let randomCard = picture[last]

// It's also easy to check how many cards you have left in your deck
let remaining = cardIndices.count

这首先创建一个元组数组,其中包含0 ... 12的数字和一些随机整数。然后该元组按元组中的随机整数元素排序,然后map用于分隔索引数组,为您留下一个Int的随机数组,其值为0 ... 12(每个的四个值)。

这是课堂形式。

import UIKit

struct Card {
    let image: UIImage
    let text:  String
}

class Deck {
    private let cards:[Card] = [
        Card(image: UIImage(named: "Card2")!, text: "Velg en som må drikke"),
        Card(image: UIImage(named: "Card3")!, text: "Drikk selv"),
        Card(image: UIImage(named: "Card4")!, text: "Alle jenter må drikke"),
        Card(image: UIImage(named: "Card5")!, text: "Tommelen"),
        Card(image: UIImage(named: "Card6")!, text: "Alle gutter må drikke"),
        Card(image: UIImage(named: "Card7")!, text: "Pek på himmelen"),
        Card(image: UIImage(named: "Card8")!, text: "Drikkepartner"),
        Card(image: UIImage(named: "Card9")!, text: "Rim"),
        Card(image: UIImage(named: "Card10")!, text: "Kategori"),
        Card(image: UIImage(named: "CardJack")!, text: "Lag en regel"),
        Card(image: UIImage(named: "CardQueen")!, text: "Spørsmålsrunde"),
        Card(image: UIImage(named: "CardKing")!, text: "Hell drikke i koppen"),
        Card(image: UIImage(named: "CardAce")!, text: "Fossefall")
    ]

    private var cardIndices = [Int]()

    var cardsInDeck: Int { return cardIndices.count }

    func shuffleCards() {
        cardIndices = (0...51).map{($0 % 13, arc4random())}.sort{$0.1 < $1.1}.map{$0.0}
    }

    func drawCard() -> Card {
        if cardIndices.count == 0 {
            shuffleCards()
        }

        let last = cardIndices.removeLast()

        return cards[last]
    }
}

注意:

  • cardscardIndicesprivate隐藏Deck用户的详细信息。
  • 感谢@ Paulw11的建议,此解决方案现在使用struct来表示卡片。这样可以将数据保存在一起,并提供可以从drawCard返回的漂亮值。
  • Deck的用户可以使用Deck创建Deck(),他们可以调用shuffleCards()随机化套牌,查看cardsInDeck属性以查找有多少洗牌可用,他们可以拨打drawCard()从牌组中取出下一张牌。

如何使用

对于控制套牌的viewController,将属性添加到viewController:

class MyGame: UIViewController {
    var deck = Deck()

    // the rest of the code
 }

然后,当您需要一张卡片时,例如在@IBAction内的按钮,只需拨打deck.drawCard

@IBAction func turnOverNextCard(button: UIButton) {
    let card = deck.drawCard()

    // Use the image and text to update the UI
    topCardImageView.image = card.image
    topCardLabel.text  = card.text

    // I'm not going to wait for the deck to shuffle itself
    if deck.cardsInDeck < 10 {
        deck.shuffleCards()
    }
}

分裂头发:更好的随机播放

我的随机播放程序通过将随机UInt32与每张卡相关联然后按照这些值对牌组进行排序来对牌组进行洗牌。如果为两张牌生成相同的随机数,那么牌组中的早期牌可能比后来的牌更受青睐(反之亦然,取决于排序算法)。这真的是分裂的头发,但为了提供最好的洗牌,我提供以下选择:

func shuffleCards() {
    cardIndices = (0...51).map {$0 % 13}
    for i in (1...51).reverse() {
        let rand = Int(arc4random_uniform(UInt32(i + 1)))
        (cardIndices[i], cardIndices[rand]) = (cardIndices[rand], cardIndices[i])
    }
}

此算法基于Fisher-Yates shuffle

答案 1 :(得分:1)

你需要一个班级代表卡片的Deck,就像这样。

class Deck {

    static let seeds = 4

    var images : [UIImage:Int] = [
        UIImage(named: "Card2")! : seeds,
        UIImage(named: "Card3")! : seeds,
        UIImage(named: "Card4")! : seeds,
        UIImage(named: "Card5")! : seeds,
        UIImage(named: "Card6")! : seeds,
        UIImage(named: "Card7")! : seeds,
        UIImage(named: "Card8")! : seeds,
        UIImage(named: "Card9")! : seeds,
        UIImage(named: "Card10")! : seeds,
        UIImage(named: "CardJack")! : seeds,
        UIImage(named: "CardQueen")! : seeds,
        UIImage(named: "CardKing")! : seeds,
        UIImage(named: "CardAce")! : seeds
    ]

    func extractRandomCard() -> UIImage? {
        let flatten = images.reduce([UIImage]()) { [UIImage](count: $0.1.1, repeatedValue: $0.1.0) }
        guard !flatten.isEmpty else { return nil }
        let random = Int(arc4random_uniform(UInt32(flatten.count)))
        let selectedCard = flatten[random]
        images[selectedCard] = images[selectedCard]! - 1
        return selectedCard
    }
}

现在你可以从牌组中提取牌

let deck = Deck()
let image = deck.extractRandomCard()

每次提取卡片时,Deck会对其进行跟踪,并且不会让您提取相同卡片的4倍以上。

  

我没有测试它......但它应该可以工作

答案 2 :(得分:0)

随机方法的另一种方法是使用Apple的一些很好的GamePlayKit,这些东西是为这些用例创建的。如果你有cards数组,你可以这么做:

let shuffled2 = GKRandomSource().arrayByShufflingObjectsInArray(cards) as! [Card]

或者你可以保持数组未被清洗,而是改变你请求的索引:

let indexes = GKShuffledDistribution.init(forDieWithSideCount: 52)
// going through all the cards randomly
for _ in cards {
    let card = cards[indexes.nextInt()]
}

答案 3 :(得分:0)

public enum Palo: Int
{
    case Corazones = 1
    case Treboles = 2
    case Picas = 3
    case Diamantes = 4
}

public struct Card
{
    public var text: String
    public var position: Int
    public var palo: Palo

    public func description() -> String
    {
        return "\(self.position) of \(self.palo) -- \(self.text)"
    }
}

public struct Deck
{
    public var cards: [Card]

    public init()
    {
        cards = [Card]()

        for number in 1...13
        {
            for palo in 1...4
            {
                let card: Card = Card(text: "", position: number, palo: Palo(rawValue: palo)!)

                cards.append(card)
            }
        }
    }

    /**
        Return cards one by one
    */
    public mutating func randomCard() -> Card?
    {
        guard !self.cards.isEmpty else
        {
            return nil
        }

        let position: Int = Int(arc4random_uniform(UInt32(self.cards.count)))   

        let card: Card = self.cards.removeAtIndex(position)

        return card
    }
}

//
// TEST
//

var deck: Deck = Deck()

for index in 1...200
{
    if let card = deck.randomCard()
    {
        print("\(index) -- \(card.description())")
    }
}