Javascript 中 2 个数组的所有可能组合

问题描述 投票:0回答:1

美好的一天,尊敬的 StackOverflow 贡献者。

我目前正在构建一款 Ludo 游戏。这是一个简单的游戏,游戏的核心是令牌和骰子。我的目标是生成所有可能的动作组合。通常,Ludo 使用 2 个骰子。所以一次投掷应该给出 2 个骰子值。但有一个例子,当投掷(双六)为同一玩家的另一次投掷做好准备时。但由于预期的移动组合是一个巨大的结果,因此我决定通过不重复骰子值来使事情变得简单,换句话说,避免数组中出现两个 6,以帮助清晰地了解结果的模式。

因此数组:

const diceValues = [1, 3, 4, 6];
const tokens = ['A', 'B', 'C', 'D'];
const moves = [];

我的习惯解决方案是记下我期望的结果模式,然后定制代码以匹配。通过嵌套循环,我取得了一些进展,但正如预期的那样,我达到了临界点,我觉得需要一个优雅的递归(还有什么?)会有用。

下面列出了我可以在一个标记(“A”)的循环上组合的可能组合,以使其不会太长并提供一种想法。另外,我以非技术性的方式编写此列表,因此很容易理解:

例如:

A1 B346, A1 C346, A1 D346

但是在编码时,这是被推入移动数组的格式:

例如:

[ {'A': [1], 'B': [3, 4, 6]}, {'A': [1], 'C': [3, 4, 6]}, {'A': [1], 'D': [3, 4, 6]} ]

重要注意事项:

  1. 所有骰子值必须用完(即与至少 1 个令牌关联。

    A1 B3 C4
    之类的东西不是合法的移动,因为剩余的骰子值 6 尚未用完)。

  2. 并不强制要求所有代币都用完。 (一个令牌可以与所有 4 个骰子值相关联,例如

    A1346
    )。

现在我们清楚了,这是列表:

A1 B346, A1 C346, A1 D346 
A3 B146, A3 C146, A3 D146
A4 B136, A4 B136, A4 D136
A6 B134, A6 C134, A6 D134
 
A13 B46, A13 C46, A13 D46
A13 B4 C6, A13 B4 D6 
A13 C4 B6, A13 C4 D6
A13 D4 B6, A13 D4 C6

A14 B36, A14 C36, A14 D36
A14 B3 C6, A14 B3 D6
A14 C3 B6, A14 C3 D6
A14 D3 B6, A14 D3 C6

A16 B34, A16 C34, A16 D34
A16 B3 C4, A16 B3 D4
A16 C3 B4, A16 C3 D4
A16 D3 B4, A16 D3 C4

A34 B16, A34 C16, A34 D16
A34 B1 C6, A34 B1 D6
A34 C1 B6, A34 C1 D6
A34 D1 B6, A34 D1 D6

A34 B16, A34 C16, A34 D16
A34 B1 C6, A34 B1 D6
A34 C1 B6, A34 C1 D6
A34 D1 B6, A34 D1 C6

A36 B14, A34 C14, A36 D14
A36 B1 C4, A36 B1 D4
A36 C1 B4, A36 C1 D4
A36 D1 B4, A36 D1 C4

A46 B13, A46 C13, A46 D13 
A46 B1 C3, A46 B1 D3
A46 C1 B3, A46 C1 D3
A46 D1 B3, A46 D1 C3

A134 B6, A134 C6, A134 D6 
A136 B4, A136 C4, A136 D4
A146 B6, A146 C3, A146 D3
A346 B1, A346 C1, A346 D1

A1346 

总共88个循环

那么下一个令牌循环将类似于:

B1 A346, B1 C346, B1 D346
等等……

因此此时预计有 88 * 4 = 352 个循环

将所有代币分配给所有骰子值的最终部分:

A1, B3, C4, D6
A1, B3, C6, D4
A1, B6, C3, D4
A6, B1, C3, D4
A1, B4, C3, D6
A1, B4, C6, D3
A1, B6, C4, D3
A6, B1, C4, D3
A4, B1, C3, D6
A4, B1, C6, D3
A4, B6, C1, D3
A6, B4, C1, D3
A3, B1, C4, D6
A3, B1, C6, D4
A3, B6, C1, D4
A6, B3, C1, D4
A3, B4, C1, D6
A3, B4, C6, D1
A3, B6, C4, D1
A6, B4, C3, D1
A6, B3, C4, D1
A4, B3, C1, D6
A4, B3, C6, D1
A4, B6, C3, D1

我估计总共有448个周期。

两个数组都有 4 个长度,但我希望有一个解决方案能够在更长且不同长度的数组上正常工作。

感谢您的努力。我不介意采用完全不同的方法。更简洁的东西也可能有帮助。最后,但不是必需的,希望看到一种数学方法来计算可能的移动组合,以便在一定程度上保证结果的准确性,至少在长度上是这样。

我的做法:

const tokens = ['A', 'B', 'C', 'D'];
const diceValues = [1, 3, 4, 6];
let moves = [];


const moveCollection = (tokens, diceValues) => {
    diceValues.map((die, dieIndex) => {    // [1, 3, 4, 6]
        const leftDiceValues = diceValues.slice(0, dieIndex + 1); // [1], [1, 3], [1, 3, 4], [1, 3, 4, 6]
        const rightDiceValues = diceValues.slice(dieIndex + 1, diceValues.length); // [3, 4, 6], [3, 4, 6], [4, 6], [6]

        tokens.map((token, tokenIndex) => { // [A, B, C, D]
            const remTokens = tokens.slice();
            remTokens.splice(tokenIndex, 1);    // [B, C, D], [A, C, D], [A, B, D], [A, B, C]

            remTokens.map((remToken, remTokenIndex) => {
                moves.push([
                    { [token]: leftDiceValues },    // {A: [1]}
                    { [remToken] : rightDiceValues }    // {B: [3, 4, 6]}
                ]);
            });

            // It was at this point I felt the need for some sort of recursive solution
            // This condition was necessary only to prove the 1st loop new format of 
            // [ {A: [3], B: [1, 4, 6]}, {A: [3], C: [1, 4, 6]}, {A: [3], D: [1, 4, 6]} ]
            
            if (dieIndex === 0) {
                rightDiceValues.map((rightDiceValue, rightDiceIndex) => {   // [3, 4, 6]
                    const remDiceValues = diceValues.slice();   // [1, 3, 4, 6]
                    remDiceValues.splice(rightDiceIndex + 1, 1);
                    remTokens.map((remToken, remTokenIndex) => {
                        moves.push([
                            { [token]: rightDiceValue },    // {A: [3]}
                            { [remToken]: remDiceValues }    // {B: [1, 4, 6]}
                        ]);
                    });
                });
            }
        });
    });
}
moveCollection(tokens, diceValues);
javascript arrays loops combinations permutation
1个回答
0
投票

那么,对于任何骰子值,您是否需要获取这些棍子的所有动作?

好吧,要做这样的事情,我们需要做一些非常重要的事情,列出骰子的所有概率:

  • 两个骰子的值低于 12,然后我们计算游戏板上每根棍子的位置,除了房子里的棍子(或其他什么),并且,不是我在这里的任务,检查该棍子是否可以通过查看锁来归还另一位玩家的另一根棍子。
  • 如果两个骰子的点数都是12,那么一根棍子可以出家,或者玩家可以移动,骰子可以扔出去,如果再扔一次,然后就不再扔了,简单!

现在,让我们开始执行解决方案,首先我们将制作一个定位系统,如果需要的话可以制作自己的,这是我自己的:位置从棍子获得的第一个插槽开始,每种颜色都不同,通过使用这个:

var differentiateGap = 13 // The distance between the first color and the second
var total = 52 // The total slots are there
var additional = 5 // The number of slots till the player arrives to the win, the win slot is exclusive
var playerSlot = 51 // The number of slots till the stick arrives to additional, without actual additional slots
var throwAgain = false // To tell if to throw again
var throws = 0 // To see how many times the dice got thrown

var players = {
    yellow: [
        {
            slot: -1, // For example, to indicate it is inside the 1st slot in house
            won: false // To indicate if the stick won
        }
    ],
    // ...
}

function diceThrow() {
    let randomNum = Math.floor(Math.random())*5 + 1 // For first throw
    let randomNum2 = Math.floor(Math.random())*5 +1 // For second throw

    if(randomNum + randomNum2 == 12) { // Now the two dices have the number 6
        players.yellow.forEach(function(stick) {
            if(stick.slot >= 0) boardGuide(stick.slot + randomNum + randomNum2, "yellow") // A custom function
            else boardGuide(0, "yellow")
        })
        if(throws <= 2){
            throwAgain = true
            throws++
        }
    }

    else {
        players.yellow.forEach(function(stick) {
            if(stick.slot >= 0) boardGuide(stick.slot + randomNum + randomNum2, "yellow") // A custom function
        })

        throwAgain = false
    }
}

document.getElementById("button").onclick = function() {
    diceThrow()
    // Do your algorithms
}

告诉我你需要什么,因为我的答案还不够

© www.soinside.com 2019 - 2024. All rights reserved.