简体   繁体   English

如何在多个阵列上使用Fisher-Yates Shuffle?

[英]How can i use Fisher-Yates Shuffle on multiple arrays?

I'm trying to generate a bridge deal, four players, which get 13 (randomized) cards each. 我试图产生一个过渡交易,四个玩家,每个玩家获得13张(随机)卡。

I figured i would just start with declaring some variables eg the suits, a deck containing the suits, and the players hands: 我认为我只是从声明一些变量开始,例如西服,包含西服的牌组和玩家的手牌:

var deal = function() {
    var spades   = ['A', 'K', 'Q', 'J', 'T', 9, 8, 7, 6, 5, 4, 3, 2];
    var hearts   = ['A', 'K', 'Q', 'J', 'T', 9, 8, 7, 6, 5, 4, 3, 2];
    var diamonds = ['A', 'K', 'Q', 'J', 'T', 9, 8, 7, 6, 5, 4, 3, 2];
    var clubs    = ['A', 'K', 'Q', 'J', 'T', 9, 8, 7, 6, 5, 4, 3, 2];

    var deck = [spades, hearts, diamonds, clubs];

    //Next to do: get 13 random cards dealt to each player
    var northHand = [ [], [], [], [] ];
    var eastHand  = [ [], [], [], [] ];
    var southHand = [ [], [], [], [] ];
    var westHand  = [ [], [], [], [] ];


}

Then i came across this shuffle function based on the fisher-yates algorithm: 然后我遇到了基于fisher-yates算法的随机播放功能:

function shuffle(array) {
  var m = array.length, t, i;

  // While there remain elements to shuffle…
  while (m) {

    // Pick a remaining element…
    i = Math.floor(Math.random() * m--);

    // And swap it with the current element.
    t = array[m];
    array[m] = array[i];
    array[i] = t;
  }

  return array;
}

The problem is that my programming (and/or logical) skills, are too poor for finding out how i could apply this algoritm on my scenario, dealing with multiple arrays. 问题是我的编程(和/或逻辑)技能太差,无法找出如何将这种算法应用于我的场景,处理多个数组。

Is this a good start for my problem, or is there a better approach i should look into? 这是解决我的问题的一个好的开始,还是我应该研究一种更好的方法?

I think your problem is the way you're building your deck. 我认为您的问题是构建甲板的方式。 That's fine for sequential, logical access. 对于顺序的逻辑访问来说很好。 You want suits mixed up as well as cards in a suit. 您需要将西装和西装中的卡片混在一起。 You'd be better off with a 52-element array containing either strings 2H , QD , etc or simple objects {'Suit': 'Hearts', 'Value': 'Q'} 最好使用包含字符串2HQD等的52个元素的数组或简单对象{'Suit': 'Hearts', 'Value': 'Q'}

Once you've got a single array, the shuffle implementation becomes trivial using the code you've provided 一旦有了一个数组,使用提供的代码即可轻松实现随机播放

Once you've shuffled you can either give player 1 cards 0-12, 2 13-25, etc or you can "deal" them properly so player 1 gets cards from positions 0, 4, 6, 12, etc... 洗牌后,您可以给玩家1张卡0-12、2 13-25等,也可以正确地“交易”它们,以便玩家1从位置0、4、6、12等处获得卡。

Instead of naming 4 arrays N/E/S/W, use a 2d array so you can access it easily. 不用命名为N / E / S / W的4个数组,而是使用2d数组,这样您就可以轻松访问它。

Then loop through the cards something like... 然后像这样循环浏览卡片...

for(var i=0;i<52;i++) {
    Pos = i % 4;
    Hands[Pos].push(Deck[i]);
}

Assuming your hands are defined as 假设你的手被定义为

var Hands = [ [], [], [], [] ];

You should be good to go (untested) 你应该去(没试过)

Suit and value of each card is significant, so you need to keep them together. 每张卡的花色和价值都很重要,因此您需要将它们放在一起。 A card is probably better represented as {suit: 'spades', value: 'A'} . 卡片最好用{suit: 'spades', value: 'A'}

I would build the deck along these lines: 我将按照以下路线构建甲板:

