0

The code is supposed to create win condition for the game. Imagine an array with 64 numbers: (0...63). The code cuts this array every 4 numbers and then shuffles them: (0,1,2,3)=>(1,0,3,2) etc. The main part is the loop through those numbers:

  • we pick the first number from the first set and move on (in the example it was 1) and push it to our win condition array (finale array);
  • on the second randomized set (5,4,7,6) we also pick the first number, but we supposed to check if this number is not in the same iteration as the one before (so, 0 is 1st, 1 is 2nd etc.; 4 is 1st, 5 is 2nd etc.). The number 5 is in the same place, so we supposed to pick next number in the array, which is 4 in this example. 4 fits the condition, so we move on;
  • we have the third set (8,9,11,10), where we repeat the previous action to check if the position of the element in this set is the same as in the previous sets! 8 is 1st and 4 is 1st, so we change it to the next number - 9. But here is the complication - we are supposed to check with the first set as well. 9 is 2nd and 1 is 2nd, so we move to the next number, which is 11;
  • on the last iteration of sets we repeat all the above procedures by checking every number of the previous sets with the one in our array. We pick 15 from (12,15,13,14) on the second try;
  • we start again every 16 numbers.

The finale array will be something like this (1,4,11,15,16,...,61) with 16 numbers in it.

I already wrote the needed code that works just fine, but I want it to be smarter and shorter. I do understand that the answer requiers a recursion approach, yet I have no idea how to use it.

Here is the code itself:

let currDiff = 4;

function createWinCond() {
let numb = []
let winNum = []
winCond = []
for (let i = 0; i < currDiff * currDiff * currDiff; i++) {
    numb.push(i) //array with numbers from 0 to 63
    if (numb.length % currDiff == 0) {
        winNum = shuffle(numb) // I have a function that shuffles those numbers
        for (let j = 0; j < currDiff; j++) {
            if (winCond[j] == undefined || winCond.length % currDiff == 0) {
                winCond.push(winNum[j]);
                break;
            }
            if ((winCond.length + currDiff) % currDiff == 1 && winCond[winCond.length - 1] != (winNum[j] - currDiff)) {
                winCond.push(winNum[j]);
                break;
            }
            if ((winCond.length + currDiff) % currDiff == 2 && winCond[winCond.length - 1] != (winNum[j] - currDiff) && winCond[winCond.length - 2] != (winNum[j] - currDiff * 2)) {
                winCond.push(winNum[j]);
                break;
            }
            if ((winCond.length + currDiff) % currDiff == 3 && winCond[winCond.length - 1] != (winNum[j] - currDiff) && winCond[winCond.length - 2] != (winNum[j] - currDiff * 2) && winCond[winCond.length - 3] != (winNum[j] - currDiff * 3)) {
                winCond.push(winNum[j]);
                break;
            }                
        }
        numb = [];
        winNum = [];
    }
}

If you have any idea how this could be written better, please, let me know.

Sourav Dutta
  • 145
  • 8
Alex Bird
  • 11
  • 5

1 Answers1

0

I think I understand the rules you're working with, and if so, then yes, this can be simplified a lot. Here's my thinking: From each independent group of sixteen we will think of groups of four, and the indices we will choose for the elements from those groups will be a permutation of the set {0, 1, 2, 3}. That permutation can be chosen at random from the 24 possibilities.

By collecting those 24 partitions and writing a quick function to choose one of those at random, we can write this function quite simply:

const perms = [[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1], [0, 3, 1, 2], [0, 3, 2, 1], 
               [1, 0, 2, 3], [1, 0, 3, 2], [1, 2, 0, 3], [1, 2, 3, 0], [1, 3, 0, 2], [1, 3, 2, 0], 
               [2, 0, 1, 3], [2, 0, 3, 1], [2, 1, 0, 3], [2, 1, 3, 0], [2, 3, 0, 1], [2, 3, 1, 0], 
               [3, 0, 1, 2], [3, 0, 2, 1], [3, 1, 0, 2], [3, 1, 2, 0], [3, 2, 0, 1], [3, 2, 1, 0]]
const randomPerm = () => perms [Math .floor (Math .random () * perms .length)]

const createWinCond = () => 
  [0, 1, 2, 3] .flatMap ((i) => randomPerm () .map ((j, k) => 16 * i  + 4 * k + j))

console .log (createWinCond ())
.as-console-wrapper {max-height: 100% !important; top: 0}

We will combine the three values i, j, and k, each taking on a value from 0 to 3. So i represents the group of sixteen. For each one of those, we select a random permutation, and mapping over those values, we will have k representing an index into that partition, that is, representing the group of four within that group of sixteen, and j represents the actual index value within that group. With that, 16i + 4k + j gives us our values.

Note that the only random calls we need to make are to choose the random permutations. We don't need to do any shuffling. More importantly, we don't need to do any testing of whether we're reusing an index inside a block.

To simplify this, we might prefer to use a permutations function to generate those initial permutations, or we might prefer a version like this:

const perms = `0123 0132 0213 0231 0312 0321 1023 1032 1203 1230 1302 1320
               2013 2031 2103 2130 2301 2310 3012 3021 3102 3120 3201 3210`
  .split (/\s+/) .map (p => p.split ('') .map (Number))

I'm not 100% certain I've captured your requirements, but it feels as though I have, and this is significantly simpler.

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103