<nav class="app-bar">
<button onclick="HamburgerButtonClick();" class="button bar-button hamburger-button">
<span class="material-icons">menu</span>
</button>
<div class="bar-font title">Sudoku</div>
<div id="moreoption-sec" class="more-option-div more-button">
<button onclick="moreOptionButtonClick()" class="button bar-button">
<span class="material-icons">more_vert</span>
</button>
<!-- it is important to put these styles in here because if I do not do that it will not work in javaScript-->
<div id="more-option-list" style="visibility: hidden;max-height: 10px;max-width: 40px;min-width: 40px;" class="more-option-list">
<button onclick="hintButtonClick()" ripple-color="#003c8f" class="button nav-item vertical-adjust">Hint</button>
<button onclick="restartButtonClick()" ripple-color="#003c8f" class="button nav-item vertical-adjust">Restart</button>
<button onclick="SurrenderButtonClick()" ripple-color="tomato" class="button nav-item vertical-adjust">Surrender</button>
</div>
</div>
<button id="pause-btn" onclick="pauseGameButtonClick()" class="button bar-button more-button">
<span id="pause-icon" class="material-icons">pause</span>
<span id="pause-text">Pause</span>
</button>
<button id="check-btn" onclick="checkButtonClick()" class="button bar-button more-button">
<span class="material-icons">done_all</span>
<span>Check</span>
</button>
<button id="isunique-btn" style="display: none;" onclick="isUniqueButtonClick();" class="button bar-button more-button">
<span class="material-icons">call_split</span>
<span>Is unique</span>
</button>
<button id="solve-btn" style="display: none;" onclick="solveButtonClick()" class="button bar-button more-button">
<span class="material-icons">border_color</span>
<span>Solve</span>
</button>
</nav>
<div id="hamburger-menu" class="hamburger-menu">
<nav id="nav-menu" class="nav-menu">
<div class="nav-head">
<div class="nav-head-img">
<img src="https://image.ibb.co/jmuOKn/icon.jpg" art="" />
</div>
<div class="nav-head-title">Sudoku</div>
</div>
<ul class="nav-items">
<button onclick="showDialogClick('dialog');" ripple-color="#003c8f" class="button nav-item vertical-adjust">
<div>
<span class="material-icons">add</span>
<span style="left:12px;">New game</span>
</div>
</button>
<button onclick="sudokuSolverMenuClick();" ripple-color="#003c8f" class="button nav-item vertical-adjust">
<div>
<span class="material-icons">edit</span>
<span style="left:12px;">Sudoku Solver</span>
</div>
</button>
<button onclick="showDialogClick('about-dialog');" ripple-color="#003c8f" class="button nav-item vertical-adjust">
<div>
<span class="material-icons">star</span>
<span style="left:12px;">About</span>
</div>
</button>
<div class="bar-footer">
<ul>
<a href="#" class="bar-footer-link">Site feedback</a>
<a href="#" class="bar-footer-link">Privacy</a>
<a href="#" class="bar-footer-link">Terms</a>
</ul>
</div>
</ul>
</nav>
<div class="nav-menu-blank" onclick="hideHamburgerClick()">
</div>
</div>
<div class="floating">
<button onclick="showDialogClick('dialog');" class="button floating-btn vertical-adjust">
<span class="material-icons">add</span>
</button>
</div>
<div id="dialog" class="dialog">
<div id="dialog-box" class="dialog-content">
<div class="dialog-header">New game</div>
<div class="dialog-body">
<p>Select game difficulty to get started.</p>
<ul>
<li class="radio-option">
<label for="very-easy">
<input id="very-easy" value="very easy" type="radio" name="difficulty"> Very easy
</label>
</li>
<li class="radio-option">
<label for="easy">
<input id="easy" value="easy" type="radio" name="difficulty"> Easy
</label>
</li>
<li class="radio-option">
<label for="normal">
<input id="normal" value="normal" type="radio" name="difficulty"> Normal
</label>
</li>
<li class="radio-option">
<label for="hard">
<input id="hard" value="hard" type="radio" name="difficulty"> Hard
</label>
</li>
<li class="radio-option">
<label for="very-hard">
<input id="very-hard" value="expert" type="radio" name="difficulty"> Expert
</label>
</li>
</ul>
</div>
<div class="dialog-footer">
<button onclick="startGameButtonClick();" ripple-color="#003c8f" class="button dialog-btn vertical-adjust">OK</button>
<button onclick="hideDialogButtonClick('dialog');" ripple-color="#202020" class="button dialog-btn vertical-adjust">Cancel</button>
</div>
</div>
</div>
<div id="about-dialog" class="dialog">
<div id="about-dialog-box" onblur="hideDialogButtonClick('about-dialog');" class="dialog-content about-dialog-content">
<div class="dialog-header">CodeTeam6</div>
<div class="dialog-body">
<p>about us</p>
<div class="card-group">
<div class="card dialog-card">
<div class="about-card-img">
<img src="https://image.ibb.co/crYHen/a_abdallah.jpg" alt="" />
</div>
<div class="about-card-title">Ahmad Abdalla</div>
<div class="about-card-content">Egypt</div>
<div class="about-card-quote">My dream is to be the best developer in the world, and I'll work continuously to achieve that.</div>
</div>
<div class="card dialog-card">
<div class="about-card-img">
<img src="https://image.ibb.co/mKg3Kn/a_alrifai.jpg" alt="" />
</div>
<div class="about-card-title">Ayman Alrifai</div>
<div class="about-card-content">Libya</div>
<div class="about-card-quote">I love coding & design. I learn every day to build awesome stuff.</div>
</div>
<div class="card dialog-card">
<div class="about-card-img">
<img src="https://image.ibb.co/dYd5X7/m_diab.jpg" alt="" />
</div>
<div class="about-card-title">Mohammad Diab</div>
<div class="about-card-content">Syria</div>
<div class="about-card-quote">Silent but deadly.</div>
</div>
<div class="card dialog-card">
<div class="about-card-img">
<img src="https://image.ibb.co/g01g5S/" alt="" />
</div>
<div class="about-card-title">RB</div>
<div class="about-card-content">Palestine</div>
<div class="about-card-quote">I think outside the box, I love trying everything new.</div>
</div>
</div>
</div>
<div class="dialog-footer">
<button onclick="hideDialogButtonClick('about-dialog');" ripple-color="#003c8f" class="button dialog-btn vertical-adjust">OK</button>
</div>
</div>
</div>
<div class="body" id="sudoku">
<div class="card game">
<table id="puzzle-grid">
<tr>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
</tr>
<tr>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
</tr>
<tr>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
</tr>
<tr>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
</tr>
<tr>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
</tr>
<tr>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
</tr>
<tr>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
</tr>
<tr>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
</tr>
<tr>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
<td>
<input type="text" maxlength="1" onchange="checkInput(this)" disabled />
</td>
</tr>
</table>
</div>
<div class="card status">
<div id="game-number">game #0</div>
<ul class="game-status">
<li>
<div class="vertical-adjust">
<span class="material-icons">timer</span>
<span id="timer-label">Time</span>
</div>
<div id="timer" class="timer">00:00</div>
</li>
<li>
<div class="vertical-adjust">
<span class="material-icons">network_check</span>
<span id="game-difficulty-label">Game difficulty</span>
</div>
<div id="game-difficulty" class="timer">undefined</div>
</li>
<li>
<div class="vertical-adjust">
<span class="material-icons">grid_on</span>
<span>Remaining numbers</span>
</div>
<div class="remain-table">
<div class="remain-column">
<div class="remain-cell">
<div class="remain-cell-header">1</div>
<div onchange="document.write('Hello');" id="remain-1" class="remain-cell-content">0</div>
</div>
<div class="remain-cell">
<div class="remain-cell-header">4</div>
<div id="remain-4" class="remain-cell-content">0</div>
</div>
<div class="remain-cell">
<div class="remain-cell-header">7</div>
<div id="remain-7" class="remain-cell-content">0</div>
</div>
</div>
<div class="remain-column">
<div class="remain-cell">
<div class="remain-cell-header">2</div>
<div id="remain-2" class="remain-cell-content">0</div>
</div>
<div class="remain-cell">
<div class="remain-cell-header">5</div>
<div id="remain-5" class="remain-cell-content">0</div>
</div>
<div class="remain-cell">
<div class="remain-cell-header">8</div>
<div id="remain-8" class="remain-cell-content">0</div>
</div>
</div>
<div class="remain-column">
<div class="remain-cell">
<div class="remain-cell-header">3</div>
<div id="remain-3" class="remain-cell-content">0</div>
</div>
<div class="remain-cell">
<div class="remain-cell-header">6</div>
<div id="remain-6" class="remain-cell-content">0</div>
</div>
<div class="remain-cell">
<div class="remain-cell-header">9</div>
<div id="remain-9" class="remain-cell-content">0</div>
</div>
</div>
</div>
</li>
</ul>
<!--<button class="option-button">
<span class="material-icons">pause</span>
<span>Pause</span>
</button>
<button class="option-button">
<span class="material-icons">done_all</span>
<span>Check</span>
</button>
<button class="option-button">
<span class="material-icons">help</span>
<span>Hint</span>
</button>
<button class="option-button">
<span class="material-icons">refresh</span>
<span>Restart</span>
</button>
<button class="option-button">
<span class="material-icons">flag</span>
<span>Surrender</span>
</button>
-->
</div>
</div>
<div class="footer vertical-adjust">
<span class="material-icons">code</span>
<span>with</span>
<span class="material-icons">favorite</span>
<span>by Mohammad Diab from</span>
<a href="#" onclick="showDialogClick('about-dialog');">#codeTeam6</a>
<span> . © 2018 all right reserved.</span>
</div>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: Roboto, sans-serif;
}
html,
body {
background-color: rgb(235, 235, 240);
}
table {
border: 2px solid #000000;
border-spacing: 0;
border-collapse: collapse;
transition: all 0.5s;
}
ul {
list-style-type: none;
}
td {
border: 1px solid #000000;
text-align: center;
vertical-align: middle;
}
td input {
color: #000000;
padding: 0;
border: 0;
text-align: center;
width: 48px;
height: 48px;
font-size: 24px;
background-color: #ffffff;
outline: none;
text-transform: uppercase;
transition: all 0.5s;
}
input:disabled {
background-color: #bbdefb;
}
tr:nth-child(3n) {
border-bottom: 4px solid #000000;
}
tr:nth-child(3n + 1) {
border-top: 4px solid #000000;
}
td:nth-child(3n) {
border-right: 4px solid #000000;
}
td:nth-child(3n + 1) {
border-left: 4px solid #000000;
}
.right-cell {
box-shadow: inset 0px 0px 20px 3px forestgreen;
}
.wrong-cell {
box-shadow: inset 0px 0px 20px 3px tomato;
}
.worning-cell {
box-shadow: inset 0px 0px 20px 3px goldenrod;
}
/*Material Design*/
.app-bar {
background: #49599a;
width: 100%;
position: fixed;
height: 64px;
color: #fff;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.14);
z-index: 5;
top: 0;
}
.bar-button {
position: relative;
background: transparent;
border: none;
outline: none;
color: #fff;
vertical-align: middle;
padding: 0 22px;
transition: all 0.5s;
}
.bar-button span {
line-height: 64px;
display: inline-block;
vertical-align: middle;
}
.hamburger-button {
float: left;
left: 4px;
}
.bar-font {
font-size: 18px;
line-height: 64px;
}
.title {
position: relative;
float: left;
left: 18px;
}
.more-button {
float: right;
/*right: 18px;*/
}
.hamburger-menu {
background: rgba(0, 0, 0, 0.4);
position: fixed;
left: 0;
top: 0;
bottom: 0;
z-index: 25;
width: 100vw;
height: 100vh;
display: none;
opacity: 0;
transition: 0.1s all;
}
.nav-menu {
border-right: 1px solid rgba(0, 0, 0, 0.4);
background: #fff;
color: #212121;
position: fixed;
left: -256px;
top: 0;
bottom: 0;
width: 256px;
z-index: 26;
font-size: 15px;
box-shadow: 16px 0 24px 2px rgba(0, 0, 0, 0.14);
transition: all 0.3s;
}
.nav-menu-blank {
position: relative;
left: 256px;
width: 100%;
height: 100%;
}
.nav-head {
height: 172px;
background: #5e92f3;
position: relative;
}
.nav-head-img {
position: relative;
border: 2px solid rgba(255, 255, 255, 0.4);
border-radius: 50%;
width: 96px;
height: 96px;
top: 16px;
left: 16px;
overflow: hidden;
}
.nav-head-img img {
width: 100%;
height: 100%;
}
.nav-head-title {
color: #fff;
position: absolute;
bottom: 10px;
margin-left: auto;
margin-right: auto;
left: 0px;
right: 0;
font-size: 22px;
display: block;
text-align: center;
}
.nav-items {
margin-top: 12px;
}
.nav-item {
font-weight: 700;
display: block;
color: #333;
background: #0000;
padding: 15px 0 15px 22px;
letter-spacing: 1.1px;
outline: none;
border: none;
width: 100%;
text-align: left;
margin: 0 !important;
}
.bar-footer {
position: fixed;
bottom: 12px;
left: 10px;
}
.bar-footer-link {
font-size: 12px;
display: inline-block;
margin: 0 8px;
text-decoration: none;
color: gray;
}
.body {
width: 95%;
max-width: 800px;
margin: 96px auto 16px auto;
display: flex;
}
.card {
background: #fff;
width: fit-content;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.14);
float: left;
padding: 32px 32px 16px 32px;
}
.status {
margin-left: 32px;
padding-top: 10px;
padding-left: 10px;
}
#game-number {
font-size: 12px;
color: gray;
}
.game-status {
/*display: flex;
flex-direction: column;
justify-content: center;
flex-flow: column;*/
margin: 0 0 0 22px;
height: 100%;
}
.game-status li {
margin: 18px 0 0 0;
}
.vertical-adjust {
margin: 12px 0;
}
.vertical-adjust span,
.footer a {
line-height: 24px;
display: inline-block;
vertical-align: middle;
}
.option-button {
display: block;
margin: 16px 8px 16px 30px;
width: 130px;
padding: 8px 10px;
font-size: 16px;
border: none;
outline: none;
box-shadow: 0 6px 10px 1px rgba(0, 0, 0, 0.14);
border-radius: 2px;
transition: all 0.5s;
text-align: left;
}
.button {
position: relative;
overflow: hidden;
cursor: pointer;
}
.option-button:hover {
background: #1565c0;
}
.option-button:active {
background: #3d7df4;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.24);
}
.option-button span {
vertical-align: middle;
line-height: 24px;
}
.ripple {
position: absolute;
background: #fff;
border-radius: 50%;
width: 5px;
height: 5px;
animation: ripple-effect 1.1s 1 cubic-bezier(0.42, 0, 0.58, 1);
opacity: 0;
}
@keyframes ripple-effect {
0% {
transform: scale(1);
opacity: 0.4;
}
100% {
transform: scale(100);
opacity: 0;
}
}
.timer {
color: #1565c0;
font-size: 32px;
padding: 4px;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.14);
text-align: center;
}
.remain-table {
position: relative;
left: 0;
right: 0;
display: inline-block;
margin: auto;
}
.remain-column {
float: left;
max-width: 64px;
}
.remain-cell {
margin: 10px;
text-align: center;
border: solid 1px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.14);
}
.remain-cell div {
padding: 5px 12px;
}
.remain-cell-header {
background-color: #1565c0;
color: white;
font-weight: bold;
border-bottom: solid 2px rgba(0, 0, 0, 0.2);
}
.red {
background: #ff6659;
color: #9a0007;
}
.gray {
background: #808080;
color: #404040;
}
.floating {
position: fixed;
bottom: 64px;
right: 64px;
z-index: 20;
}
.floating-btn {
position: fixed;
bottom: 48px;
right: 48px;
border-radius: 50%;
padding: 12px;
border: none;
background-color: #1565c0;
color: #fff;
box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14);
outline: none;
z-index: 21;
}
.dialog {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
z-index: 50;
display: none;
transition: all 0.2s;
}
.dialog-content {
top: -200px;
background: #fff;
width: 90%;
max-width: 540px;
height: fit-content;
margin: auto;
vertical-align: middle;
box-shadow: 0 24px 38px 3px rgba(0, 0, 0, 0.14);
z-index: 51;
transition: all 0.5s;
}
.dialog-header {
font-size: 24px;
font-weight: bold;
padding: 16px 32px;
border-bottom: solid 1px #808080;
}
.dialog-body p {
margin: 16px 0 4px 28px;
color: gray;
}
.radio-option {
padding: 0 36px;
list-style-type: none;
position: relative;
}
.radio-option input {
outline: none;
margin-right: 12px;
}
.radio-option label {
display: block;
height: 24px;
cursor: pointer;
padding: 1.25em 0;
}
.dialog-footer {
border-top: solid 1px #808080;
margin-top: 24px;
text-align: right;
padding-right: 16px;
}
.dialog-btn {
background: transparent;
border: none;
color: #003c8f;
font-size: 16px;
margin: 8px 0;
padding: 8px 16px;
outline: none;
min-width: 96px;
display: inline-block;
}
.footer {
text-align: center;
color: white;
background-color: #49599a;
margin: 44px 0 0 0;
padding: 8px;
}
.footer a {
color: white;
}
.about-dialog-content {
max-width: 720px;
}
.card-group {
overflow: hidden;
width: fit-content;
margin: 0 auto;
padding: 16px 0;
display: flex;
}
.dialog-card {
padding: 16px;
margin: 8px;
max-width: 160px;
}
.about-card-quote {
color: #606060;
font-size: 14px;
margin-top: 16px;
}
.about-card-img {
margin: 16px auto;
overflow: hidden;
border-radius: 50%;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.14);
width: fit-content;
}
.about-card-img img {
width: 96px;
height: auto;
}
.about-card-title {
font-size: 16px;
margin: 8px 0;
}
.about-card-content {
font-size: 15px;
margin: 4px 0;
}
.more-option-div {
position: static;
display: inline-block;
margin-right: 16px;
}
.more-option-list {
display: block;
position: absolute;
background-color: #fff;
overflow: hidden;
box-shadow: 0px 8px 10px 1px rgba(0, 0, 0, 0.14);
right: 18px;
z-index: 25;
transition: all 0.2s cubic-bezier(0.4, 0, 0.6, 1);
}
// grid variable
var table;
// game number
var gameId = 0;
// puzzle grid
var puzzle = [];
// solution grid
var solution = [];
// remaining number counts
var remaining = [9, 9, 9, 9, 9, 9, 9, 9, 9];
// variable to check if "Sudoku Solver" solve the puzzle
var isSolved = false;
var canSolved = true;
// stopwatch timer variables
var timer = 0;
var pauseTimer = false;
var intervalId;
var gameOn = false;
function newGame(difficulty) {
// get random position for numbers from '1' to '9' to generate a random puzzle
var grid = getGridInit();
// prepare rows, columns and blocks to solove the initioaled grid
var rows = grid;
var cols = getColumns(grid);
var blks = getBlocks(grid);
// solve the grid section
// generate allowed digits for each cell
var psNum = generatePossibleNumber(rows, cols, blks);
// solve the grid
solution = solveGrid(psNum, rows, true);
// reset the game state timer and remaining number
timer = 0;
for (var i in remaining) remaining[i] = 9;
// empty cells from grid depend on difficulty
// for now it will be:
// 59 empty cells for very easy
// 64 empty cells for easy
// 69 empty cells for normal
// 74 empty cells for hard
// 79 empty cells for expert
puzzle = makeItPuzzle(solution, difficulty);
// game is on when the difficulty = [0, 4]
gameOn = difficulty < 5 && difficulty >= 0;
// update the UI
ViewPuzzle(puzzle);
updateRemainingTable();
// finally, start the timer
if (gameOn) startTimer();
}
function getGridInit() {
var rand = [];
// for each digits from 1 to 9 find a random row and column
for (var i = 1; i <= 9; i++) {
var row = Math.floor(Math.random() * 9);
var col = Math.floor(Math.random() * 9);
var accept = true;
for (var j = 0; j < rand.length; j++) {
// if number exist or there is a number already located in then ignore and try again
if ((rand[j][0] == i) | ((rand[j][1] == row) & (rand[j][2] == col))) {
accept = false;
// try to get a new position for this number
i--;
break;
}
}
if (accept) {
rand.push([i, row, col]);
}
}
// initialize new empty grid
var result = [];
for (var i = 0; i < 9; i++) {
var row = "000000000";
result.push(row);
}
// put numbers in the grid
for (var i = 0; i < rand.length; i++) {
result[rand[i][1]] = replaceCharAt(
result[rand[i][1]],
rand[i][2],
rand[i][0]
);
}
return result;
}
// return columns from a row grid
function getColumns(grid) {
var result = ["", "", "", "", "", "", "", "", ""];
for (var i = 0; i < 9; i++) {
for (var j = 0; j < 9; j++) result[j] += grid[i][j];
/*try {
result[j] += grid[i][j];
} catch (err) {
alert(grid);
}*/
}
return result;
}
// return blocks from a row grid
function getBlocks(grid) {
var result = ["", "", "", "", "", "", "", "", ""];
for (var i = 0; i < 9; i++) {
for (var j = 0; j < 9; j++)
result[Math.floor(i / 3) * 3 + Math.floor(j / 3)] += grid[i][j];
}
return result;
}
// function to replace char in string
function replaceCharAt(string, index, char) {
if (index > string.length - 1) return string;
return string.substr(0, index) + char + string.substr(index + 1);
}
// get allowed numbers that can be placed in each cell
function generatePossibleNumber(rows, columns, blocks) {
var psb = [];
// for each cell get numbers that are not viewed in a row, column or block
// if the cell is not empty then, allowed number is the number already exist in it
for (var i = 0; i < 9; i++) {
for (var j = 0; j < 9; j++) {
psb[i * 9 + j] = "";
if (rows[i][j] != 0) {
psb[i * 9 + j] += rows[i][j];
} else {
for (var k = "1"; k <= "9"; k++) {
if (!rows[i].includes(k))
if (!columns[j].includes(k))
if (
!blocks[Math.floor(i / 3) * 3 + Math.floor(j / 3)].includes(k)
)
psb[i * 9 + j] += k;
}
}
}
}
return psb;
}
function solveGrid(possibleNumber, rows, startFromZero) {
var solution = [];
// solve Sudoku with a backtracking algorithm
// Steps are:
// 1. get all allowed numbers that fit in each empty cell
// 2. generate all possible rows that fit in the first row depend on the allowed number list
//` 3. select one row from possible row list and put it in the first row
// 4. go to next row and find all possible number that fit in each cell
// 5. generate all possible row fit in this row then go to step 3 until reach the last row or there aren't any possible rows left
// 6. if next row hasn't any possible left then go the previous row and try the next possibility from possibility rows' list
// 7. if the last row has reached and a row fit in it has found then the grid has solved
var result = nextStep(0, possibleNumber, rows, solution, startFromZero);
if (result == 1) return solution;
}
// level is current row number in the grid
function nextStep(level, possibleNumber, rows, solution, startFromZero) {
// get possible number fit in each cell in this row
var x = possibleNumber.slice(level * 9, (level + 1) * 9);
// generate possible numbers sequence that fit in the current row
var y = generatePossibleRows(x);
if (y.length == 0) return 0;
// to allow check is solution is unique
var start = startFromZero ? 0 : y.length - 1;
var stop = startFromZero ? y.length - 1 : 0;
var step = startFromZero ? 1 : -1;
var condition = startFromZero ? start <= stop : start >= stop;
// try every numbers sequence in this list and go to next row
for (var num = start; condition; num += step) {
var condition = startFromZero ? num + step <= stop : num + step >= stop;
for (var i = level + 1; i < 9; i++) solution[i] = rows[i];
solution[level] = y[num];
if (level < 8) {
/*if (solution[4] === undefined) {
var x = 0;
x++;
}*/
var cols = getColumns(solution);
var blocks = getBlocks(solution);
var poss = generatePossibleNumber(solution, cols, blocks);
if (nextStep(level + 1, poss, rows, solution, startFromZero) == 1)
return 1;
}
if (level == 8) return 1;
}
return -1;
}
// generate possible numbers sequence that fit in the current row
function generatePossibleRows(possibleNumber) {
var result = [];
function step(level, PossibleRow) {
if (level == 9) {
result.push(PossibleRow);
return;
}
for (var i in possibleNumber[level]) {
if (PossibleRow.includes(possibleNumber[level][i])) continue;
step(level + 1, PossibleRow + possibleNumber[level][i]);
}
}
step(0, "");
return result;
}
// empty cell from grid depends on the difficulty to make the puzzle
function makeItPuzzle(grid, difficulty) {
/*
difficulty:
// expert : 0;
// hard : 1;
// Normal : 2;
// easy : 3;
// very easy: 4;
*/
// empty_cell_count = 5 * difficulty + 20
// when difficulty = 13, empty_cell_count = 85 > (81 total cells count)
// so the puzzle is showen as solved grid
if (!(difficulty < 5 && difficulty > -1)) difficulty = 13;
var remainedValues = 81;
var puzzle = grid.slice(0);
// function to remove value from a cell and its symmetry then return remained values
function clearValue(grid, x, y, remainedValues) {
function getSymmetry(x, y) {
var symX = 8 - x; //Symmetry
var symY = 8 - y;
return [symX, symY];
}
var sym = getSymmetry(x, y);
if (grid[y][x] != 0) {
grid[y] = replaceCharAt(grid[y], x, "0");
remainedValues--;
if (x != sym[0] && y != sym[1]) {
grid[sym[1]] = replaceCharAt(grid[sym[1]], sym[0], "0");
remainedValues--;
}
}
return remainedValues;
}
// remove value from a cell and its symmetry to reach the expected empty cells amount
while (remainedValues > difficulty * 5 + 20) {
var x = Math.floor(Math.random() * 9);
var y = Math.floor(Math.random() * 9);
remainedValues = clearValue(puzzle, x, y, remainedValues);
}
return puzzle;
}
// view grid in html page
function ViewPuzzle(grid) {
for (var i = 0; i < grid.length; i++) {
for (var j = 0; j < grid[i].length; j++) {
var input = table.rows[i].cells[j].getElementsByTagName("input")[0];
addClassToCell(table.rows[i].cells[j].getElementsByTagName("input")[0]);
if (grid[i][j] == "0") {
input.disabled = false;
input.value = "";
} else {
input.disabled = true;
input.value = grid[i][j];
remaining[grid[i][j] - 1]--;
}
}
}
}
// read current grid
function readInput() {
var result = [];
for (var i = 0; i < 9; i++) {
result.push("");
for (var j = 0; j < 9; j++) {
var input = table.rows[i].cells[j].getElementsByTagName("input")[0];
if (input.value == "" || input.value.length > 1 || input.value == "0") {
input.value = "";
result[i] += "0";
} else result[i] += input.value;
}
}
return result;
}
// check value if it is correct or wrong
// return:
// 0 for value can't be changed
// 1 for correct value
// 2 for value that hasn't any conflict with other values
// 3 for value that conflict with value in its row, column or block
// 4 for incorect input
function checkValue(value, row, column, block, defaultValue, currectValue) {
if (value === "" || value === "0") return 0;
if (!(value > "0" && value < ":")) return 4;
if (value === defaultValue) return 0;
if (
row.indexOf(value) != row.lastIndexOf(value) ||
column.indexOf(value) != column.lastIndexOf(value) ||
block.indexOf(value) != block.lastIndexOf(value)
) {
return 3;
}
if (value !== currectValue) return 2;
return 1;
}
// remove old class from input and add a new class to represent current cell's state
function addClassToCell(input, className) {
// remove old class from input
input.classList.remove("right-cell");
input.classList.remove("worning-cell");
input.classList.remove("wrong-cell");
if (className != undefined) input.classList.add(className);
}
// update value of remaining numbers in html page
function updateRemainingTable() {
for (var i = 1; i < 10; i++) {
var item = document.getElementById("remain-" + i);
item.innerText = remaining[i - 1];
item.classList.remove("red");
item.classList.remove("gray");
if (remaining[i - 1] === 0) item.classList.add("gray");
else if (remaining[i - 1] < 0 || remaining[i - 1] > 9)
item.classList.add("red");
}
}
// start stopwatch timer
function startTimer() {
var timerDiv = document.getElementById("timer");
clearInterval(intervalId);
// update stopwatch value every one second
pauseTimer = false;
intervalId = setInterval(function () {
if (!pauseTimer) {
timer++;
var min = Math.floor(timer / 60);
var sec = timer % 60;
timerDiv.innerText =
(("" + min).length < 2 ? "0" + min : min) +
":" +
(("" + sec).length < 2 ? "0" + sec : sec);
}
}, 1000);
}
// solve sudoku function
// input: changeUI boolean true to allow function to change UI
// output:
// 0 when everything goes right
// 1 when grid is already solved
// 2 when Invalid input
// 3 when no solution
function solveSudoku(changeUI) {
// read current state
puzzle = readInput();
var columns = getColumns(puzzle);
var blocks = getBlocks(puzzle);
// check if there is any conflict
var errors = 0;
var correct = 0;
for (var i = 0; i < puzzle.length; i++) {
for (var j = 0; j < puzzle[i].length; j++) {
var result = checkValue(
puzzle[i][j],
puzzle[i],
columns[j],
blocks[Math.floor(i / 3) * 3 + Math.floor(j / 3)],
-1,
-1
);
correct = correct + (result === 2 ? 1 : 0);
errors = errors + (result > 2 ? 1 : 0);
addClassToCell(
table.rows[i].cells[j].getElementsByTagName("input")[0],
result > 2 ? "wrong-cell" : undefined
);
}
}
// check if invalid input
if (errors > 0) {
canSolved = false;
return 2;
}
canSolved = true;
isSolved = true;
// check if grid is already solved
if (correct === 81) {
return 1;
}
//read the current time
var time = Date.now();
// solve the grid
solution = solveGrid(
generatePossibleNumber(puzzle, columns, blocks),
puzzle,
true
);
// show result
// get time
time = Date.now() - time;
if (changeUI)
document.getElementById("timer").innerText =
Math.floor(time / 1000) + "." + ("000" + (time % 1000)).slice(-3);
if (solution === undefined) {
isSolved = false;
canSolved = false;
return 3;
}
if (changeUI) {
remaining = [0, 0, 0, 0, 0, 0, 0, 0, 0];
updateRemainingTable();
ViewPuzzle(solution);
}
return 0;
}
// hide more option menu
function hideMoreOptionMenu() {
var moreOptionList = document.getElementById("more-option-list");
if (moreOptionList.style.visibility == "visible") {
moreOptionList.style.maxWidth = "40px";
moreOptionList.style.minWidth = "40px";
moreOptionList.style.maxHeight = "10px";
moreOptionList.style.opacity = "0";
setTimeout(function () {
moreOptionList.style.visibility = "hidden";
}, 175);
}
}
// UI Comunication functions
// function that must run when document loaded
window.onload = function () {
// assigne table to its value
table = document.getElementById("puzzle-grid");
// add ripple effect to all buttons in layout
var rippleButtons = document.getElementsByClassName("button");
for (var i = 0; i < rippleButtons.length; i++) {
rippleButtons[i].onmousedown = function (e) {
// get ripple effect's position depend on mouse and button position
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
// add div that represents the ripple
var rippleItem = document.createElement("div");
rippleItem.classList.add("ripple");
rippleItem.setAttribute("style", "left: " + x + "px; top: " + y + "px");
// if ripple item should have special color... get and apply it
var rippleColor = this.getAttribute("ripple-color");
if (rippleColor) rippleItem.style.background = rippleColor;
this.appendChild(rippleItem);
// set timer to remove the dif after the effect ends
setTimeout(function () {
rippleItem.parentElement.removeChild(rippleItem);
}, 1500);
};
}
for (var i = 0; i < 9; i++) {
for (var j = 0; j < 9; j++) {
var input = table.rows[i].cells[j].getElementsByTagName("input")[0];
// add function to remove color from cells and update remaining numbers table when it get changed
input.onchange = function () {
//remove color from cell
addClassToCell(this);
// check if the new value entered is allowed
function checkInput(input) {
if (input.value[0] < "1" || input.value[0] > "9") {
if (input.value != "?" && input.value != "؟") {
input.value = "";
alert("only numbers [1-9] and question mark '?' are allowed!!");
input.focus();
}
}
}
checkInput(this);
// compare old value and new value then update remaining numbers table
if (this.value > 0 && this.value < 10) remaining[this.value - 1]--;
if (this.oldvalue !== "") {
if (this.oldvalue > 0 && this.oldvalue < 10)
remaining[this.oldvalue - 1]++;
}
//reset canSolved value when change any cell
canSolved = true;
updateRemainingTable();
};
//change cell 'old value' when it got focused to track numbers and changes on grid
input.onfocus = function () {
this.oldvalue = this.value;
};
}
}
};
// function to hide dialog opened in window
window.onclick = function (event) {
var d1 = document.getElementById("dialog");
var d2 = document.getElementById("about-dialog");
var m1 = document.getElementById("more-option-list");
if (event.target == d1) {
hideDialogButtonClick("dialog");
} else if (event.target == d2) {
hideDialogButtonClick("about-dialog");
} else if (m1.style.visibility == "visible") {
hideMoreOptionMenu();
}
};
// show hamburger menu
function HamburgerButtonClick() {
debugger
var div = document.getElementById("hamburger-menu");
var menu = document.getElementById("nav-menu");
div.style.display = "block";
div.style.visibility = "visible";
setTimeout(function () {
div.style.opacity = 1;
menu.style.left = 0;
}, 50);
}
// start new game
function startGameButtonClick() {
var difficulties = document.getElementsByName("difficulty");
// difficulty:
// 0 expert
// 1 hard
// 2 normal
// 3 easy
// 4 very easy
// 5 solved
// initial difficulty to 5 (solved)
var difficulty = 5;
// get difficulty value
for (var i = 0; i < difficulties.length; i++) {
if (difficulties[i].checked) {
newGame(4 - i);
difficulty = i;
break;
}
}
if (difficulty > 4) newGame(5);
hideDialogButtonClick("dialog");
gameId++;
document.getElementById("game-number").innerText = "game #" + gameId;
// hide solver buttons
// show other buttons
document.getElementById("moreoption-sec").style.display = "block";
document.getElementById("pause-btn").style.display = "block";
document.getElementById("check-btn").style.display = "block";
document.getElementById("isunique-btn").style.display = "none";
document.getElementById("solve-btn").style.display = "none";
// prerpare view for new game
document.getElementById("timer-label").innerText = "Time";
document.getElementById("timer").innerText = "00:00";
document.getElementById("game-difficulty-label").innerText =
"Game difficulty";
document.getElementById("game-difficulty").innerText =
difficulty < difficulties.length
? difficulties[difficulty].value
: "solved";
}
// pause \ continue button click function
function pauseGameButtonClick() {
var icon = document.getElementById("pause-icon");
var label = document.getElementById("pause-text");
// change icon and label of the button and hide or show the grid
if (pauseTimer) {
icon.innerText = "pause";
label.innerText = "Pause";
table.style.opacity = 1;
} else {
icon.innerText = "play_arrow";
label.innerText = "Continue";
table.style.opacity = 0;
}
pauseTimer = !pauseTimer;
}
// check grid if correct
function checkButtonClick() {
// check if game is started
if (gameOn) {
// add one minute to the stopwatch as a cost of grid's check
timer += 60;
var currentGrid = [];
// read gritd status
currentGrid = readInput();
var columns = getColumns(currentGrid);
var blocks = getBlocks(currentGrid);
var errors = 0;
var currects = 0;
for (var i = 0; i < currentGrid.length; i++) {
for (var j = 0; j < currentGrid[i].length; j++) {
if (currentGrid[i][j] == "0") continue;
// check value if it is correct or wrong
var result = checkValue(
currentGrid[i][j],
currentGrid[i],
columns[j],
blocks[Math.floor(i / 3) * 3 + Math.floor(j / 3)],
puzzle[i][j],
solution[i][j]
);
// remove old class from input and add a new class to represent current cell's state
addClassToCell(
table.rows[i].cells[j].getElementsByTagName("input")[0],
result === 1
? "right-cell"
: result === 2
? "worning-cell"
: result === 3
? "wrong-cell"
: undefined
);
if (result === 1 || result === 0) {
currects++;
} else if (result === 3) {
errors++;
}
}
}
// if all values are correct and they equal original values then game over and the puzzle has been solved
// if all values are correct and they aren't equal original values then game over but the puzzle has not been solved yet
if (currects === 81) {
gameOn = false;
pauseTimer = true;
document.getElementById("game-difficulty").innerText = "Solved";
clearInterval(intervalId);
alert("Congrats, You solved it.");
} else if (errors === 0 && currects === 0) {
alert(
"Congrats, You solved it, but this is not the solution that I want."
);
}
}
}
// restart game
function restartButtonClick() {
if (gameOn) {
// reset remaining number table
for (var i in remaining) remaining[i] = 9;
// review puzzle
ViewPuzzle(puzzle);
// update remaining numbers table
updateRemainingTable();
// restart the timer
// -1 is because it take 1 sec to update the timer so it will start from 0
timer = -1;
}
}
// surrender
function SurrenderButtonClick() {
if (gameOn) {
// reset remaining number table
for (var i in remaining) remaining[i] = 9;
// review puzzle
ViewPuzzle(solution);
// update remaining numbers table
updateRemainingTable();
// stop the game
gameOn = false;
pauseTimer = true;
clearInterval(intervalId);
// mark game as solved
document.getElementById("game-difficulty").innerText = "Solved";
}
}
// hint
function hintButtonClick() {
if (gameOn) {
// get list of empty cells and list of wrong cells
var empty_cells_list = [];
var wrong_cells_list = [];
for (var i = 0; i < 9; i++) {
for (var j = 0; j < 9; j++) {
var input = table.rows[i].cells[j].getElementsByTagName("input")[0];
if (input.value == "" || input.value.length > 1 || input.value == "0") {
empty_cells_list.push([i, j]);
} else {
if (input.value !== solution[i][j]) wrong_cells_list.push([i, j]);
}
}
}
// check if gird is solved if so stop the game
if (empty_cells_list.length === 0 && wrong_cells_list.length === 0) {
gameOn = false;
pauseTimer = true;
document.getElementById("game-difficulty").innerText = "Solved";
clearInterval(intervalId);
alert("Congrats, You solved it.");
} else {
// add one minute to the stopwatch as a cost for given hint
timer += 60;
// get random cell from empty or wrong list and put the currect value in it
var input;
if (
(Math.random() < 0.5 && empty_cells_list.length > 0) ||
wrong_cells_list.length === 0
) {
var index = Math.floor(Math.random() * empty_cells_list.length);
input = table.rows[empty_cells_list[index][0]].cells[
empty_cells_list[index][1]
].getElementsByTagName("input")[0];
input.oldvalue = input.value;
input.value =
solution[empty_cells_list[index][0]][empty_cells_list[index][1]];
remaining[input.value - 1]--;
} else {
var index = Math.floor(Math.random() * wrong_cells_list.length);
input = table.rows[wrong_cells_list[index][0]].cells[
wrong_cells_list[index][1]
].getElementsByTagName("input")[0];
input.oldvalue = input.value;
remaining[input.value - 1]++;
input.value =
solution[wrong_cells_list[index][0]][wrong_cells_list[index][1]];
remaining[input.value - 1]--;
}
// update remaining numbers table
updateRemainingTable();
}
// make updated cell blinking
var count = 0;
for (var i = 0; i < 6; i++) {
setTimeout(function () {
if (count % 2 == 0) input.classList.add("right-cell");
else input.classList.remove("right-cell");
count++;
}, i * 750);
}
}
}
function showDialogClick(dialogId) {
// to hide navigation bar if it opened
hideHamburgerClick();
var dialog = document.getElementById(dialogId);
var dialogBox = document.getElementById(dialogId + "-box");
dialogBox.focus();
dialog.style.opacity = 0;
dialogBox.style.marginTop = "-500px";
dialog.style.display = "block";
dialog.style.visibility = "visible";
// to view and move the dialog to the correct position after it set visible
setTimeout(function () {
dialog.style.opacity = 1;
dialogBox.style.marginTop = "64px";
}, 200);
}
// show more option menu
function moreOptionButtonClick() {
var moreOptionList = document.getElementById("more-option-list");
// timeout to avoid hide menu immediately in window event
setTimeout(function () {
if (moreOptionList.style.visibility == "hidden") {
moreOptionList.style.visibility = "visible";
setTimeout(function () {
moreOptionList.style.maxWidth = "160px";
moreOptionList.style.minWidth = "160px";
moreOptionList.style.maxHeight = "160px";
moreOptionList.style.opacity = "1";
}, 50);
}
}, 50);
}
function hideDialogButtonClick(dialogId) {
var dialog = document.getElementById(dialogId);
var dialogBox = document.getElementById(dialogId + "-box");
dialog.style.opacity = 0;
dialogBox.style.marginTop = "-500px";
setTimeout(function () {
dialog.style.visibility = "collapse";
//dialog.style.display = "none";
}, 500);
}
// hide hamburger menu when click outside
function hideHamburgerClick() {
var div = document.getElementById("hamburger-menu");
var menu = document.getElementById("nav-menu");
menu.style.left = "-256px";
setTimeout(function () {
div.style.opacity = 0;
//divstyle.display = "none";
div.style.visibility = "collapse";
}, 200);
}
// sudoku solver section
function sudokuSolverMenuClick() {
// hide hamburger menu
hideHamburgerClick();
//stop current game if its running
if (gameOn) {
gameOn = false;
clearInterval(intervalId);
}
solution = [];
canSolved = true;
isSolved = false;
// generate empty grid
var grid = [];
for (var i = 0; i < 9; i++) {
grid.push("");
for (var j = 0; j < 9; j++) {
grid[i] += "0";
}
}
// view empty grid... allow user to edit all cells
ViewPuzzle(grid);
// update remaining table
remaining = [9, 9, 9, 9, 9, 9, 9, 9, 9];
updateRemainingTable();
// show solve and check unique buttons
// hide other buttons
document.getElementById("moreoption-sec").style.display = "none";
document.getElementById("pause-btn").style.display = "none";
document.getElementById("check-btn").style.display = "none";
document.getElementById("isunique-btn").style.display = "block";
document.getElementById("solve-btn").style.display = "block";
// change status card view
// timer for time takes to solve grid
// gameid show text "sudoku solver"
// difficulty show if grid solved is unique
document.getElementById("timer-label").innerText = "Solve time";
document.getElementById("timer").innerText = "00:00";
document.getElementById("game-difficulty-label").innerText = "Is unique";
document.getElementById("game-difficulty").innerText = "Unknown";
document.getElementById("game-number").innerText = "#Soduko_Solver";
//focus first cell
document
.getElementById("puzzle-grid")
.rows[0].cells[0].getElementsByTagName("input")[0]
.focus();
}
function solveButtonClick() {
if (gameOn) {
gameOn = false;
clearInterval(intervalId);
}
var result = solveSudoku(true);
switch (result) {
case 0:
alert("SOLVED");
break;
case 1:
alert("This grid is already solved");
break;
case 2:
alert("This grid can't be solved because of an invalid input");
break;
case 3:
alert("this grid has no solution");
break;
}
}
function isUniqueButtonClick() {
// check if gird is already solved
// if not try to solve it
if (!isSolved) {
if (canSolved) solveSudoku(false);
}
if (!isSolved) {
alert("Can't check this grid because it is unsolvable!");
return;
}
// solve it again but start from the end
var columns = getColumns(puzzle);
var blocks = getBlocks(puzzle);
var solution2 = solveGrid(
generatePossibleNumber(puzzle, columns, blocks),
puzzle,
false
);
// if tow solutions are equals then it is unique and vice versa
var unique = true;
for (var i = 0; i < solution.length; i++) {
for (var j = 0; j < solution[i].length; j++) {
if (solution[i][j] !== solution2[i][j]) {
unique = false;
break;
}
if (!unique) break;
}
}
//display the result
document.getElementById("game-difficulty").innerText = unique ? "Yes" : "No";
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.