Home > Back-end >  Randomising arrays to form an highly entropic grid
Randomising arrays to form an highly entropic grid

Time:08-27

I am attempting to make a 5x5 grid using arrays with the following limitations

  • Should not exceed more than 4 check marks per grid
  • Should not have 2 consecutive check marks

This is what I have come up with so far, I would appreciate if someone could help me figure out how would I achieve the latter condition

 let emoji = {
            0: '✅',
            1: '❓',
   }
    let grid = []
        let checkmarks = 0
        for (let i = 0; i < 5; i  ) {
            let row = []
            for (let j = 0; j < 5; j  ) {
                let random = crypto.randomInt(0, 1000) % 2
                if (random == 0) {
                    if(checkmarks < 4) {
                    row.push(emoji[0])
                    checkmarks  
                    }
                    else {
                        row.push(emoji[1])
                    }
                } else {
                    row.push(emoji[1])
                }
            }
            grid.push(row)
        }

I am attempting to make it as random as possible.

CodePudding user response:

Instead of randomly determining if a cell should be a checkmark I would rather randomly find cells that should be a checkmark.

Your current solution decreases the chance of getting a checkmark with each cell.

Created some example code for you:

const emojis = ['✅', '❓']

const size = 5
const checkmarks = []

for (let i = 0; i < 4; i  = 1) {
  while (true) {
    // get random x and y
    const x = Math.random() * size | 0
    const y = Math.random() * size | 0
    // check if x and y are far enough from existing checkmarks
    const areNeighbours = checkmarks.some(c => {
      if (c.x === x) {
        return Math.abs(c.y - y) <= 1
      }
      if (c.y === y) {
        return Math.abs(c.x - x) <= 1
      }
      return false
    })

    if (!areNeighbours) {
      checkmarks.push({
        x,
        y
      })
      break
    }
  }
}

const grid = []

for (let y = 0; y < size; y  = 1) {
  grid.push([])
  for (let x = 0; x < size; x  = 1) {
    const checkmark = checkmarks.find(c => c.x === x && c.y === y)
    grid[y][x] = checkmark ? emojis[0] : emojis[1]
  }
}


console.log(grid.map(row => row.join('')).join('\n'))

CodePudding user response:

Imagine a 5x5 board initially filled by ❓.

Next you toss 4 coins at once, each coin will landed in one cell, head or tail.

If head, place a ✅ in the cell.

Now check if non-consecutive ✅ condition is met. If not start over.

Solution:

const emojis = ['✅', '❓'];

function randomInt(min, max) {
  return min   Math.floor(Math.random() * (max - min));
}

function tossCoins(checkmarkLimit, size) {
  const positions = Array.from({ length: checkmarkLimit }, () => {
    const pos = randomInt(0, size * size);
    const tail = Math.random() > 0.5;
    if (tail) return null;
    const x = pos % 5;
    const y = (pos - x) / 5;
    return [x, y];
  })

  return positions.filter(Boolean);
}
 
function checkNonConsecutive(positions) {
  for (let i = 0; i < positions.length; i  ) {
    const p = positions[i];
    for (let j = 0; j < positions.length; j  ) {
      if (i == j) continue;
      const o = positions[j];
      const distance = Math.abs(p[0] - o[0])   Math.abs(p[1] - o[1])
      if (distance <= 1) {
        return false;
      }
    }
  }
  return true;
}

function main() {
  const checkmarkLimit = 4;
  const size = 5;
  const grid = Array.from({ length: size }, () => Array.from({ length: size }, () => emojis[1]));

  let positions = tossCoins(checkmarkLimit, size);
  while (!checkNonConsecutive(positions)) {
    positions = tossCoins(checkmarkLimit, size);
  }
  
  positions.forEach(([x, y]) => {
    grid[y][x] = emojis[0];
  });
  
  return grid;
}

for (let n=0; n < 10; n  ) {
  console.log('round: '   n);
  console.log(main().map(row => row.join('')).join('\n'));
}

  • Related