JSFiddle - React, Tailwind, and code Playground

HTML

<div>Level: <select id="level"></select></div>
<div id="main" class="cont"></div>
<p style="clear:both">Available Patterns:</p>
<div id="sols"></div>

CSS

.cont {
    float: left;
    display: inline-block;
    width: 90px;
    height: 90px;
    padding: 10px;
}
#main.cont {
    width: 150px;
    height: 150px;
    font-size: 25px;
}
.blk {
    float: left;
    text-align: center;
}

JavaScript

function random(n) {
    return Math.floor(Math.random() * (n || 0))
}

// core
var M = 3, N = 3, NUM0 = 0, NUM1 = ~((~1 >> M * N) << (M * N))
var num = 0
var sol = [ ]
var masks = [
    '1',
    '1/1/1',
    '01/11', '10/11', '11/10', '11/01',
    '10/11/01', '01/11/10',
    '10/10/11', '01/01/11', '11/10/10', '11/01/01',
    '111',
    '110/011', '011/110',
]
function parseMask(list) {
    var mask = 0
    list.forEach(function(s, i) {
        mask |= (parseInt(s, 2) << (M * N - s.length)) >> (M * i)
    })
    return mask
}
function applyFlip(num, mask, i, j) {
    return num ^ (mask >> (i * M + j))
}
function makeNewPuzzle(level) {
    num = [NUM0, NUM1][random(2)]
    sol = [ ]
    for (var i = 0; i < level; i ++) {
        var mst = masks[random(masks.length)],
            list = mst.split('/')
        var data = {
            mask: parseMask(list),
            width: list[0].length,
            height: list.length,
            i: random(N - list.length + 1),
            j: random(M - list[0].length + 1)
        }
        num = applyFlip(num, data.mask, data.i, data.j)
        sol.push(data)
    }
}

// ui
function testBit(num, i) {
    return num & (1 << (M * N - i - 1))
}
function updateView() {
    var main = $('#main').empty()
    for (var i = 0; i < M * N; i ++) {
        $('<div></div>').addClass('blk')
            .attr('index', i)
            .width(100/M+'%').height(100/N+'%')
            .text(testBit(num, i) ? 'X' : 'O')
            .appendTo(main)
    }
    var sols = $('#sols').empty()
    for (var i = 0; i < sol.length; i ++) {
        var data = sol[i],
            mask = $('<div></div>').addClass('cont').appendTo(sols)
        for (var j = 0; j < M * N; j ++) {
            $('<div></div>').addClass('blk')
                .width(100/M+'%').height(100/N+'%')
                .css('background', testBit(data.mask, j) ? 'red' : 'white')
                .appendTo(mask)
        }
    }
    sols.children().first().css('background', '#aaa')
    
   ...