【问题标题】:No Repetition of Result following a Shuffle of an Array数组洗牌后不重复结果
【发布时间】:2017-06-24 03:39:50
【问题描述】:

基本上,我有一个随机排列的数组。该数组是一副这样的纸牌:

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

我有一个 for 循环来创建卡片组

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

然后我在一个函数中调用我创建的扩展来洗牌。 (这给我带来了 52 张随机分类的卡片)

        deck.shuffle()

唯一的问题是,虽然结果是随机的,但我不希望卡片重复。例如,如果结果是 2♠,我不希望 2♥、2♦、2♣ 在打印列表中。

感谢任何帮助!谢谢!

【问题讨论】:

  • 您是否考虑过再次将这 52 个随机播放,直到不再重复?有52! = 8.065 x 10^67 洗牌的方法,所以你洗牌的机会很小
  • 是的,尽管 UILabel 打印出 Deck.First 是什么,然后再洗牌。我唯一的问题是我不希望在洗牌后打印的顺序有重复。
  • 你真的不想洗牌吗?
  • 所以你永远不想要一张牌后面跟着另一张同等级的牌?
  • 是的,基本上我想要一个洗牌,但结果不是同一等级。感谢您的回复!

标签: arrays swift string for-loop append


【解决方案1】:

我认为最好的方法是使用经过修改的 Knuth shuffle。下面的代码是一个完整的例子。将内容保存在customshuffle.swift 中后,只需在带有swiftc -o customshuffle customshuffle.swift && ./customshuffle 的shell 中运行它即可。

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

这可以快速计算并且相当公平,但遗憾的是并非没有偏见。我怀疑使用快速运行的约束可能很难生成“公平洗牌”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-10
    • 2015-03-31
    • 1970-01-01
    • 1970-01-01
    • 2021-10-15
    • 2015-04-15
    • 1970-01-01
    相关资源
    最近更新 更多