JSFiddle - React, Tailwind, and code Playground

by Sergei Sokolov

HTML

<button>перестрой-ка</button>
<div id="container"></div>

CSS

.box {
  width:42px;
  height:26px;
  padding:16px 0 0;
  margin:0;
  border:1px solid #CCC;
  float: left;
  text-align: center;
  font-family:Helvetica,Arial,sans-serif;
  font-size: 10px;
}
.row {clear: both}
.type0 {background: #AAA}
.type1 {background: #9F0}
.type2 {background: #09F}
.type3 {background: #F09}

JavaScript

// block ids 0..3 
// 0 bit: width:  0: 1 sqr, 1: 2 sqr
// 1 bit: height: 0: 1 sqr, 1: 2 sqr

function fill(w, h) {
	const M = Array(h).fill(null).map(() => Array(w).fill(0));
  
	let count = 0;
	while(count++ < 1000) {
    const topRow = M.findIndex(row => !!~row.indexOf(0));
    if (-1 === topRow) break;
    const row = M[topRow];

// find index and length of longest blank in the row
    const max = row.reduce(function(p,c,i,a) {
    	if (c === 0) {
      	p.len++;
        if (!p.blank) {
        	p.pos = i;
          p.blank = true;
        }
      } else {
      	if (p.blank) {
        	if (p.maxlen < p.len) {
          	p.maxlen = p.len;
            p.maxpos = p.pos;
          }
          p.len = 0;
          p.pos = -1;
          p.blank = false;
        }
      }
      return p;
    }, {len: 0, pos: -1, maxlen: 0, maxpos: -1, blank: false});
    
    if (max.blank  &&  max.maxlen < max.len) {
      max.maxlen = max.len;
      max.maxpos = max.pos;
    }
    
    let code = 0;
    if (max.maxlen > 1) // can fit height 2 ?
      code |= Math.random() > 0.5;  // bit 0
    if (topRow < M.length - 1)     // can fit width 2 ?
      code |= (Math.random() > 0.5) << 1;  // bit 1

    // place the block at position max.maxpos
    for (let y = 0; y < ((code & 2) ? 2 : 1); y++) {
      for (let x = 0; x < ((code & 1) ? 2 : 1); x++) {
        M[topRow + y][max.maxpos + x] = '' + code + '_' + count;
      }
    }
  }
  
  return M;
}

function draw(element, M) {
  function adddiv(parent, type, text) {
    const div = document.createElement('div');
    div.classList.add('box', 'type' + type);
    div.innerText = text;
    parent.appendChild(div);
  }
  for (let y=0; y<M.length; y++) {
  	const rowdiv = document.createElement('div');
    rowdiv.className = 'row';
  	const row = M[y];
  	for (let x=0; x<row.length; x++) {
    	adddiv(rowdiv, row[x].substr(0,1), row[x].substr(2));
    }
    element.appendChild(rowdiv);
  }
}

const container =...