1

我正在尝试在 x 次的过程中设置成对的唯一数字

例如,如果 x = 8 我想生成类似:

(5,3) (1,4) (7,2) (8,6)

目前我有:

var playerArray = [0,1,2,3,4,5,6,7];
var loopLength = playerArray.length;
var player1 = 0;
var player2 = 0;
for(var i = 1; i <= loopLength;i++){
    var num = Math.floor(Math.random() * playerArray.length);
    if(player1 == 0){
        player1 = num+1;
        playerArray.splice(num, 1);
    }else if(player2 == 0){
        player2 = num+1;
        playerArray.splice(num, 1);
    }

    if((player1 != 0) && player2 != 0){
        alert(player1 + ' vs ' + player2);
        player1 = 0;
        player2 = 0;
    }

}

我认为问题在于我使用索引来分配数字,当我拼接它们时它会重置索引,所以我最终可以得到 1 vs 2、1 vs 3、2 vs 3 等等。

任何帮助,将不胜感激。谢谢!

4

6 回答 6

2

我喜欢@JeroenVannevel 使用随机播放的想法,或者这是我脑海中浮现的一种方法:

// Given an array of player IDs, return an array of random pairs
function randomPairs( players ) {
    var pairs = [];
    while( players.length ) {
        pairs.push([
            pluckRandomElement( players ),
            pluckRandomElement( players )
        ]);
    }
    return pairs;
}

// Return a random element and remove it from the array
function pluckRandomElement( array ) {
    var i = randomInt( array.length );
    return array.splice( i, 1 )[0];
}

// Return a random integer 0 <= n < limit
function randomInt( limit ) {
    return Math.floor( Math.random() * limit );
}

@LeeMeador 分享了关于这段代码的有趣见解:

        output.push([
            pluckRandomElement( array ),
            pluckRandomElement( array )
        ]);

这里没有必要对两个值都使用随机元素。由于数组已经随机化,您可以选择第一个数组元素和一个随机元素。或者用于array.pop()提取最后一个元素——对于一个非常长的数组,可能会稍微更有效:

        output.push([
            array.pop(),
            pluckRandomElement( array )
        ]);

这是另一个版本,使用 Jeroen 建议的随机播放:

// Given an array of player IDs, return an array of random pairs
function randomPairs( players ) {
    shuffle( players );
    var output = [];
    for( var i = 0, n = players.length;  i < n;  i += 2 ) {
        output.push([ players[i], players[i+1] ]);
    }
    return output;
}

// Shuffle an array in place using the Fisher-Yates algorithm,
// adapted from http://bost.ocks.org/mike/shuffle/
function shuffle( array ) {
    for( var m = array.length;  m; ) {
        var i = Math.floor( Math.random() * m-- );
        var t = array[m];
        array[m] = array[i];
        array[i] = t;
    }
    return array;
}

可以使用以下代码测试任一版本:

// Create an array of length n and values 1 through n
function createPlayerArray( nPlayers ) {
    var array = [];
    for( var i = 0;  i < nPlayers;  ++i ) {
        array.push( i + 1 );
    }
    return array;
}

var players = createPlayerArray( 8 );
console.log( randomPairs(players) );

我将播放器数组的创建与其余代码分开,以考虑非连续播放器 ID 的可能性(例如数据库中的 ID 字段等)。

于 2013-07-12T16:56:03.437 回答
1

我不熟悉 javascript,所以请原谅任何语法错误:随时纠正它们。

我想到的是:

var playerArray = [0,1,2,3,4,5,6,7];
// Shuffle the array here. I just googled 
// and I noticed there is no shuffle function in JS, is this correct?
var player1 = 0;
var player2 = 0;
for(var i = 0, len = Math.floor(playerArray.length / 2); i < len; i++) {
   player1 = playerArray[i * 2];
   player2 = playerArray[(i * 2) + 1];
   alert(player1 + " vs " + player2);
}

您所要做的就是添加一个随机播放功能。

补充说明:

通过改组一组项目,您可以提取它们并检索随机结果。这里的关键是存储您提取的最后一项的指针,以便您知道从哪里继续。由于我们想要多个随机元素,我们应该以线性方式工作,从边界开始(在这种情况下是第一个索引并朝着结束工作)。

我们让循环运行到数组大小的一半。因为我们使用整数作为索引,所以将一个奇数分成两半 (7 => 3.5),循环将运行 3 次。因为我们有一个循环,所以我们也已经有了我们的指针 ( i)。唯一棘手的部分是确保您指向正确的索引:循环的每次遍历实际上使用 2 个索引,因此我们必须将其乘以 2。通过这样做,我们得到循环的第一项和第二项一个使用相同的方法,但将 1 添加到索引以获取下一项。

于 2013-07-12T16:57:31.897 回答
1
var playerArray = [0,1,2,3,4,5,6,7];  //your array
var loopLength = playerArray.length/2; //divid by 2 since you only want pairs
var player1 = 0; //intialize varibles
var player2 = 0;
for(var i = 1; i <= loopLength;i++){
  var num = Math.floor(Math.random() * playerArray.length); //generate a random number
  player1 = playerArray.splice(num, 1); //player1 = number from array
  num = Math.floor(Math.random() * playerArray.length); //generate a new random number
  player2 = playerArray.splice(num, 1); //player2 = number from array
  alert(player1 + ' vs ' + player2); //result

}
于 2013-07-12T16:48:41.790 回答
0
var playerArray = [0,1,2,3,4,5,6,7];
var opponentArray = [];

// mark everyone unassigned
for (var i = 0; i < playerArray.length; ++i) {
    opponentArray[i] = -1;
}

for (var i = 0; i < playerArray.length; ++i) {
    if (opponenentArray[i] == -1) {
        for (;;) {  // Keep trying until you get one that isn't assigned yet
            var num = Math.floor(Math.random() * playerArray.length);
            if (num != i && opponentArray[num] == -1) { // this one is unassigned and not me
                opponentArray[i] = num; // assign them to each other
                opponentArray[num] = i;
                break;
            }
        }
    }
}

笔记

有人指出,它们在获取随机数然后丢弃它们方面效率低下。

它必须进行测试,但我怀疑这是由于缺乏与在内存中移动数组元素相关的成本而抵消的。大多数人都splice在重新排列数组元素并在内存中创建更多对象,同时增加内存管理和垃圾收集成本。

感谢@JimmiTh 发现有人可能最终自己玩的错误。我想即使这段代码也需要测试:)

于 2013-07-12T16:46:04.437 回答
0

我认为您正在寻找的是更多类似的东西,除非我弄错了:

var playerArray = [0,1,2,3,4,5,6,7];
var player1 = 0;
var player2 = 0;

// While there are still numbers in the array, keep pairing up the players
while (playerArray.length > 0) {
    // Get the first players number from the array and then and remove it from the array
    var arrayNum1 = Math.floor(Math.random() * playerArray.length);
    player1 = playerArray[arrayNum1] + 1;
    playerArray.splice(arrayNum1, 1);

    // Get the second players number from the array and then and remove it from the array
    var arrayNum2 = Math.floor(Math.random() * playerArray.length);
    player2 = playerArray[arrayNum2]  + 1;
    playerArray.splice(arrayNum2, 1);

    // Display the pairing
    alert(player1 + ' vs ' + player2);
}

测试的一些示例结果:

1st run - (7, 3), (8, 1), (6, 5), (4, 2)
2nd run - (4, 6), (5, 7), (2, 3), (8, 1)
3rd run - (1, 8), (2, 6), (3, 5), (7, 4)
4th run - (6, 3), (5, 8), (7, 1), (4, 2)
5th run - (2, 4), (7, 5), (8, 6), (3, 1)
于 2013-07-12T19:35:03.923 回答
0

我最近不得不这样做。我喜欢洗牌算法的想法。我创建了一个混洗数组的副本数组(对),然后将该数组旋转 1。然后我匹配每个数组的索引以创建对。我认为这将为除大小为 1 和 2 的数组之外的所有数组创建唯一的对。

于 2016-09-10T11:39:41.717 回答