var deck = [];

var suits = ['spade', 'heart', 'club', 'diamond'];

var values = ['A', 'K', 'Q', 'J', '10', '9', '8', '7', '6', '5', '4', '3', '2'];

for (var sIdx = 0; sIdx < suits.length; sIdx++) {
    for (var vIdx = 0; vIdx < values.length; vIdx++) {
        deck.push({suit: suits[sIdx], value: values[vIdx]});
    }
}

Then use your shuffle to shuffle the deck, and slice() to split it into 4 hands of 13. 然后使用随机播放来随机播放牌组,然后slice()将其分成4手,每组13个。

The approach you outlined (with a separate array for each suit) can totally work. 您概述的方法(每套西装都有一个单独的数组)可以完全起作用。 But I feel this is one of those cases where making the data representation map cleanly to the thing being represented makes just about every operation you want to perform on the data easier. 但是我认为这是其中一种情况,其中使数据表示形式清晰地映射到要表示的事物将使您几乎想要对数据执行的每个操作都变得容易。

First you need a way to distinguish between every card. 首先,您需要一种区分每张卡的方法。 Let's say all the cards are numbered from 0 to 51 as follows: 假设所有卡的编号从0到51如下:

  1. Hearts are numbered from 0 to 12. 心的编号从0到12。
  2. Spades are numbered from 13 to 25. 黑桃的编号从13到25。
  3. Diamonds are numbered from 26 to 38. 钻石编号从26到38。
  4. Clubs are numbered from 39 to 51. 俱乐部编号从39到51。

In each suit the cards are numbered as follows: 在每套西装中,卡的编号如下:

  1. Ace to 10 are numbered from 0 to 9. A到10从0到9编号。
  2. Jack is 10. 杰克10岁。
  3. Queen is 11. 女王是11。
  4. King is 12. 国王是12。

Note that these numbers are just used to identify the cards. 请注意,这些数字仅用于识别卡。 They don't represent the values of any card. 它们不代表任何卡的值。 Hence they can be used for all card games. 因此,它们可以用于所有纸牌游戏。 Given a number you can find its suit and rank as follows: 给定一个数字,您可以找到它的适合度和等级,如下所示:

var suits = ["Hearts","Spades","Diamonds","Clubs"];

var ranks = ["Ace","2","3","4","5","6","7","8","9","10","Jack","Queen","King"];

function getSuite(card) {
    return suits[Math.floor(card / 13)];
}

function getRank(card) {
    return ranks[card % 13];
}

Now your deck is simply an array of numbers from 0 to 51. Hence you can use Fischer Yates to shuffle it: 现在,您的牌组只是一个从0到51的数字数组。因此,您可以使用Fischer Yates对其进行混洗:

function deal() {
    var deck = shuffle(range(0, 51));

    var northHand = deck.slice(0, 13);
    var eastHand  = deck.slice(13, 26);
    var southHand = deck.slice(26, 39);
    var westHand  = deck.slice(39, 52);
}

function range(from, to) {
    if (from > to) return [];
    else return [from].concat(range(from + 1, to));
}

That's all. 就这样。

You cannot use Fisher-Yates shuffle here, since you want to move values randomly between arrays. 您不能在此处使用Fisher-Yates随机播放,因为您想在数组之间随机移动值。 This should do it and still be random: 这应该做到并且仍然是随机的:

var hands = [northHand, eastHand, southHand, westHand];
var numberofcards = 4*13;
for (var i=0; i<4; i++) {
    for (var j=0; j<13; j++) {
        // draw card:
        var card = Math.floor(Math.random() * numberofcards--);
        // check which card it is:
        for (var suit=4; suit-- && card > deck[suit].length; )
            card -= deck[suit].length;
        // remove from deck and assign to player
        hands[i][suit].push(deck[suit].splice(card, 1)[0]);
    }
}

However, representing a single card as an object with suit and value will probably be easier to deal with - you then can also use the shuffle method before slicing the deck into four parts. 但是,将一张卡表示为具有适合性和价值的对象可能会更容易处理-然后,您还可以在将卡座切成四个部分之前使用shuffle方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM