【问题标题】:Array occasionally returning duplicate values数组偶尔返回重复值
【发布时间】:2017-02-17 23:40:54
【问题描述】:

我正在尝试制作一款类似于战争游戏的卡牌游戏。该游戏有两个玩家,每个玩家都有自己的牌组。
我有一个函数可以传入一个空数组,该数组是每个玩家拥有的牌组。
此数组由另一个数组(即整个牌组)中的一半项目填充。
大多数情况下,这可以正常工作,但有时,数组会有 26 个值,其他时候,一些值会重复。
我的问题是,如何阻止将重复项传递到玩家的牌组数组中?

Player = function(wonRound, currentCards, newCards) {
  this.wonRound = wonRound;
  this.currentCards = currentCards;
  this.newCards = newCards;
}

Deck = {
  suits: ["Clubs", "Diamonds", "Hearts", "Spades"],
  cards: ["Ace", "King", "Queen", "Jack", "10", "9", "8", "7", "6", "5", "4", "3", "2"],
  deck: [],
  shuffledDeck: [],
  BuildDeck: function() {
    //Builds the deck
    for (var suit = 0; suit < this.suits.length; suit++) {
      for (var card = 0; card < this.cards.length; card++) {
        this.deck.push([this.cards[card], this.suits[suit]]);
      }
    }
    return this.deck;
  },
  ShuffleDeck: function() {
    //Shuffles the deck
    for (var card = 0; card < this.deck.length; card++) {
      this.shuffledDeck.push(this.deck[Math.floor(Math.random() * this.deck.length)]);
    }
    return this.shuffledDeck;
  },
  DistributeCards: function(playerDeck) {
    //Distributes half the deck to each player
    for (var i = 0; i < this.shuffledDeck.length / 2; i++) {
      playerDeck.push(this.shuffledDeck[i]);
    }
    return playerDeck;
  }
}
Player1 = new Player(false, [], []);
Player2 = new Player(false, [], []);
Deck.BuildDeck();
Deck.ShuffleDeck();
Deck.DistributeCards(Player1.currentCards);
for (var i = 0; i < Player1.currentCards.length; i++) {
  console.log(Player1.currentCards[i][0], Player1.currentCards[i][1], Player1.currentCards.indexOf(Player1.currentCards[i]));
}

【问题讨论】:

  • 检查我的答案以将其分发给第二个玩家:)

标签: javascript arrays


【解决方案1】:

您会得到重复,因为您从同一个数组中选择而不排除已经选择的值。一种方法是删除(使用splice)选择的项目,这样它们就不会再次被选择。像这样:

ShuffleDeck: function() {                                         // while there still items in the deck
    while(this.deck.length) {
        var index = Math.floor(Math.random() * this.deck.length); // get a random index
        this.shuffledDeck.push(this.deck.splice(index, 1)[0]);    // remove the item at index (splice will return an array so we use [0] to get the item)
    }
    return this.shuffledDeck;
},

注意:之后牌组将是空的,但由于您不再使用它,这不会有问题。

编辑:

DistributeCards 更改为:

DistributeCards: function(player1, player2) {
    for (var i = 0; i < this.shuffledDeck.length / 2; i++) {
        player1.push(this.shuffledDeck[i]); // push the first half to player1's deck (0, 1, 2, ...)
        player2.push(this.shuffledDeck[this.shuffledDeck.length - i - 1]); // push the other half to player2's deck (len - 1, len - 2, len - 3, ...)
    }
    // no need for return if you won't use the return value (my advice is to remove return from all the function that you don't use their return value)
}

然后像这样使用它:

Deck.DistributeCards(Player1.currentCards, Player2.currentCards);

【讨论】:

  • 感谢您解释一切。现在的问题是当有两个玩家时该怎么办。
  • @Robert 检查编辑部分!
【解决方案2】:

问题主要出在你洗牌的方式上!在声明中:

this.shuffledDeck.push(this.deck[Math.floor(Math.random() * this.deck.length)]);

Math.floor(Math.random() * this.deck.length) 逻辑可能会两次给出相同的数字,这将复制一张卡片(并且可能不止一次),这不是您所期望的。
所以你真正需要的是创建一个逻辑来确保没有数字重复,并且有很多方法可以做到这一点,查看this SO 帖子以获取多个示例。

