Subscribe to Updates

    Get the latest creative news from FooBar about art, design and business.

    What's Hot

    Flutter Interview Questions for freshers

    June 25, 2023

    Flutter Interview Questions for Experienced

    June 25, 2023

    Top 15 Flutter Interview Questions and Answers 2023

    April 22, 2023
    Facebook Twitter Instagram
    Facebook Twitter Instagram Pinterest YouTube
    DeepCrazyWorld
    Subscribe
    • Home
    • FLUTTER
      • UI
        • Splash Screen
        • Card Design
        • Login Screen
      • APPS
    • ANDROID
      • ANDROID APP
      • GAME APP
    • SOURCE CODE
    • ANDROID STUDIO
    • PROJECT
      • Android Projects
      • College Projects
      • Project Ideas
      • PHP Projects
      • Python Projects
    • MCQ
      • AKTU MCQ
        • RPA MCQ
        • COA MCQ
        • HPC MCQ
        • SPM MCQ
        • Renewable Energy All MCQ
        • Data Compression MCQ
        • Data Structure MCQ
        • Digital Image Processing MCQ
        • Software Engineering MCQ
        • Machine Learning MCQ
        • Artificial Intelligence MCQ
      • D PHARMA MCQ
        • Pharmaceutics – I MCQ
        • Pharmacognosy MCQ
        • Pharmaceutical Chemistry MCQ
        • Biochemistry and Clinical Pathology MCQ
        • Human Anatomy and Physiology MCQ
        • Heath Education and Community Pharmacy MCQ
      • COLLECTION
        • WORDPRESS
          • SEO
          • TOP 10 WORDPRESS THEME
        • PRODUCTIVITY
        • Networking
        • Program
        • YOUTUBE
        • QUOTES
    • INTERVIEW QUESTIONS
    DeepCrazyWorld
    Home»Web Developer»Sudoku : How to Create a Sudoku Puzzle game with Html
    Web Developer

    Sudoku : How to Create a Sudoku Puzzle game with Html

    DeepikaBy DeepikaAugust 1, 2020Updated:April 17, 2023No Comments19 Mins Read
    Facebook Twitter LinkedIn WhatsApp Telegram
    Share
    Facebook Twitter LinkedIn Pinterest Telegram WhatsApp

    When We first started playing with writing a Sudoku game, I took the long way to create Sudoku templates. Using a recursive backtracking algorithm, I would slowly fill up the grid with random numbers – checking the validity of the puzzle at each step. If I hit a roadblock where the puzzle cannot be completed, the algorithm would backtrack until it could move forward, and then move forward again. how to make a sudoku game in javascript,
    how to make a sudoku puzzle in html

    There is a more elegant solution however: create a solved sudoku and then shuffle it.

    Table of Contents

    • Generate and Solved Sudoku
    • Sudoku Puzzle Game Source Code
    • index.html
    • Sudoku puzzle in html
    • style.css
    • script.js
    • YouTube Video
    • READ MORE

    Generate and Solved Sudoku

    1.Step : Creating the solved Sudoku is easy: just shift the row above to the left by 3 unless its vertical index is equally divisible by 3 (starting with index 0) in which case shift the row above by 4.

    1 2 3 4 5 6 7 8 9
    4 5 6 7 8 9 1 2 3
    7 8 9 1 2 3 4 5 6
    2 3 4 5 6 7 8 9 1
    5 6 7 8 9 1 2 3 4
    8 9 1 2 3 4 5 6 7
    3 4 5 6 7 8 9 1 2
    6 7 8 9 1 2 3 4 5
    9 1 2 3 4 5 6 7 8


    2.Step : Shuffle the rows and columns. Of course, to do so and ensure the Sudoku rules maintain integrity, you can only shuffle rows and columns of the same group: groups being 1-3, 4-6, and 7-9. Demonstrated below, the columns 1 and 3 are shuffled

    <img decoding=

    Sudoku Puzzle Game Source Code

    index.html

    <!DOCTYPE html>
    <html lang="en" >
    <head>
      <meta charset="UTF-8">
      <title>DeepCrazyWorld - Sudoku Puzzle Project</title>
      <meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
    <link rel="stylesheet" href="./style.css">
    
    </head>
    <body>
    
    
    <div id='sudoku-app'></div>
    
    <script type='text/javascript'>
      "use strict";!function(a){if("function"==typeof bootstrap)bootstrap("bem",a);else if("object"==typeof exports&&"object"==typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define(a);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeBem=a}else{if("undefined"==typeof window&&"undefined"==typeof self)throw new Error("This environment was not anticipated by bem. Please file a bug.");var b="undefined"!=typeof window?window:self,c=b.bem;b.bem=a(),b.bem.noConflict=function(){return b.bem=c,this}}}(function(){function a(a){"undefined"!=typeof a.modifier&&(c.modifier=a.modifier),"undefined"!=typeof a.element&&(c.element=a.element)}function b(a){if(!d.validate(a))return null;var b=a.block,e=a.element,f=a.modifiers,g=b,h=[];return!!e&&(g+=""+c.element+e),!!f&&Object.keys(f).forEach(function(a){var d=f[a],i="function"==typeof d?d(b,e,f):d;!!i&&h.push(""+g+c.modifier+a+" ")}),(g+" "+h.join("")).slice(0,-1)}var c={element:"__",modifier:"--"},d={messages:{block:"You must specify the name of block.",element:"Element name must be a string.",modifier:"Modifiers must be supplied in the `{name : bool || fn}` style."},blockName:function(a){return"undefined"!=typeof a&&"string"==typeof a&&a.length?!0:(console.warn(this.messages.block),!1)},element:function(a){return"undefined"!=typeof a&&"string"!=typeof a?(console.warn(this.messages.element),!1):!0},modifiers:function(a){return"undefined"==typeof a||"object"==typeof a&&"[object Object]"===toString.call(a)?!0:(console.warn(this.messages.modifier),!1)},validate:function(a){return this.blockName(a.block)&&this.element(a.element)&&this.modifiers(a.modifiers)}};return{setDelimiters:a,makeClassName:b}});
    </script>
    
    <!-- Include Babel to transform code in browser -->
    <script type='text/javascript'
            src='https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.25/browser-polyfill.min.js'>
    </script>
    <script type='text/javascript'
            src='https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.25/browser.min.js'>
    </script>
    
    <!-- worker, sudoku api -->
    <script type='text/babel' id='worker'>
      
      self.sudoku = null
      
      // Worker Setup
      self.addEventListener('message', (event) => {
        var options = { method: null }
        try {
          options = JSON.parse(event.data);
        } catch (e) {
          console.warn('event.data is misformed', event)
        }
      
        switch (options.method) {
      
          case 'generate':
            var { hints, limit } = options
            self.sudoku = new Sudoku(hints, limit).generate()
    
            self.postMessage({
              success: self.sudoku.success,
              board: self.sudoku.getBoard(),
              solution: self.sudoku.getSolution()
            });
            break;
      
          case 'validate':
            var { map, number, index } = options
            self.postMessage({
              result: sudoku.validate(map, number, index)
            });
            break;
      
        }
      }, false);
    
      // API
      class Sudoku {
        constructor(hints, limit) {
          this.hints = hints
          this.limit = limit || 10000
      
          this._logs = {
            raw: [],
            incidents: {
              limitExceeded: 0,
              notValid: 0,
              noNumbers: 0
            }
          }
      
          this.success = null
    
          this.numbers = () =>
            new Array(9)
              .join(" ")
              .split(" ")
              .map((num , i) => i + 1)
    
          /*
            Will be used in initial map. Each row will be
            consisted of randomly ordered numbers
          */
          this.randomRow = () => {
            var row = []
            var numbers = this.numbers()
            while (row.length < 9) {
              var index = Math.floor(Math.random() * numbers.length)
              row.push(numbers[index])
              numbers.splice(index, 1)
            }
    
            return row
          }
    
          /*
            This is the dummy placeholder for the
            final results. Will be overridden through the
            backtracking process, and at the and, this will
            be the real results.
          */
          this.result = new Array(9 * 9)
            .join(" ")
            .split(" ")
            .map(entry => null)
    
          /*
            Will be used as the nodeTree in the
            process of backtracking. Each cell has 9 alternative
            paths (randomly ordered).
          */
          this.map = new Array(9 * 9)
            .join(" ")
            .split(" ")
            .map(path => this.randomRow())
    
          /*
            Will be used as history in the backtracking
            process for checking if a candidate number is valid.
          */
          this.stack = []
    
          return this
        }
      
        toRows(arr) {
          var row = 0
          var asRows = new Array(9)
            .join(" ")
            .split(" ")
            .map(row => [])
      
          for (let [index, entry] of arr.entries()) {
            asRows[row].push(entry)
    
            if ( !((index + 1) % 9) ) {
              row += 1
            }
          }
    
          return asRows
        }
    
        no(path, index, msg) {
          var number = path[path.length - 1]
          this._logs.raw.push(`no: @${index} [${number}] ${msg} ${path} `)
        }
    
        yes(path, index) {
          this._logs.raw.push(`yes: ${index} ${path}`)
        }
      
        finalLog() {
          console.groupCollapsed('Raw Logs')
          console.groupCollapsed(this._logs.raw)
          console.groupEnd()
          console.groupEnd()
          console.groupCollapsed('Incidents')
          console.groupCollapsed(this._logs.incidents)
          console.groupEnd()
          console.groupEnd()
        }
    
        getBoard() {
          return this.toRows(this.substractCells())
        }
    
        getSolution() {
          return this.toRows(this.result)
        }
    
        substractCells() {
          var _getNonEmptyIndex = () => {
            var index = Math.floor(Math.random() * _result.length)
            return _result[index] ? index : _getNonEmptyIndex()
          }
    
          var _result = this.result.filter(() => true)
    
          while (
            _result.length - this.hints >
            _result.filter(n => !n).length
          ) {
            _result[_getNonEmptyIndex()] = ''
          }
    
          return _result
        }
      
        validate(map, number, index) {
          var rowIndex = Math.floor(index / 9)
          var colIndex = index % 9
    
          var row = map.slice(
            rowIndex * 9, 9 * (rowIndex + 1)
          )
    
          var col = map.filter((e, i) =>
            i % 9 === colIndex
          )
    
          var boxRow = Math.floor(rowIndex / 3)
          var boxCol = Math.floor(colIndex / 3)
    
          var box = map.filter((e, i) =>
            Math.floor(Math.floor(i / 9) / 3) === boxRow &&
            Math.floor((i % 9) / 3) === boxCol
          )
    
          return {
            row: {
              first: row.indexOf(number),
              last: row.lastIndexOf(number)
            },
            col: {
              first: col.indexOf(number),
              last: col.lastIndexOf(number)
            },
            box: {
              first: box.indexOf(number),
              last: box.lastIndexOf(number)
            }
          }
        }
    
        _validate(map, index) {
          if (!map[index].length) {
            return false
          }
    
          this.stack.splice(index, this.stack.length)
      
          var path = map[index]
          var number = path[path.length - 1]
      
          var didFoundNumber = this.validate(this.stack, number, index)
      
          return (
            didFoundNumber.col.first === -1 &&
            didFoundNumber.row.first === -1 &&
            didFoundNumber.box.first === -1
          )
        }
    
        _generate(map, index) {
          if (index === 9 * 9) {
            return true
          }
    
          if (--this.limit < 0) {
            this._logs.incidents.limitExceeded++
            this.no(map[index], index, 'limit exceeded')
            return false
          }
    
          var path = map[index]
    
          if (!path.length) {
            map[index] = this.numbers()
            map[index - 1].pop()
            this._logs.incidents.noNumbers++
            this.no(path, index, 'no numbers in it')
            return false
          }
    
          var currentNumber = path[path.length - 1]
    
          var isValid = this._validate(map, index)
          if (!isValid) {
            map[index].pop()
            map[index + 1] = this.numbers()
            this._logs.incidents.notValid++
            this.no(path, index, 'is not valid')
            return false
          } else {
            this.stack.push(currentNumber)
          }
    
          for (let number of path.entries()) {
            if (this._generate(map, index + 1)) {
              this.result[index] = currentNumber
              this.yes(path, index)
              return true
            }
          }
    
          return false
        }
    
        generate() {
          if (this._generate(this.map, 0)) {
            this.success = true
          }
    
          this.finalLog()
    
          return this
        }
    
      }
    </script>
    <!-- partial -->
      <script src='https://cdn.rawgit.com/MaxArt2501/object-observe/master/dist/object-observe-lite.min.js'></script><script  src="./script.js"></script>
    
    </body>
    </html>
    

    Sudoku puzzle in html

    style.css

    
    \**********************************/
    @font-face {
      src: url("http://enes.in/GillSansTr-LightNr.otf");
      font-family: Gill;
      font-weight: 100;
    }
    @font-face {
      src: url("http://enes.in/GillSansTr-Normal.otf");
      font-family: Gill;
      font-weight: 300;
    }
    @font-face {
      src: url("http://enes.in/GillSansTr-Bold.otf");
      font-family: Gill;
      font-weight: 600;
    }
    @font-face {
      src: url("http://enes.in/GillSansTr-ExtraBold.otf");
      font-family: Gill;
      font-weight: 700;
    }
    @font-face {
      src: url("http://enes.in/GillSansTr-UltraBold.otf");
      font-family: Gill;
      font-weight: 900;
    }
    html, body {
      width: 100%;
      height: 100%;
    }
    
    body {
      margin: 0;
      background: #f0f0f0;
    }
    
    @media (max-width: 260px) {
      .show-on-sm {
        display: none;
      }
    
      .show-on-md {
        display: none;
      }
    
      .show-on-lg {
        display: none;
      }
    
      .show-on-xs {
        display: block;
      }
    }
    @media (max-width: 420px) {
      .show-on-xs {
        display: none;
      }
    
      .show-on-md {
        display: none;
      }
    
      .show-on-lg {
        display: none;
      }
    
      .show-on-sm {
        display: block;
      }
    }
    @media (min-width: 421px) and (max-width: 615px) {
      .show-on-xs {
        display: none;
      }
    
      .show-on-sm {
        display: none;
      }
    
      .show-on-lg {
        display: none;
      }
    
      .show-on-md {
        display: block;
      }
    }
    @media (min-width: 615px) {
      .show-on-xs {
        display: none;
      }
    
      .show-on-sm {
        display: none;
      }
    
      .show-on-md {
        display: none;
      }
    
      .show-on-lg {
        display: block;
      }
    }
    @-webkit-keyframes progress {
      0% {
        box-shadow: none;
      }
      25% {
        box-shadow: 2px -2px 0 1px;
      }
      50% {
        box-shadow: 2px -2px 0 1px, 7px -2px 0 1px;
      }
      100% {
        box-shadow: 2px -2px 0 1px, 7px -2px 0 1px, 12px -2px 0 1px;
      }
    }
    @keyframes progress {
      0% {
        box-shadow: none;
      }
      25% {
        box-shadow: 2px -2px 0 1px;
      }
      50% {
        box-shadow: 2px -2px 0 1px, 7px -2px 0 1px;
      }
      100% {
        box-shadow: 2px -2px 0 1px, 7px -2px 0 1px, 12px -2px 0 1px;
      }
    }
    .fr {
      float: right;
    }
    
    .fl {
      float: left;
    }
    
    @media (max-width: 260px) {
      .button {
        padding: 0.25em 0.5em;
        font-size: 0.6em;
      }
      .button:not(:last-of-type) {
        margin-right: 0.15em;
      }
      .button--loading {
        padding-right: 1.5em;
      }
    }
    @media (min-width: 261px) and (max-width: 420px) {
      .button {
        padding: 0.25em 0.5em 0.15em;
        font-size: 0.75em;
      }
      .button:not(:last-of-type) {
        margin-right: 0.25em;
      }
      .button--loading {
        padding-right: 1.5em;
      }
    }
    @media (min-width: 421px) and (max-width: 615px) {
      .button {
        padding: 0.5em 0.75em 0.4em;
        font-size: 0.9em;
      }
      .button:not(:last-of-type) {
        margin-right: 0.5em;
      }
      .button--loading {
        padding-right: 1.5em;
      }
    }
    @media (min-width: 615px) {
      .button {
        padding: 0.75em 1em 0.6em;
        font-size: 1em;
      }
      .button:not(:last-of-type) {
        margin-right: 0.75em;
      }
      .button--loading {
        padding-right: 1.5em;
      }
    }
    .button {
      border: 1px solid;
      font-weight: normal;
      border-radius: 3px;
      background: none;
      box-shadow: none;
      -webkit-transition: all 0.2s;
      transition: all 0.2s;
    }
    .button--primary {
      color: #4242d7;
      font-weight: 600;
    }
    .button--primary:hover, .button--primary:focus, .button--primary:active {
      border-color: #4242d7;
      background: #4242d7;
    }
    .button--primary:focus {
      box-shadow: 0 0 5px #4242d7;
    }
    .button--secondary {
      color: #d74242;
    }
    .button--secondary:hover, .button--secondary:focus, .button--secondary:active {
      border-color: #d74242;
      background: #d74242;
    }
    .button--secondary:focus {
      box-shadow: 0 0 5px #d74242;
    }
    .button--tertiary {
      color: #fff;
      border-color: #2ECC40;
      background: #2ECC40;
    }
    .button--neutral {
      color: #333;
    }
    .button--neutral:hover, .button--neutral:focus, .button--neutral:active {
      border-color: #333;
      background: #333;
    }
    .button--neutral:focus {
      box-shadow: 0 0 5px #333;
    }
    .button--compound {
      border-radius: 0;
      border-right: none;
    }
    .button--compound-first {
      border-bottom-left-radius: 3px;
      border-top-left-radius: 3px;
    }
    .button--compound-last {
      border-bottom-right-radius: 3px;
      border-top-right-radius: 3px;
      border-right: 1px solid;
    }
    .button--muted {
      pointer-events: none;
    }
    .button--disabled {
      border-color: #bbb;
      color: #bbb;
      pointer-events: none;
    }
    .button--loading-text::after {
      display: inline-block;
      width: 1px;
      height: 1px;
      content: '';
      box-shadow: 2px -2px 1px 0;
      -webkit-animation: progress 1s infinite;
              animation: progress 1s infinite;
    }
    .button:hover, .button:focus, .button:active {
      color: #fff;
    }
    .button:focus {
      outline: none;
    }
    .button:active {
      box-shadow: inset 0 -2px 10px rgba(0, 0, 0, 0.4);
    }
    
    .message {
      font-size: .9em;
      padding: 2em;
      margin: 0;
      border-radius: 3px;
      color: rgba(0, 0, 0, 0.75);
    }
    .message--busy {
      background: rgba(0, 0, 255, 0.1);
    }
    .message--fail {
      background: rgba(255, 0, 0, 0.1);
    }
    
    @media (max-width: 260px) {
      .sudoku {
        margin: 0 auto;
        padding-top: 0.5em;
        padding-bottom: 0.5em;
      }
      .sudoku__header {
        padding-bottom: 0.6em;
      }
      .sudoku__title {
        font-size: 1em;
      }
      .sudoku__table {
        font-size: 0.9em;
        border-top: 2px solid #444;
        border-left: 2px solid #444;
        border-collapse: collapse;
      }
      .sudoku__table-row {
        border-bottom: 1px solid #444;
        border-right: 2px solid #444;
      }
      .sudoku__table-row--separator {
        border-bottom: 2px solid #444;
      }
      .sudoku__table-cell {
        width: 16px;
        height: 16px;
        border-right: 1px solid #444;
      }
      .sudoku__table-cell--separator {
        border-right: 2px solid #444;
      }
    
      .sudoku {
        max-width: calc(260px / 1.5);
        min-width: calc(260px / 2);
      }
    }
    @media (min-width: 261px) and (max-width: 420px) {
      .sudoku {
        margin: 0 auto;
        padding-top: 1em;
        padding-bottom: 1em;
      }
      .sudoku__header {
        padding-bottom: 0.9em;
      }
      .sudoku__title {
        font-size: 1.2em;
      }
      .sudoku__table {
        font-size: 1.2em;
        border-top: 3px solid #444;
        border-left: 3px solid #444;
        border-collapse: collapse;
      }
      .sudoku__table-row {
        border-bottom: 1px solid #444;
        border-right: 3px solid #444;
      }
      .sudoku__table-row--separator {
        border-bottom: 3px solid #444;
      }
      .sudoku__table-cell {
        width: 32px;
        height: 32px;
        border-right: 1px solid #444;
      }
      .sudoku__table-cell--separator {
        border-right: 3px solid #444;
      }
    
      .sudoku {
        width: 260px;
      }
    }
    @media (min-width: 421px) and (max-width: 615px) {
      .sudoku {
        margin: 0 auto;
        padding-top: 2em;
        padding-bottom: 2em;
      }
      .sudoku__header {
        padding-bottom: 1.3em;
      }
      .sudoku__title {
        font-size: 1.5em;
      }
      .sudoku__table {
        font-size: 1.5em;
        border-top: 4px solid #444;
        border-left: 4px solid #444;
        border-collapse: collapse;
      }
      .sudoku__table-row {
        border-bottom: 1px solid #444;
        border-right: 4px solid #444;
      }
      .sudoku__table-row--separator {
        border-bottom: 4px solid #444;
      }
      .sudoku__table-cell {
        width: 48px;
        height: 48px;
        border-right: 1px solid #444;
      }
      .sudoku__table-cell--separator {
        border-right: 4px solid #444;
      }
    
      .sudoku {
        width: 420px;
      }
    }
    @media (min-width: 615px) {
      .sudoku {
        margin: 0 auto;
        padding-top: 3em;
        padding-bottom: 3em;
      }
      .sudoku__header {
        padding-bottom: 1.618em;
      }
      .sudoku__title {
        font-size: 2em;
      }
      .sudoku__table {
        font-size: 1.75em;
        border-top: 6px solid #444;
        border-left: 6px solid #444;
        border-collapse: collapse;
      }
      .sudoku__table-row {
        border-bottom: 2px solid #444;
        border-right: 6px solid #444;
      }
      .sudoku__table-row--separator {
        border-bottom: 6px solid #444;
      }
      .sudoku__table-cell {
        width: 64px;
        height: 64px;
        border-right: 2px solid #444;
      }
      .sudoku__table-cell--separator {
        border-right: 6px solid #444;
      }
    
      .sudoku {
        width: 615px;
      }
    }
    .sudoku {
      color: #444;
    }
    .sudoku__header {
      font-family: Gill, sans-serif;
    }
    .sudoku__title {
      font-weight: 600;
    }
    .sudoku__description {
      max-width: 640px;
      line-height: 1.4;
      font-weight: 100;
    }
    .sudoku__table {
      background: #fff;
    }
    .sudoku__table-cell {
      overflow: hidden;
      text-align: center;
      -webkit-transition: all .25s;
      transition: all .25s;
    }
    .sudoku__table-cell--editable {
      color: #2020df;
    }
    .sudoku__table-cell--editable:focus {
      background: rgba(0, 0, 255, 0.1);
      outline: none;
    }
    .sudoku__table-cell--error {
      color: red;
      background: #fdd;
    }
    .sudoku__table-cell--editable-error {
      text-shadow: 0 0 15px;
    }
    .sudoku__table-cell--editable-error:focus {
      color: #eee;
      background: #f45;
    }

    script.js

    // Utility
    var utils = (() => {
      function dom(selector) {
        if (selector[0] === '#') {
          return document.getElementById(selector.slice(1));
        }
        return document.querySelectorAll(selector);
      }
    
      function copyJSON(obj) {
        return JSON.parse(JSON.stringify(obj));
      }
    
      function isTouchDevice() {
        return navigator.userAgent.
        match(/(iPhone|iPod|iPad|Android|BlackBerry)/);
      }
    
      function getWorkerURLFromElement(selector) {
        var element = dom(selector);
        var content = babel.transform(element.innerText).code;
        var blob = new Blob([content], { type: 'text/javascript' });
        return URL.createObjectURL(blob);
      }
    
        var cursorManager = function () {
        var cursorManager = {};
    
        var voidNodeTags = [
        'AREA', 'BASE', 'BR', 'COL', 'EMBED',
        'HR', 'IMG', 'INPUT', 'KEYGEN', 'LINK',
        'MENUITEM', 'META', 'PARAM', 'SOURCE',
        'TRACK', 'WBR', 'BASEFONT', 'BGSOUND',
        'FRAME', 'ISINDEX'];
    
    
        Array.prototype.contains = function (obj) {
          var i = this.length;
          while (i--) {
            if (this[i] === obj) {
              return true;
            }
          }
          return false;
        };
    
        function canContainText(node) {
          if (node.nodeType == 1) {
            return !voidNodeTags.contains(node.nodeName);
          } else {
            return false;
          }
        };
    
        function getLastChildElement(el) {
          var lc = el.lastChild;
          while (lc && lc.nodeType != 1) {
            if (lc.previousSibling)
            lc = lc.previousSibling;else
    
            break;
          }
          return lc;
        }
        cursorManager.setEndOfContenteditable = function (contentEditableElement) {
    
          while (getLastChildElement(contentEditableElement) &&
          canContainText(getLastChildElement(contentEditableElement))) {
            contentEditableElement = getLastChildElement(contentEditableElement);
          }
    
          var range, selection;
          if (document.createRange) {
            range = document.createRange();
            range.selectNodeContents(contentEditableElement);
            range.collapse(false);
            selection = window.getSelection();
            selection.removeAllRanges();
            selection.addRange(range);
          } else
          if (document.selection)
          {
            range = document.body.createTextRange();
            range.moveToElementText(contentEditableElement);
            range.collapse(false);
            range.select();
          }
        };
    
        return cursorManager;
      }();
    
      return {
        copyJSON, cursorManager, dom,
        getWorkerURLFromElement, isTouchDevice };
    
    })();
    
    
    // API Adapter
    class SudokuAdapter {
      constructor(url) {
        this.worker = new Worker(url);
        return this;
      }
    
      _postMessage(options) {
        this.worker.postMessage(JSON.stringify(options));
        return new Promise((resolve, reject) => {
          this.worker.onmessage = event => {
            resolve(event.data);
          };
        });
      }
    
      generate(options) {
        options = Object.assign(
        {}, options, { method: 'generate' });
    
        return this._postMessage(options);
      }
    
      validate(options) {
        options = Object.assign(
        {}, options, { method: 'validate' });
    
        return this._postMessage(options);
      }}
    
    
    
    // Client Side Settings
    const SUDOKU_APP_CONFIG = {
      HINTS: 34,
      TRY_LIMIT: 100000,
      WORKER_URL: utils.getWorkerURLFromElement('#worker'),
      DOM_TARGET: utils.dom('#sudoku-app') };
    
    
    
    // Client Side
    var SudokuApp = (config => {
      const {
        HINTS, TRY_LIMIT,
        WORKER_URL, DOM_TARGET } =
      config;
    
      var sudokuAdapter = new SudokuAdapter(WORKER_URL);
    
      var state = {
        success: null,
        board: null,
        solution: null,
        solved: null,
        errors: [] };
    
      Object.observe(state, render);
    
      var history = [state];
      var historyStash = [];
    
    
      // Event listeners
      var onClickGenerate = initialize;
    
      var onClickSolve = function () {
        setState({
          board: state.solution,
          solved: true,
          errors: [] });
    
      };
    
      var onKeyUpCell = function (event) {
        var key = event.keyCode;
        if ( // a
        key === 36 || // r
        key === 37 || // r
        key === 38 || // o
        key === 39 || // w
        key === 9 || // tab
        // mod key flags are always false in keyup event
        // keyIdentifier doesn't seem to be implemented
        // in all browsers
        key === 17 || // Control
        key === 16 || // Shift
        key === 91 || // Meta
        key === 19 || // Alt
        event.keyIdentifier === 'Control' ||
        event.keyIdentifier === 'Shift' ||
        event.keyIdentifier === 'Meta' ||
        event.keyIdentifier === 'Alt')
        return;
    
        var cell = event.target;
        var value = cell.innerText;
    
        if (value.length > 4) {
          cell.innerText = value.slice(0, 4);
          return false;
        }
    
        var cellIndex = cell.getAttribute('data-cell-index');
        cellIndex = parseInt(cellIndex, 10);
        var rowIndex = Math.floor(cellIndex / 9);
        var cellIndexInRow = cellIndex - rowIndex * 9;
    
        var board = Object.assign([], state.board);
        board[rowIndex].splice(cellIndexInRow, 1, value);
    
        validate(board).then(errors => {
          historyStash = [];
          history.push({});
          var solved = null;
          if (errors.indexOf(true) === -1) {
            solved = true;
            board.forEach(row => {
              row.forEach(value => {
                if (!value || !parseInt(value, 10) || value.length > 1) {
                  solved = false;
                }
              });
            });
          }
          if (solved) {
            board = Object.assign([], board).map(row => row.map(n => +n));
          }
          setState({ board, errors, solved }, newState => {
            history[history.length - 1] = newState;
            restoreCaretPosition(cellIndex);
          });
        });
      };
    
      function keyDown(event) {
        var keys = {
          ctrlOrCmd: event.ctrlKey || event.metaKey,
          shift: event.shiftKey,
          z: event.keyCode === 90 };
    
    
        if (keys.ctrlOrCmd && keys.z) {
          if (keys.shift && historyStash.length) {
            redo();
          } else if (!keys.shift && history.length > 1) {
            undo();
          }
        }
      }
    
      function undo() {
        historyStash.push(history.pop());
        setState(utils.copyJSON(history[history.length - 1]));
      }
    
      function redo() {
        history.push(historyStash.pop());
        setState(utils.copyJSON(history[history.length - 1]));
      }
    
    
      function initialize() {
        unbindEvents();
        render();
        getSudoku().then(sudoku => {
          setState({
            success: sudoku.success,
            board: sudoku.board,
            solution: sudoku.solution,
            errors: [],
            solved: false },
          newState => {
            history = [newState];
            historyStash = [];
          });
        });
      }
    
      function setState(newState, callback) {
        requestAnimationFrame(() => {
          Object.assign(state, newState);
          if (typeof callback === 'function') {
            var param = utils.copyJSON(state);
            requestAnimationFrame(callback.bind(null, param));
          }
        });
      }
    
      function bindEvents() {
        var generateButton = utils.dom('#generate-button');
        var solveButton = utils.dom('#solve-button');
        var undoButton = utils.dom('#undo-button');
        var redoButton = utils.dom('#redo-button');
        generateButton &&
        generateButton.
        addEventListener('click', onClickGenerate);
        solveButton &&
        solveButton.
        addEventListener('click', onClickSolve);
        undoButton &&
        undoButton.
        addEventListener('click', undo);
        redoButton &&
        redoButton.
        addEventListener('click', redo);
    
        var cells = utils.dom('.sudoku__table-cell');
        [].forEach.call(cells, cell => {
          cell.addEventListener('keyup', onKeyUpCell);
        });
    
        window.addEventListener('keydown', keyDown);
      }
    
      function unbindEvents() {
        var generateButton = utils.dom('#generate-button');
        var solveButton = utils.dom('#solve-button');
        var undoButton = utils.dom('#undo-button');
        var redoButton = utils.dom('#redo-button');
        generateButton &&
        generateButton.
        removeEventListener('click', onClickGenerate);
        solveButton &&
        solveButton.
        removeEventListener('click', onClickSolve);
        undoButton &&
        undoButton.
        removeEventListener('click', undo);
        redoButton &&
        redoButton.
        removeEventListener('click', redo);
    
        var cells = utils.dom('.sudoku__table-cell');
        [].forEach.call(cells, cell => {
          cell.removeEventListener('keyup', onKeyUpCell);
        });
    
        window.removeEventListener('keydown', keyDown);
      }
    
      function restoreCaretPosition(cellIndex) {
        utils.cursorManager.setEndOfContenteditable(
        utils.dom(`[data-cell-index="${cellIndex}"]`)[0]);
    
      }
    
      function getSudoku() {
        return sudokuAdapter.generate({
          hints: HINTS,
          limit: TRY_LIMIT });
    
      }
    
      function validate(board) {
        var map = board.reduce((memo, row) => {
          for (let num of row) {
            memo.push(num);
          }
          return memo;
        }, []).map(num => parseInt(num, 10));
    
        var validations = [];
    
        // Will validate one by one
        for (let [index, number] of map.entries()) {
          if (!number) {
            validations.push(
            new Promise(res => {
              res({ result: { box: -1, col: -1, row: -1 } });
            }));
    
          } else {
            let all = Promise.all(validations);
            validations.push(all.then(() => {
              return sudokuAdapter.validate({ map, number, index });
            }));
          }
        }
    
        return Promise.all(validations).
        then(values => {
          var errors = [];
          for (let [index, validation] of values.entries()) {
            let { box, col, row } = validation.result;
            let errorInBox = box.first !== box.last;
            let errorInCol = col.first !== col.last;
            let errorInRow = row.first !== row.last;
    
            let indexOfRow = Math.floor(index / 9);
            let indexInRow = index - indexOfRow * 9;
    
            errors[index] = errorInRow || errorInCol || errorInBox;
          }
    
          return errors;
        });
      }
    
      function render() {
        unbindEvents();
    
        DOM_TARGET.innerHTML = `
          <div class='sudoku'>
            ${headerComponent()}
            ${contentComponent()}
          </div>
        `;
    
        bindEvents();
      }
    
      function buttonComponent(props) {
        var { id, text, mods, classes } = props;
    
        var blockName = 'button';
        var modifiers = {};
        var modType = toString.call(mods);
        if (modType === '[object String]') {
          modifiers[mods] = true;
    
        } else if (modType === '[object Array]') {
          for (let modName of mods) {
            modifiers[modName] = true;
          }
        }
    
        var blockClasses = bem.makeClassName({
          block: blockName,
          modifiers: modifiers });
    
    
        var buttonTextClass = `${blockName}-text`;
        if (Object.keys(modifiers).length) {
          buttonTextClass +=
          Object.keys(modifiers).reduce((memo, curr) => {
            return memo + ` ${blockName}--${curr}-text`;
          }, '');
    
        }
    
        var lgText = typeof text === 'string' ?
        text : text[0];
        var mdText = typeof text === 'string' ?
        text : text[1];
        var smText = typeof text === 'string' ?
        text : text[2];
    
        return `
          <button
            id='${id}'
            class='${blockClasses} ${classes || ""}'>
            <span class='show-on-sm ${buttonTextClass}'>
              ${smText}
            </span>
            <span class='show-on-md ${buttonTextClass}'>
              ${mdText}
            </span>
            <span class='show-on-lg ${buttonTextClass}'>
              ${lgText}
            </span>
          </button>
        `;
      }
    
      function messageComponent(options) {
        var { state, content } = options;
    
        var messageClass = bem.makeClassName({
          block: 'message',
          modifiers: state ? {
            [state]: true } :
          {} });
    
    
        return `
          <p class='${messageClass}'>
            ${content}
          </p>
        `;
      }
    
      function descriptionComponent(options) {
        var { className, infoLevel } = options;
    
        var technical = `
          In this demo,
          <a href='https://en.wikipedia.org/wiki/Backtracking'>
            backtracking algorithm
          </a> is used for <em>making</em>
          the sudoku project.`;
    
        var description = `
          Difficulty and solvability is
          totally random as I randomly left a certain number of hints
          from a full-filled board.
        `;
    
        if (infoLevel === 'full') {
          return `
            <p class='${className || ''}'>
              ${technical} ${description}
            </p>
          `;
    
        } else if (infoLevel === 'mini') {
          return `
            <p class='${className || ''}'>
              ${description}
            </p>
          `;
        }
      }
    
      function restoreScrollPosComponent() {
        return `<div style='height: 540px'></div>`;
      }
    
      function headerComponent() {
        return `
          <div class='sudoku__header'>
    
            <h1 class='sudoku__title'>
    
              <span class='show-on-sm'>
                Sudoku
              </span>
    
              <span class='show-on-md'>
                Sudoku Puzzle
              </span>
    
              <span class='show-on-lg'>
                Sudoku Puzzle Project
              </span>
    
            </h1>
    
            ${descriptionComponent({
          infoLevel: 'mini',
          className: 'sudoku__description show-on-md' })
        }
    
            ${descriptionComponent({
          infoLevel: 'full',
          className: 'sudoku__description show-on-lg' })
        }
    
            ${
        state.success ? `
        
                  ${buttonComponent({
          id: 'generate-button',
          text: ['New Board', 'New Board', 'New'],
          mods: 'primary' })
        }
        
                  ${state.solved ?
        buttonComponent({
          id: 'solve-button',
          text: 'Solved',
          mods: ['tertiary', 'muted'] }) :
    
        buttonComponent({
          id: 'solve-button',
          text: 'Solve',
          mods: 'secondary' })
    
        }
    
                ` :
    
        `
        
                  ${buttonComponent({
          id: 'generate-button',
          text: ['Generating', '', ''],
          mods: ['disabled', 'loading'] })
        }
        
                  ${buttonComponent({
          id: 'solve-button',
          text: 'Solve',
          mods: 'disabled' })
        }
                `
    
        }
    
            ${utils.isTouchDevice() ? `
    
              ${buttonComponent({
          id: 'redo-button',
          text: ['&raquo;', '&raquo;', '&gt;', '&gt;'],
          classes: 'fr',
          mods: [
          'neutral',
          'compound',
          'compound-last',
          `${!historyStash.length ?
          'disabled' :
          ''
          }`] })
    
        }
              ${buttonComponent({
          id: 'undo-button',
          text: ['&laquo;', '&laquo;', '&lt;', '&lt;'],
          classes: 'fr',
          mods: [
          'neutral',
          'compound',
          'compound-first',
          `${history.length > 1 ?
          '' :
          'disabled'
          }`] })
    
        }
    
          ` : ''}
    
          </div>
        `;
      }
    
      function contentComponent() {
        var _isSeparator = (index) =>
        !!index && !((index + 1) % 3);
    
        var resultReady = !!state.board;
        var fail = resultReady && !state.success;
    
        if (!resultReady) {
          return `
            ${messageComponent({
            state: 'busy',
            content: `Generating new board...` })
          }
            ${restoreScrollPosComponent()}
          `;
        }
    
        if (fail) {
          return `
            ${messageComponent({
            state: 'fail',
            content: `Something went wrong with this board, try generating another one.` })
          }
            ${restoreScrollPosComponent()}
          `;
        }
    
        var rows = state.board;
    
        return `
          <table class='sudoku__table'>
    
            ${rows.map((row, index) => {
          let className = bem.makeClassName({
            block: 'sudoku',
            element: 'table-row',
            modifiers: {
              separator: _isSeparator(index) } });
    
    
    
          return (
            `<tr class='${className}'>
    
                  ${row.map((num, _index) => {
              let cellIndex = index * 9 + _index;
              let separator = _isSeparator(_index);
              let editable = typeof num !== 'number';
              let error = state.errors[cellIndex];
              let className = bem.makeClassName({
                block: 'sudoku',
                element: 'table-cell',
                modifiers: {
                  separator,
                  editable,
                  error,
                  'editable-error': editable && error } });
    
    
    
              return (
                `\n\t
                      <td class='${className}'
                          data-cell-index='${cellIndex}'
                          ${editable ? 'contenteditable' : ''}>
                            ${num}
                      </td>`);
    
            }).join('')}
    
                \n</tr>\n`);
    
    
        }).join('')}
    
          </table>
        `;
      }
    
      return { initialize };
    
    })(SUDOKU_APP_CONFIG).initialize();

    YouTube Video

    And this can be continued for as many iterations as one likes, shuffling random rows and columns from a random group, resulting in a pseudo-random puzzle. I am still waiting for the day when I solve a puzzle and the result is the first puzzle above: not sure I would even notice until it is close to being solved.

    READ MORE

    Don’t forget to share this post!

    Share this…
    • Facebook
    • Pinterest
    • Twitter
    • Linkedin
    • Whatsapp
    • Gmail
    Post Views: 780
    create a sudoku game in html create a sudoku game in html css create a sudoku game in html css and js create a sudoku in excel how to create a sudoku puzzle how to make a fast sudoku talent talk how to make a sudoku app how to make a sudoku board how to make a sudoku book how to make a sudoku game how to make a sudoku game in css how to make a sudoku game in javascript how to make a sudoku grid in excel how to make a sudoku grid in word how to make a sudoku in html how to make a sudoku puzzle how to make a sudoku puzzle in excel how to make a sudoku puzzle in html how to make a sudoku puzzle in html create a sudoku puzzle how to make a sudoku puzzle in python how to make a sudoku puzzle on word how to make a sudoku solver how to make a sudoku solver in c++ how to make a sudoku solver in excel how to make a sudoku solver in js How to Make Sudoku Puzzle Game in Html CSS and JS make sudoku Related Tags: how to make a sudoku game sudoku
    Share. Facebook Twitter LinkedIn WhatsApp Telegram
    Previous ArticleLove Shayari in Hindi – Amazing Collection of Love Shayaris
    Next Article Sudoku : How to Make a Sudoku puzzle Game in html
    Deepika
    • Website
    • Facebook
    • Twitter
    • Pinterest
    • Instagram
    • LinkedIn

    Hey, I'm Deepika a professional blogger and Experienced in Android Developer,Flutter Developer, PHP Web Developer. Technically sound Post graduate pursuing M.Tech in Computer Science and Engineering. I Love to gain every type of knowledge that's why i have done many courses in different fields like engineering and technology. Skilled in Java, HTML, CSS,Bootstrap,j query PHP, Python, SQL, C, C++,Firebase,MySQL,SQLite,JavaScript. Also I have learned Networking.

    Related Posts

    Top 20 Amazing Websites जिनके बारे में आपको जानना चाहिए 2023

    March 1, 2022

    Top 5 Beginner’s Guide: How To Learn Web Design At Home 2023

    January 21, 2022

    Model View Controller Pattern – MVC Architecture & Frameworks(updated)

    December 3, 2021

    Unable to load class ‘javax.xml.bind.JAXBException’

    October 6, 2021

    Leave A Reply Cancel Reply

    Our Picks
    • Facebook
    • Twitter
    • Pinterest
    • Instagram
    • YouTube
    • Vimeo
    Don't Miss
    FLUTTER

    Flutter Interview Questions for freshers

    By DeepikaJune 25, 202303 Mins Read

    Certainly! Here’s a Flutter interview question along with its answer suitable for a fresher: Question:…

    Share this...
    • Facebook
    • Pinterest
    • Twitter
    • Linkedin
    • Whatsapp
    • Gmail

    Flutter Interview Questions for Experienced

    June 25, 2023

    Top 15 Flutter Interview Questions and Answers 2023

    April 22, 2023

    The Best Flutter Stepper Widget : Build Multi-Step Forms

    April 22, 2023
    Archives

    Subscribe to Updates

    Get the latest creative news from SmartMag about art & design.

    About Us
    About Us

    Hey, I'm Deepika a professional blogger and Experienced in Mobile App Developer ( Android and Flutter ) Technically sound Post graduated M.Tech in Computer Science and Engineering.
    I Love to gain every type of knowledge that's why i have done many courses in different fields like engineering and technology.

    Recent Posts
    • Flutter Interview Questions for freshers
    • Flutter Interview Questions for Experienced
    • Top 15 Flutter Interview Questions and Answers 2023
    • The Best Flutter Stepper Widget : Build Multi-Step Forms
    • Flutter ListView – A Guide to Creating Dynamic Lists with flutter
    • Top 10 Flutter Projects with source code For Startups
    • How to use chatGPT for UI/UX design with examples in 2023
    • Top 30 Flutter Interview Questions in 2023

    Flutter Interview Questions for freshers

    June 25, 2023

    Flutter Interview Questions for Experienced

    June 25, 2023

    Top 15 Flutter Interview Questions and Answers 2023

    April 22, 2023

    The Best Flutter Stepper Widget : Build Multi-Step Forms

    April 22, 2023
    Facebook Twitter Instagram Pinterest
    • Home
    • Contact Us
    • Disclaimer
    • Privacy Policy
    © 2023 DeepCrazyWorld. Designed by DeepCrazyWorld.

    Type above and press Enter to search. Press Esc to cancel.