2

I´m creating a Bingo board and I need that the one in the middle always stays the same even when shuffleing this array:

 const bbb = [
  "",
  "",
  "",
  "",
  "",
  "",
  "",
  "",
  "",
  "",  
  " ",
  "",
  "",
  "",
  "",
  "",
  " ",
  " ",
  "",
  "",
  "",
  "",
  " ",
  "",
  ""
];

const data = arrayShuffle(bbb).reduce(
  (data, value, index) => ({ ...data, [index]: value }),
  {}
);

and then Im maping the array to display the Tiles and create the board like this:

 {Object.keys(data).map(id => (
      <Tile
        key={id}
        id={id}
        isSet={state.checked[id]}
        onToggle={() => toggle(id)}
      >
        {data[id]}
      </Tile>
    ))}
Amila Senadheera
  • 12,229
  • 15
  • 27
  • 43

2 Answers2

0

Remove the middle item from the array initially. Then do the in-place randomizing of items and finally attach the middle item to the array.

This runs in O(n) time complexity where n is the size of your array and you always get a uniform random permutation.

const bbb = [ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ];

const getRandomInt = (min, max) => {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min)) + min;
};

const arrayShuffleInplaceExceptMiddle = (A) => {
  const middle = A.splice(A.length/2, 1);
  const n = A.length;
  const middleIndex = Math.floor(n / 2);
  for (let i = 0; i < n; i++) {
    let swapIndex = getRandomInt(i, n);
    let a = A[i];
    A[i] = A[swapIndex];
    A[swapIndex] = a;
  }
  A.splice(n/2, 0, ...middle)
};

// test runs
Array.from({length: 10}, () => {
  arrayShuffleInplaceExceptMiddle(bbb);
  console.log(bbb.join(""));
})
Amila Senadheera
  • 12,229
  • 15
  • 27
  • 43
0

Just shuffle the array normally, but remove the the value before the shuffle and insert it back afterward:

/**
 * Durstenfeld shuffle
 *
 * - https://stackoverflow.com/a/12646864/438273
 * - https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
 *
 * @param {unknown[]} array
 */
function shuffleArray (array) {
  for (let i = array.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [array[i], array[j]] = [array[j], array[i]];
  }
}

/**
 * Like a normal shuffle, but for a bingo board
 *
 * @param {unknown[]} array
 */
function bingoShuffle (array) {
  const index = Math.floor((array.length - 1) / 2);
  const [value] = array.splice(index, 1);
  shuffleArray(array);
  array.splice(index, 0, value);
}

// Let's keep the board small for this demo:
const board = [
  "",
  "",
  "",
  "",
  "",
  "",
  "",
  "",
  "",
];

console.log(board.join(' '));

// Shuffle it a few times and look at the results:
for (let i = 0; i < 10; i += 1) {
  bingoShuffle(board);
  console.log(board.join(' '));
}

And because you tagged this with reactjs, I'm guessing this is (immutable) state, so you'll need to get a new array when shuffling, like this:

const updatedBoard = bingoShuffle([...board]);
//                                ^^^^^^^^^^
// Shallow copy into new array so you don't mutate React state
jsejcksn
  • 27,667
  • 4
  • 38
  • 62