All possible combinations of 2 arrays in Javascript

68 Views Asked by At

Good day, esteemed StackOverflow contributors.

I am currently building a Ludo game. It's a simple game and at the core of the game are tokens and dice. What I aim to achieve is generate all possible combination of moves. Usually, Ludo works with 2 dice. So a throw should give 2 dice values. There is an instance though, when a throw (double-six) makes provision for another throw by same player. But because the expected combination of moves is a huge result, I've decided to keep things simple by not repeating the dice Values, in other words, avoiding two 6's in the array, in order to aid clarity in the result's pattern.

Hence the arrays:

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

My customary solution below was to make a note of the pattern of results I would expect, then tailor the code to match. With nested loops I made some progress but as expected, I reached that breaking point where I felt the need an elegant recursion (what else?) would avail.

Below is a list of the possible combinations I could muster on the loop of one token ("A"), in order to keep it not too long and as also provide an idea. Also, I write this list non-technically so it's easy on the eye:

e.g: A1 B346, A1 C346, A1 D346

but while coding, this is the format that gets pushed into the moves array:

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

Important things to note:

  1. All dice values must be used up (i.e. associated with at least 1 token. Something like A1 B3 C4 is not a legal move because the remaining die value of 6 has not been used up).

  2. It is not mandatory all tokens are used up. (One token may associate with all 4 dice values e.g. A1346).

Now we are clear, here's the list:

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 

In total, this is 88 loops

Then the next token loop would be something like:

B1 A346, B1 C346, B1 D346 and on and on...

Thus at this point would be expecting 88 * 4 = 352 loops

Final segment which distributes all tokens to all dice values:

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

I estimate a total number of 448 cycles.

Both arrays were of 4 lengths, but I expect a solution that would work just fine on arrays with longer and varying lengths.

Thank you for your efforts. I would not mind a completely different approach. Something more terse too could be of help. Finally, but not necessary, would love to see a mathematical way to calculate the combination of possible moves so the accuracy of the results is somewhat guaranteed, at least by length.

My approach:

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);
1

There are 1 best solutions below

1
hasan darwish On

So, do you need to get all the movements for these sticks for any dice value ?

well, to make such thing, we need to do something really important, list all the probabilities of a dice :

  • The two dices have a value of lower than 12, then we calculate the position of each stick in the playboard, except the ones in the house (or whatever are it), and, not of my mission here, check if that stick can return another stick of another player by viewing the lock .
  • If the value of the two dices are 12, then a stick can get out of the home, or the player can move, and the dice can be thrown, if again, another throw, and no throw after, simple !

Now, let's start executing the solution, first we will make a positioning system, just make your own if you need, this is my own : the position starts from the first slot the stick gets from, and each color is different than the other, by using this :

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
}

Tell me anything you need, as my answer is not enough