// ==UserScript== // @name UsDoku solver // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description Solves UsDoku sudokus // @author scar17off // @match https://www.usdoku.com/* // @icon https://www.google.com/s2/favicons?domain=www.usdoku.com // @grant none // ==/UserScript== (()=>{"use strict";class t{constructor(){this.grid=Array(9).fill().map((()=>Array(9).fill(0))),this.solution=null}loadGrid(t){this.grid=t.map((t=>[...t])),this.solution=null}isValid(t,e,i,n){for(let i=0;i<9;i++)if(t[e][i]===n)return!1;for(let e=0;e<9;e++)if(t[e][i]===n)return!1;const o=3*Math.floor(e/3),s=3*Math.floor(i/3);for(let e=o;e<o+3;e++)for(let i=s;i<s+3;i++)if(t[e][i]===n)return!1;return!0}findEmptyCell(t){for(let e=0;e<9;e++)for(let i=0;i<9;i++)if(0===t[e][i])return[e,i];return null}getPossibleNumbers(t,e,i){const n=[];for(let o=1;o<=9;o++)this.isValid(t,e,i,o)&&n.push(o);return n}solve(){const t=this.grid.map((t=>[...t]));return!!this._solveGrid(t)&&(this.solution=t,!0)}_solveGrid(t){const e=this.findEmptyCell(t);if(!e)return!0;const[i,n]=e,o=this.getPossibleNumbers(t,i,n);for(const e of o){if(t[i][n]=e,this._solveGrid(t))return!0;t[i][n]=0}return!1}getNextMove(){if(this.solution||this.solve(),!this.solution)return null;for(let t=0;t<9;t++)for(let e=0;e<9;e++)if(0===this.grid[t][e])return{row:t,col:e,number:this.solution[t][e]};return null}isValidGrid(){for(let t=0;t<9;t++)for(let e=0;e<9;e++){const i=this.grid[t][e];if(0!==i){this.grid[t][e]=0;const n=this.isValid(this.grid,t,e,i);if(this.grid[t][e]=i,!n)return!1}}return!0}isComplete(){return!this.findEmptyCell(this.grid)}getCellDifficulty(t,e){if(0!==this.grid[t][e])return 1/0;const i=this.getPossibleNumbers(this.grid,t,e);if(0===i.length)return 1/0;let n=10*i.length;const o=new Set;for(let i=0;i<9;i++)i!==e&&0===this.grid[t][i]&&this.getPossibleNumbers(this.grid,t,i).forEach((t=>o.add(t)));i.some((t=>!o.has(t)))&&(n-=5);const s=new Set;for(let i=0;i<9;i++)i!==t&&0===this.grid[i][e]&&this.getPossibleNumbers(this.grid,i,e).forEach((t=>s.add(t)));i.some((t=>!s.has(t)))&&(n-=5);const r=3*Math.floor(t/3),l=3*Math.floor(e/3),d=new Set;for(let i=r;i<r+3;i++)for(let n=l;n<l+3;n++)i===t&&n===e||0!==this.grid[i][n]||this.getPossibleNumbers(this.grid,i,n).forEach((t=>d.add(t)));return i.some((t=>!d.has(t)))&&(n-=5),n}getLegitMove(){if(this.solution||this.solve(),!this.solution)return null;let t=null,e=1/0;for(let i=0;i<9;i++)for(let n=0;n<9;n++)if(0===this.grid[i][n]){const o=this.getCellDifficulty(i,n);o<e&&(e=o,t={row:i,col:n,number:this.solution[i][n],difficulty:o})}return t}getRandomMove(){if(this.solution||this.solve(),!this.solution)return null;const t=[];for(let e=0;e<9;e++)for(let i=0;i<9;i++)0===this.grid[e][i]&&t.push({row:e,col:i});if(0===t.length)return null;const e=Math.floor(Math.random()*t.length),{row:i,col:n}=t[e];return{row:i,col:n,number:this.solution[i][n],difficulty:0}}}function e(t){const e=Array(9).fill().map((()=>Array(9).fill(0))),i=[],n=Array.from(t.children).filter((t=>"52"===t.getAttribute("size")));return n.forEach(((t,n)=>{const o=Math.floor(n/9),s=n%9,r=t.querySelector('div[size="52"]');r&&r.textContent.trim()&&(r.classList.contains("css-1skby7h")?i.push(n):r.classList.contains("css-1im429o")&&(e[o][s]=parseInt(r.textContent)))})),{grid:e,incorrectCells:i,cells:n}}async function i(){const i=function(){const t=document.querySelectorAll("div[size]");let e=0,i=null;return t.forEach((t=>{const n=parseInt(t.getAttribute("size"));n>e&&(e=n,i=t)})),i}();if(!i)return void console.error("Could not find Sudoku grid");const{grid:n,incorrectCells:o,cells:s}=e(i),r=new t;if(r.loadGrid(n),!r.isValidGrid()){console.log("Invalid grid detected, removing incorrect numbers..."),await async function(t,e){for(const i of e)t[i].click(),await new Promise((t=>setTimeout(t,50))),document.dispatchEvent(new KeyboardEvent("keydown",{key:"Backspace",keyCode:8,which:8,bubbles:!0})),await new Promise((t=>setTimeout(t,100)))}(s,o);const{grid:t}=e(i);r.loadGrid(t)}for(;!r.isComplete();){let t;if(t=window.isLegitMode?r.getLegitMove():window.isRandomMode?r.getRandomMove():r.getNextMove(),!t)return void console.error("No solution exists");const e=s[9*t.row+t.col],i=e.querySelector(".css-1im429o");if(i){r.grid[t.row][t.col]=parseInt(i.textContent);continue}e.click(),await new Promise((t=>setTimeout(t,50))),document.dispatchEvent(new KeyboardEvent("keydown",{key:t.number.toString(),keyCode:48+t.number,which:48+t.number,bubbles:!0})),r.grid[t.row][t.col]=t.number;const n=window.isLegitMode?1e4+Math.min(t.difficulty,50)/50*5e3:window.isRandomMode?900*Math.random()+100:100;await new Promise((t=>setTimeout(t,n)))}}function n(){const t=document.querySelectorAll('div[size="478"]'),e=Array.from(t).find((t=>4===t.children.length));if(e){const t=function(){const t=document.createElement("div");t.setAttribute("size","478"),t.className="css-2bpbil";const e=document.createElement("div");e.setAttribute("size","478"),e.className="css-o90g4c";const n=document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("width","100%"),n.setAttribute("height","100%"),n.setAttribute("viewBox","0 0 33 32"),n.setAttribute("version","1.1"),n.innerHTML='\n <title>Solve</title>\n <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">\n <g transform="translate(-34.000000, -500.000000)">\n <g transform="translate(11.000000, 500.000000)">\n <g transform="translate(23.400000, 0.000000)">\n <polygon points="0 0 31.2 0 31.2 31.2 0 31.2"></polygon>\n <rect x="6" y="6" width="20" height="20" stroke="#3D4960" \n stroke-width="1.3" fill="#FFF9C4" \n stroke-linecap="round" stroke-linejoin="round"/>\n <line x1="6" y1="16" x2="26" y2="16" stroke="#3D4960" \n stroke-width="1.3" stroke-linecap="round"/>\n <line x1="16" y1="6" x2="16" y2="26" stroke="#3D4960" \n stroke-width="1.3" stroke-linecap="round"/>\n </g>\n </g>\n </g>\n </g>\n ',e.appendChild(n);const o=document.createElement("div");return o.setAttribute("size","478"),o.className="css-7s2mhh",o.textContent="Solve",t.appendChild(e),t.appendChild(o),t.addEventListener("click",i),t}(),n=function(){const t=document.createElement("div");t.setAttribute("size","478"),t.className="css-2bpbil",t.style.cursor="pointer";const e=document.createElement("div");e.setAttribute("size","478"),e.className="css-o90g4c";const i=document.createElementNS("http://www.w3.org/2000/svg","svg");i.setAttribute("width","100%"),i.setAttribute("height","100%"),i.setAttribute("viewBox","0 0 33 32"),i.setAttribute("version","1.1"),i.innerHTML='\n <title>Legit Mode</title>\n <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">\n <rect x="6" y="6" width="20" height="20" stroke="#3D4960" \n stroke-width="1.3" fill="#FFF9C4" \n stroke-linecap="round" stroke-linejoin="round"/>\n <path class="checkmark" d="M9 16L14 21L23 12" stroke="#3D4960" \n stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"\n style="display: none;"/>\n </g>\n ',e.appendChild(i);const n=document.createElement("div");n.setAttribute("size","478"),n.className="css-7s2mhh",n.textContent="Legit",t.appendChild(e),t.appendChild(n);let o=!1;const s=i.querySelector(".checkmark");return t.addEventListener("click",(()=>{o=!o,s.style.display=o?"block":"none",window.isLegitMode=o})),t}(),o=function(){const t=document.createElement("div");t.setAttribute("size","478"),t.className="css-2bpbil",t.style.cursor="pointer";const e=document.createElement("div");e.setAttribute("size","478"),e.className="css-o90g4c";const i=document.createElementNS("http://www.w3.org/2000/svg","svg");i.setAttribute("width","100%"),i.setAttribute("height","100%"),i.setAttribute("viewBox","0 0 33 32"),i.setAttribute("version","1.1"),i.innerHTML='\n <title>Random Fill</title>\n <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">\n <rect x="6" y="6" width="20" height="20" stroke="#3D4960" \n stroke-width="1.3" fill="#FFF9C4" \n stroke-linecap="round" stroke-linejoin="round"/>\n <path class="checkmark" d="M9 16L14 21L23 12" stroke="#3D4960" \n stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"\n style="display: none;"/>\n </g>\n ',e.appendChild(i);const n=document.createElement("div");n.setAttribute("size","478"),n.className="css-7s2mhh",n.textContent="Random",t.appendChild(e),t.appendChild(n);let o=!1;const s=i.querySelector(".checkmark");return t.addEventListener("click",(()=>{o=!o,s.style.display=o?"block":"none",window.isRandomMode=o})),t}();return e.appendChild(t),e.appendChild(n),e.appendChild(o),!0}return!1}function o(){document.querySelectorAll(".css-imzd00").forEach((t=>{t.style.width="unset"}))}n()&&o(),new MutationObserver(((t,e)=>{n()&&(o(),e.disconnect())})).observe(document.body,{childList:!0,subtree:!0})})();