2016-06-22 7 views
0

Also ich erstelle ein Kartenspiel, Ring of Fire. Ich habe Bilder wie diese gespeichert:IOS Random Kartenspiel - 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")!, 
     ] 

Jede Karte Text wird unter der aktuellen Karte angezeigt:

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 

Und das ist, wie ich eine zufällige Karte auswählen:

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

Das Problem ist, dass die Karte oft erscheint, und das ist falsch. Es gibt 4 von jeder Karte, wie kann ich das in meinem Spiel kontrollieren? Also die CardJack erscheinen nicht 6 mal?

+0

Sie haben werden halten Spur von dem, was gezeichnet wurde. –

+0

So kann jede Karte maximal 4 mal zurückgegeben werden, oder? –

+0

@appzYourLife Ja, richtig. Genau wie ein echtes Kartenspiel. –

Antwort

5

Eine Möglichkeit besteht darin, ein Array von Indizes zu generieren, die Ihre Karten darstellen. Mischen Sie dieses Array und entfernen Sie die Indizes aus diesem Array, während Sie eine Karte zeichnen.

// 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 

Dies funktioniert, indem zuerst ein Array von Tupeln erstellt wird, die eine Zahl von 0 bis 12 und eine zufällige ganze Zahl enthalten. Dann wird dieses Array nach dem zufälligen Integer-Element im Tupel sortiert, und dann wird map verwendet, um nur das Array von Indizes zu trennen, wobei Sie ein zufälliges Array von Int mit Werten von 0 ... 12 (jeweils vier Werte) erhalten.


Hier ist es in der Klassenform.

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

Hinweise:

  • Die cards und cardIndices haben private gemacht worden, diese Angaben von einem Benutzer von Deck zu verstecken.
  • Dank @ Paulw11s Vorschlag verwendet diese Lösung jetzt eine struct, um eine Karte darzustellen. Dies hält die Daten zusammen und bietet einen schönen Wert, der von drawCard zurückgegeben werden kann.
  • Der Benutzer eines Deck können erstellen Deck mit Deck(), können sie shuffleCards() nennen das Deck, überprüfen Sie die cardsInDeck Eigenschaft randomisieren, um herauszufinden, wie viele gemischte Karten stehen zur Verfügung, und sie können drawCard() die nächste Karte aus dem erhalten rufen Deck.

Wie

Für die Viewcontroller verwenden, die das Deck steuert, fügen Sie eine Eigenschaft auf den Viewcontroller:

class MyGame: UIViewController { 
    var deck = Deck() 

    // the rest of the code 
} 

Dann, wenn Sie eine Karte benötigen, beispielsweise innerhalb eines @IBAction für eine Schaltfläche, rufen Sie einfach 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() 
    } 
} 

Haarspalterei: A Better Shuffle

Meine Shuffle Routine das Deck schlurft durch eine zufällige UInt32 mit jeder Karte zuordnet und dann das Deck von diesen Werten zu sortieren. Wenn dieselbe Zufallszahl für zwei Karten erzeugt wird, ist es möglich, dass frühere Karten im Stapel gegenüber späteren Karten bevorzugt sind (oder umgekehrt, abhängig vom Sortieralgorithmus). Das ist wirklich Haare spalten, sondern im Interesse der beste Shuffle möglich aus, bietet mir die folgende Alternative:

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

Dieser Algorithmus auf die Fisher-Yates shuffle basiert.

+0

Das hat nicht ganz funktioniert .. Ich bekomme die gleiche Karte mehr als 4 mal. –

+0

Haben Sie die cardIndices nur einmal generiert? Sie sollten das tun und dann Karten von cardIndices ziehen, bis es leer ist. – vacawama

+0

Oh, ich habe den ganzen Code in eine Tastenaktion eingefügt, die eine neue Karte setzt. –

1

Sie benötigen eine Klasse, um die Deck von Karten darzustellen, so.

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

Jetzt können Sie Karten aus dem Deck Schreiben extrahieren

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

Jedes Mal, wenn Sie eine Karte zu extrahieren das Deck Schiene von ihm hält und es wird nicht lassen Sie mehr als 4 mal die gleiche Karte extrahieren .

Ich habe es nicht testen ... aber es sollte

+0

Muss ich eine neue Klasse erstellen? Datei wie 'Deck.swift'? –

+0

@RoduckNickes: Sie müssen nicht, aber Sie sollten –

0

Einen alternativen Ansatz zu den Random-Sachen arbeitet einige von Apples schön GamePlayKit-Sachen genau für diese Art von Anwendung erstellt verwenden -Fälle. Wenn Sie die cards Array haben Sie zum Beispiel können es einfach tun:

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

oder man könnte das Array hält ungemischte und stattdessen die Indizes mischen Sie anfordern:

let indexes = GKShuffledDistribution.init(forDieWithSideCount: 52) 
// going through all the cards randomly 
for _ in cards { 
    let card = cards[indexes.nextInt()] 
} 
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())") 
    } 
}