1

During the use of this function you click a button that will give you a square that will display a colour within a square. However when you click the button 60 times the programme stops working because all the colours have been used. How would I then restart this process so that I can continue clicking ?

<html>
    <head>
        <script>
            var usedColors = [];
            
            function randomColour(){
                var colour=[];
                colour[0]= '#edf2fb';
                colour[1]= '#d7e3fc';
                colour[3]= '#c1d3fe';
                colour[4]= '#d1d1d1';
                colour[5]= '#e1dbd6';
                colour[6]= '#e2e2e2';
                colour[7]= '#f9f6f2';
                colour[8]='#ffc09f';
                colour[9]='#ffee93';
                colour[10]='#fcf5c7';
                colour[11]='#a0ced9';
                colour[12]='#adf7b6';
                colour[13]='#809bce';
                colour[14]='#95b8d1';
                colour[15]='#b8e0d2';
                colour[16]='#d6eadf';
                colour[17]='#eac4d5';
                colour[18]='#e8d1c5';
                colour[19]='#eddcd2';
                colour[20]='#fff1e6';
                colour[21]='#f0efeb';
                colour[22]='#eeddd3';
                colour[23]='#e8dff5';
                colour[24]='#fce1e4';
                colour[25]='#fcf4dd';
                colour[26]='#ddedea';
                colour[27]='#daeaf6';
                colour[28]='#d3ab9e';
                colour[29]='#eac9c1';
                colour[30]='#ebd8d0';
                colour[31]='#ffe5ec';
                colour[32]='#ffc2d1';
                colour[33]='#ceb5b7';
                colour[35]='#b5d6d6';
                colour[36]='#f2f5ff';
                colour[37]='#efcfe3';
                colour[38]='#eaf2d7';
                colour[39]='#b3dee2';
                colour[40]='#f8ad9d';
                colour[41]='#fbc4ab';
                colour[42]='#ffdab9';
                colour[43]='#cdb4db';
                colour[44]='#ffc8dd';
                colour[45]='#ffafcc';
                colour[46]='#bde0fe';
                colour[47]='#a2d2ff';
                colour[48]='#fdffb6';
                colour[49]='#caffbf';
                colour[50]='#9bf6ff';
                colour[51]='#a0c4ff';
                colour[52]='#ffc6ff';
                colour[53]='#a7bed3';
                colour[54]='#c6e2e9';
                colour[55]='#f1ffc4';
                colour[56]='#ffcaaf';
                colour[57]='#dab894';
                colour[58]='#fec7bc';
                colour[59]='#fcf5ee';
  
                var pick= Math.floor(Math.random()*60);
  
                if(usedColors.includes(pick)){
                    randomColour();
                }
  
                usedColors.push(pick); document.getElementById("colorpad").style.backgroundColor = colour[pick];
                console.log(usedColors);
            }
        </script>
    </head>
    <body>
        <div id="colorpad" style="height: 300px; width: 300px;">
            <button onclick="randomColour()">btn</button>
        </div>
    </body>
</html>
Sercan
  • 4,739
  • 3
  • 17
  • 36
Kailau05
  • 23
  • 6
  • 1
    Simply check the length of `usedColors` and [empty it](/q/1232040/4642212)? – Sebastian Simon Dec 20 '21 at 10:17
  • 2
    `if(usedColors.length === 60) usedColors = []` – Vaibhav Vishal Dec 20 '21 at 10:17
  • I think you should just randomize the color-hex value ;) https://stackoverflow.com/questions/5092808/how-do-i-randomly-generate-html-hex-color-codes-using-javascript – john Smith Dec 20 '21 at 10:38
  • @SebastianSimon The usedColors does not have a length set. – Kailau05 Dec 20 '21 at 10:38
  • @Kailau05 What do you mean by that? `usedColors` is an array. Every array has a length. – Sebastian Simon Dec 20 '21 at 10:54
  • @SebastianSimon Sorry Sebastion the length is 0-59 and the math.pow is used to select a random number between 0-59, but I did not expect the code to stop at 60. – Kailau05 Dec 20 '21 at 11:02
  • @Kailau05 The length of `colour` is `60` in your example. I don’t see how this has anything to do with `Math.pow`, but if you mean `Math.random`, then so what? You select random _indexes_. The length stays the same. Do you understand why the code breaks? You fill `usedColors` with indexes. If the randomly picked index is already included, you run the function again until you find one that isn’t included yet. Once `usedColors` reaches the same length as `colour`, there will never be an unused index. That’s why you want to reset. So simply check when the lengths match. – Sebastian Simon Dec 20 '21 at 11:15

2 Answers2

1

Keep track of the current color:

let curr = 0;

On "Next" button click increment the curr index, and loopback with the help of the Modulo Operator %:

curr += 1;
curr %= colour.length; // On "next" loop back to 0 if we reached the end

Finally there's your color back at 0

console.log(colour[curr]);    // '#edf2fb'

Demonstration:

const EL = (sel, EL) => (EL||document).querySelector(sel);

const colors = [
  '#edf2fb',
  '#d7e3fc',
  '#c1d3fe',
  '#d1d1d1',
  '#e1dbd6',
  '#e2e2e2',
  '#f9f6f2',
  '#ffc09f',
  '#ffee93',
  '#fcf5c7',
];

const tot = colors.length;
let curr = 0;

const curr_rand = () => curr = Math.floor(Math.random() * tot);
const curr_next = () => (curr += 1, curr %= tot);
const applyColor = () => EL("body").style.background = colors[curr];

EL("#rand").addEventListener("click", () => {
  curr_rand();
  applyColor();
  console.log(curr);
});

EL("#next").addEventListener("click", () => {
  curr_next();
  applyColor();
  console.log(curr);
});
<button type="button" id="rand">Generate</button>
<button type="button" id="next">Next</button>
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
  • Would you be able to edit the code so I am able to see where I should place the code ? – Kailau05 Dec 20 '21 at 10:33
  • @Kailau05 simply replace your entire code with mine. Than eventually add the missing `usedColors` logic... if needed. – Roko C. Buljan Dec 20 '21 at 10:34
  • how would I fit this into a square I added the div id="colorpad" style="height:300px; width:300px; into the code but it did not seem to work would you mind implementing this within your code so I can try it out. Thank you very much! – Kailau05 Dec 20 '21 at 12:29
  • @Kailau05 https://jsfiddle.net/uwyc76h1/ hope it helps. It was a pretty simple edit. – Roko C. Buljan Dec 20 '21 at 12:34
0

Here's a snippet using a small factory function to be able to recolor infinitely. The recoloring is done using a randomly shuffled copy of the color array. This way you don't have to check each time if a color is already used.

Furthermore, see comments in the snippet. It uses event delegation for the handler, because it's generally not a good idea to use inline event handlers.

To keep the snippet lean, only 10 colors are used.

const colorize = randomColor(
  ['#edf2fb', '#d7e3fc', '#c1d3fe', '#d1d1d1', '#e1dbd6',
   '#e2e2e2', '#f9f6f2', '#ffc09f', '#ffee93', '#fcf5c7'] );

document.addEventListener(`click`, evt => {
  if (evt.target.id === `colorChange`) {
    return colorize(document.querySelector(`.color`));
  }
});

// randomColor is a factory function, it returns a function. 
// The function can use the inner variables as well as the 
// [colors] array from the parameter(they are 'closed over'). 
// The [colors] array is shuffled randomly (Fisher-Yates) and 
// on every call (from click) the first color from that shuffled 
// array is picked - until it's empty. If [shuffled] is empty 
// the original [color] array is reshuffled (into [shuffled]).
// This way  the coloring is restarted with a new set of 
// random colors.
function randomColor(colors){
  const shuffle = array =>
    [...Array(array.length)]
      .map((el, i) => Math.floor(Math.random() * i))
      .reduce( (a, rv, i) => 
        ([a[i], a[rv]] = [a[rv], a[i]]) && a, array.slice());
  //                                          ^ slice copies the original      
  let shuffled = shuffle(colors);
  
  // return a function
  return colorDiv => {
    const restarted = !shuffled.length;
    shuffled = shuffled.length > 0 ? shuffled : shuffle(colors);
    const nwColor = shuffled.shift();
    colorDiv.style.backgroundColor = nwColor;
    
    // for demo: color is displayed, and bold/red if [shuffled] is renewed
    colorDiv.classList[restarted ? `add` : `remove`](`restart`);
    colorDiv.dataset.color = nwColor;
  }
}
.color {
  width: 100px;
  height: 100px;
  border: 1px solid #777;
  margin: 1rem 0;
  text-align: center;
  line-height: 100px;
}

.color:before {
  content: attr(data-color);
}

.color.restart:before {
  color: red;
  font-weight: bold;
}
<div class="color"></div>

<button id="colorChange">change</button>
KooiInc
  • 119,216
  • 31
  • 141
  • 177