JSFiddle - React, Tailwind, and code Playground

by BurpmanJunior

HTML

<button id="solve">Solve</button>

CSS

@import url(https://fonts.googleapis.com/css?family=Roboto:400,900);

*,
*:before,
*:after{
  box-sizing: border-box;
}

.sudoku-stage{
  border: 1px solid #666;
  width: 400px;
}
.sudoku-stage:after{
  content: '';
  clear: both;
  display: table;
}
.sudoku-stage[data-win="true"]{
  opacity: 0.5;
}
.sudoku-stage[data-win="false"]{
  opacity: 1;
}

.sudoku-subgrid{
  width: 33.333%;
  float: left;
  border: 1px solid #666;
}

.sudoku-slot-wrap{
  width: 33.333%;
  float: left;
  display: block;
  border: 1px solid #666;
  position: relative;
  padding-top: 33.333%;
}

.sudoku-slot-input{
  position: absolute;
  display: block;
  width: 100%;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  border: 0;
  text-align: center;
  font-size: 18px;
  font-family: 'Roboto', sans-serif;
  font-weight: 400;
}
.sudoku-slot-preset{
  font-weight: 900;
  background-color: #ddd;
}

JavaScript

console.clear();

/**
 * Initialize sudoku object and set up grid
 */
var sudoku = function(preset){
	// Build default
	this.defaultGrid = Array.apply(null, Array(9)).map(function(){
    return Array.apply(null, Array(9)).map(function(){
      return null;
    });
  });
  this.grid = this.defaultGrid;
  
  // Apply preset data
  if(preset){
  	if(Object.prototype.toString.call(preset) === '[object Array]'){
    	preset = this.arrayGridConversion(preset);
    }
  	this.grid = this.mergeGrid(preset);
  }
  
  return this;
}

sudoku.prototype.arrayGridConversion = function(data){
	var output = {};
  
	data.forEach(function(grid, i){
  	var tmpObj = {};
    
    grid.forEach(function(slot, n){
    	if(slot > 0 && slot < 10){
      	tmpObj[n] = slot;
      }
    });
    
    if(Object.keys(tmpObj).length > 0){
    	output[i] = tmpObj;
    }
  });
  
  return output;
}

/**
 * Merge preset data with default template
 */
sudoku.prototype.mergeGrid = function(grid){
	// Base
	var output = this.defaultGrid;
  
  // Loop sub grid data
  for(var subGrid in grid){
  	// Loop sub grid slot data
  	for(var slot in grid[subGrid]){
    	// Apply if valid
    	if(output[subGrid][slot] === null && grid[subGrid][slot] > 0 && grid[subGrid][slot] < 10){
      	output[subGrid][slot] = grid[subGrid][slot];
      }
    }
  }
  
  return output;
}


/**
 * Build grid DOM and return element for appendage
 */
sudoku.prototype.buildGridDOM = function(){
	var self = this;
  self.gridDOM_inputs = [];
  
  // Main stage
	var stage = document.createElement('div');
  stage.id = 'sudoku-stage';
  stage.className = 'sudoku-stage';
  
  // Sub grids
  self.grid.forEach(function(subGrid, subGrid_i){
  	var stage_subGrid = document.createElement('div');
    stage_subGrid.id = 'sudoku-subgrid-' + subGrid_i;
    stage_subGrid.className = 'sudoku-subgrid';
     
    // Slots
    subGrid.forEach(function(slot, slot_i){
    
    	// Slot wrap
    	var stage_slot_wrap = document.createElement('div');
     ...