2017-02-07 10 views
0

В принципе, у меня есть массив, который перетасовывается. Массив является колода карт, как, например:Нет повторения результата после перетасовки массива

var rank = ["A","2","3","4","5","6","7","8","9","10","J","Q","K"] 
var suit = ["♠", "♥","♦","♣"] 
var deck = [String]() 

У меня есть цикл, чтобы создать палубу с

for t in suit { 
     for r in rank { 
      deck.append("\(r)\(t)") 
     } 
    } 

Я тогда в функции вызвать расширение, которое я создал, чтобы перетасовать колоду. (Это возвращает меня 52 карт ассорти случайным образом)

 deck.shuffle() 

Единственное в то время как результаты являются случайными, я не хочу карты повторить. Например, если результат равен 2 ♠, я бы не захотел 2 ♥, 2 ♦, 2 ♣, следуя в распечатанном списке.

Любая помощь приветствуется! Благодаря!

+0

Вы считали, что просто перетасовываете эти 52 снова, пока не будет повторений? Есть «52! = 8.065 x 10^67' способы перетасовать колоду, так что ваш шанс, что количество раз, которое вы должны перетасовать, довольно мало –

+0

Да, хотя происходит то, что UILabel печатает, что такое Deck.First, и перетасовывает потом. Моя единственная проблема заключается в том, что я никогда не хочу, чтобы заказ, напечатанный после перетасовки, имел повторение. –

+0

Вы действительно не хотите, чтобы колода перепуталась? –

ответ

0

Я думаю, что лучший способ продолжения - использовать измененный переплет Knuth. Приведенный ниже код является полным примером. Просто запустите его в оболочке с swiftc -o customshuffle customshuffle.swift && ./customshuffle после сохранения содержимого в customshuffle.swift.

import Foundation 

let decksize = 52 


let rankStrings = ["A","2","3","4","5","6","7","8","9","10","J","Q","K"] 
let suitStrings = ["♠", "♥","♦","♣"] 

struct card : Hashable, Equatable, CustomStringConvertible { 
    var rank: Int //1,2...,11,12,13 
    var suit: Int // 1,2,3,4 

    var hashValue: Int { 
     return rank + suit 
    } 
    static func == (lhs: card, rhs: card) -> Bool { 
     return lhs.rank == rhs.rank && lhs.suit == rhs.suit 
    } 

    var description: String { 
     return rankStrings[self.rank - 1] + suitStrings[self.suit - 1] 
    } 
} 

// seems like Swift still lacks a portable random number generator 
func portablerand(_ max: Int)->Int { 
     #if os(Linux) 
      return Int(random() % (max + 1)) // biased but I am in a hurry 
     #else 
      return Int(arc4random_uniform(UInt32(max))) 
     #endif 
} 

// we populate a data structure where the 
// cards are partitioned by rank and then suit (this is not essential) 

var deck = [[card]]() 
for i in 1...13 { 
    var thisset = [card]() 
    for j in 1...4 { 
     thisset.append(card(rank:i,suit:j)) 
    } 
    deck.append(thisset) 
} 

// we write answer in "answer" 
var answer = [card]() 
// we pick a card at random, first card is special 
var rnd = portablerand(decksize) 
answer.append(deck[rnd/4].remove(at: rnd % 4)) 

while answer.count < decksize { 
    // no matter what, we do not want to repeat this rank 
    let lastrank = answer.last!.rank 
    var myindices = [Int](deck.indices) 
    myindices.remove(at: lastrank - 1) 
    var totalchoice = 0 
    var maxbag = -1 
    for i in myindices { 
     totalchoice = totalchoice + deck[i].count 
     if maxbag == -1 || deck[i].count > deck[maxbag].count { 
     maxbag = i 
     } 
    } 
    if 2 * deck[maxbag].count >= totalchoice { 
    // we have to pick from maxbag 
    rnd = portablerand(deck[maxbag].count) 
    answer.append(deck[maxbag].remove(at: rnd)) 
    } else { 
    // any bag will do 
    rnd = portablerand(totalchoice) 
    for i in myindices { 
     if rnd >= deck[i].count { 
      rnd = rnd - deck[i].count 
     } else { 
      answer.append(deck[i].remove(at: rnd)) 
      break 
     } 
    } 
    } 
} 


for card in answer { 
    print(card) 
} 

Это можно вычислить быстро, и это достаточно справедливо, но не беспристрастно печально. Я подозреваю, что может быть сложно создать «честную перетасовку» с вашим ограничением, которое выполняется быстро.