【讨论】:

  • 将牌放入每个玩家的牌组后洗牌会解决问题吗?
  • @Robert 可能不会,因为分布不会是随机的。
  • @Robert 我完全同意布兰登的观点。
【解决方案3】:
deck.sort(function(a, b){return 0.5 - Math.random()});

只需在牌堆上执行此操作,您甚至不需要另一个牌堆来洗牌。

https://www.w3schools.com/js/js_array_sort.asp还有更多的数组方法。

【讨论】:

  • 你为什么用0.5?
  • @bormat Math.random 将返回一个介于[0, 1[ 之间的数字,因此0.5 - ... 将根据Math.random 返回负数和正数。 sort 将根据回调返回正数还是负数来交换项目。如果返回值始终为正,则sort 将让数组保持原样或反转它。在MDN 上查看sort 的文档!
  • 这总是返回“未定义”
【解决方案4】:

您的问题在于您的 ShuffleDeck 函数。每次您从现有牌组中随机选择一张牌,但您并没有从池中移除该牌以再次选择。您要么需要跟踪已经选择的数字,要么在将元素洗牌后从数组中删除它。也许最简单的随机播放类型是Fisher-Yates shuffle

此外,您的分发将始终采用牌组的前半部分而不对其进行修改,因此在不从牌组中删除元素的情况下运行该函数只会为每个玩家提供相同的牌。

Player = function(wonRound, currentCards, newCards) {
  this.wonRound = wonRound;
  this.currentCards = currentCards;
  this.newCards = newCards;
  this.getCards = function ( cards ) {
    this.currentCards = cards;
  };
}

Deck = {
  suits: ["Clubs", "Diamonds", "Hearts", "Spades"],
  cards: ["Ace", "King", "Queen", "Jack", "10", "9", "8", "7", "6", "5", "4", "3", "2"],
  deck: [],
  shuffledDeck: [],
  BuildDeck: function() {
    //Builds the deck
    for (var suit = 0; suit < this.suits.length; suit++) {
      for (var card = 0; card < this.cards.length; card++) {
        this.deck.push([this.cards[card], this.suits[suit]]);
      }
    }
    return this.deck;
  },
  ShuffleDeck: function() {
    //Shuffles the deck
    var tempDeck = this.deck.slice(0); // Clone the deck, so the original deck still exists
    while ( tempDeck.length ) {
      var newItem = tempDeck.splice( Math.floor( Math.random() * tempDeck.length ), 1); // Pull one item from the array
      this.shuffledDeck.push( newItem[0] ); // Add it to the shuffled array
    }
    return this.shuffledDeck;
  },
  DistributeCards: function( len ) {
    //Distributes portion of the deck to each player
    // Note, if the length is greater than the length of the deck, it will return all remaining cards in the deck, even if they're less than what is requested. 
    return this.shuffledDeck.splice(0, len);
  }
}
Player1 = new Player(false, [], []);
Player2 = new Player(false, [], []);
Deck.BuildDeck();
Deck.ShuffleDeck();
Player1.getCards(Deck.DistributeCards(26)); // Get 26 cards from the shuffled deck and set them as the player's hand
for (var i = 0; i < Player1.currentCards.length; i++) {
  console.log(Player1.currentCards[i][0], Player1.currentCards[i][1], Player1.currentCards.indexOf(Player1.currentCards[i]));
}

注意添加了Player.getCards 方法,只是为了让事情更清楚一点(它使玩家的“手”等于抽出和传入的牌),以及对 Shuffle 和 Distribute 方法的更改.

我试图说明为什么我更改了我更改的内容,以尝试说明您的问题。如果您需要更多说明,请随时询问。

Array.splice documentation

【讨论】:

    【解决方案5】:

    我重写了洗牌的逻辑如下:

    ShuffleDeck: function() {
        var i = this.deck.length;
        var j = 0;
    
        while (i--) {
          j = Math.floor(Math.random() * (i + 1));
          this.shuffledDeck.push(this.deck[j]);
          this.deck.splice(j, 1);
        }
    
        return this.shuffledDeck;   }
    

    工作小提琴:https://jsfiddle.net/db6xmnrn/

    更新 小提琴从剩余的牌组中向玩家 2 传送卡片 https://jsfiddle.net/db6xmnrn/1/

    【讨论】:

      猜你喜欢
      • 2015-08-27
      • 2014-01-04
      • 2011-06-11
      • 2015-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-25
      • 2021-01-21
      相关资源
      最近更新 更多