How to shuffle an array of items

55 Views Asked by At

In the following example an array of numbers is shuffled each time the document is refreshed. How do I apply the same function that shuffles the numbers to shuffle the blocks of color?

const points = [1, 2, 3, 4, 5, 6];
document.getElementById("numbers").innerHTML = points;

function myFunction() {
  for (let i = points.length - 1; i > 0; i--) {
    let j = Math.floor(Math.random() * (i + 1));
    let k = points[i];
    points[i] = points[j];
    points[j] = k;
  }
  document.getElementById("numbers").innerHTML = points;
}
<!DOCTYPE html>
<html>

<body onload="myFunction()">

  <div id="numbers"></div>

  <br>

  <div id="colors">
    <div style="width:50px; height:50px; background-color:red; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:yellow; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:blue; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:orange; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:green; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:purple; display:inline-block"></div>
  </div>

</body>

</html>

3

There are 3 best solutions below

0
Andrew Parks On BEST ANSWER

You can apply a shuffle directly to the DIVs. You start with an unshuffled region, and an initially empty shuffled region. You then pick items at random from the unshuffled region to place into the shuffled region.

let p = document.getElementById('colors')
let l = p.children.length
for(let i=l+1; --i;) p.appendChild(p.children.item(Math.random()*i|0))
<div id="colors">
    <div style="width:50px; height:50px; background-color:red; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:yellow; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:blue; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:orange; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:green; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:purple; display:inline-block"></div>
</div>

0
trincot On

Get the div elements in an array, shuffle it, and then append those elements again under the same parent element. The latter action will actually move them:

function shuffle(arr) { // Use parameter to make it more general purpose
  for (let i = arr.length -1; i > 0; i--) {
    let j = Math.floor(Math.random() * (i+1));
    let k = arr[i];
    arr[i] = arr[j];
    arr[j] = k;
  }
}

const colors = document.querySelector("#colors");
const children = [...colors.children]; 
shuffle(children);
colors.append(...children);
<div id="colors">
    <div style="width:50px; height:50px; background-color:red; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:yellow; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:blue; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:orange; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:green; display:inline-block"></div>
    <div style="width:50px; height:50px; background-color:purple; display:inline-block"></div>
</div>

0
Mr. Polywhirl On

You can break this into three parts:

  1. Get a random integer
  2. Get a random child
  3. Shuffle children

Always break the problem into smaller pieces.

const randInt = (min, max) => {
  let _min, _max;
  if (max === undefined) [_max, _min] = [_min, 0];
  [_min, _max] = [Math.ceil(min), Math.floor(max)];
  return Math.floor(Math.random() * (_max - _min + 1)) + _min;
}

const randChild = (el) => el.children.item(randInt(0, el.children.length - 1));

const shuffleChildren = (el) => {
  for (let i = el.children.length + 1; --i;) el.appendChild(randChild(el));
};

document.querySelector('#shuffle-btn').addEventListener('click', () =>
  shuffleChildren(document.querySelector('.palette')));
html, body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  background: black;
}

.palette { display: flex; gap: 0.25rem; }

.swatch {
  width: 50px;
  aspect-ratio: 1 / 1;
  background-color: var(--swatch-color);
}

.numbered {
  --shadow-blur: 3px;
  --shadow-color: rgba(0, 0, 0, 0.5);
  color: white;
  font-family: Arial;
  font-size: larger;
  font-weight: bold;
  text-shadow:  1px  1px var(--shadow-blur) var(--shadow-color),
               -1px  1px var(--shadow-blur) var(--shadow-color),
                1px -1px var(--shadow-blur) var(--shadow-color),
               -1px -1px var(--shadow-blur) var(--shadow-color);
}

.centered {
  display: flex;
  align-items: center;
  justify-content: center;
}
<div class="palette">
  <div class="swatch numbered centered" style="--swatch-color: red">0</div>
  <div class="swatch numbered centered" style="--swatch-color: yellow">1</div>
  <div class="swatch numbered centered" style="--swatch-color: blue">2</div>
  <div class="swatch numbered centered" style="--swatch-color: orange">3</div>
  <div class="swatch numbered centered" style="--swatch-color: green">4</div>
  <div class="swatch numbered centered" style="--swatch-color: purple">5</div>
</div>
<button type="button" id="shuffle-btn">Shuffle</button>