0

I need to build 2d matrix 50x50 representing boxes with random colors, but if the boxes which are close to each other have the same colors, they should get different random color from each other, until it's different and then continue building.

Here I made matrix with boxes inside it works fine, but colors sometimes do match:

function onLoad(evt)
{       
        
        var matrix = [];
        

        for (var i = 0; i < 50; i++) {
            var row = [];
            for (var j = 0; j < 50; j++) {
                var randColor = Math.floor(Math.random()*16777215).toString(16);
                row.push(MyComponent(randColor));
                }
                matrix.push(row);
            }
        
        
        var newData = matrix.map(function(row) {
                return row.map(function(x) {
                        return x;
       })})
       
     
           
         
}
Dmitry Bochok
  • 71
  • 2
  • 12

1 Answers1

3

You need a way to determine whether a particular color is too close to another. One way to do this is with rgb-lab (or, less accurately, euclidean distance). Say you use rgb-lab's deltaE function, which takes two arguments, where each argument is a 3-item array of RGB amounts.

Generate your random colors such that you can get their components' decimal values easily, and so that you can also get their hex string representation easily. Then iterate over the filled adjacent indicies and compare the colors. If they're too similar, try again. Something along the lines of:

const MINIMUM_DISTANCE = 25;
const getColor = () => {
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);
    const str = r.toString(16) + g.toString(16) + b.toString(16);
    return { rgb: [r, g, b], str };
};
const matrix = [];
for (let i = 0; i < 50; i++) {
    const row = [];
    for (let j = 0; j < 50; j++) {
        let color;
        let tooClose = false;
        do {
            color = getColor();
            tooClose =
                (row[j - 1] && deltaE(color.rgb, row[j - 1].rgb) < 25) ||
                (matrix[i - 1] && deltaE(color.rgb, row[i - 1][j].rgb < 25));
        } while (tooClose);
        row.push(color);
    }
}

Change the MINIMUM_DISTANCE as desired. See here for an explanation of the numbers.

Then you'll need to turn the color objects into an array of components with color strings at the end.

const arrayOfComponents = matrix.map(
  row => row.map(
    ({ str }) => MyComponent(str)
  )
);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • that's good, but the problem is that I'm not able to use any libraries, but vanilla js – Dmitry Bochok Apr 22 '22 at 02:29
  • Feel free to copy and paste the library code into your own, it's super trivial (MIT license) – CertainPerformance Apr 22 '22 at 02:29
  • getColor() throws an error invalid object initializer here: { rgb: [r, g, b], str } – Dmitry Bochok Apr 22 '22 at 02:45
  • 1
    The syntax is correct in any non-obsolete environment. I highly recommend using a modern environment that's *at least* capable of understanding ES2015 syntax - it's 2022 (and don't use Internet Explorer). If you're forbidden from doing that for some reason, the shorthand initializer desugars to `rgb: [r, g, b], str: str` – CertainPerformance Apr 22 '22 at 02:47
  • This one has worked. No errors, but no image too. Yes, I'd love to use modern environment, but the problem is that system works on tgml instead of html, it doesn't have proper console and was developed about 10 years ago or so... – Dmitry Bochok Apr 22 '22 at 02:55