├── visualisation.gif ├── README.md ├── index.html ├── style.css └── app.js /visualisation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Karthik-Nayak98/N-queens-visualiser/HEAD/visualisation.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # N-Queen Visualiser 2 | 3 | - The N-Queens puzzle is the problem of placing N chess queens on an N×N chessboard so that no two queens threaten each other. Thus, a solution requires that no two queens share the same row, column, or diagonal. 4 | 5 | - This algorithm is designed using recursion. 6 | 7 | ![N-Queen-visualisation](visualisation.gif) 8 | 9 | **

You can find the website live here

** 10 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | N-Queen-Visualiser 7 | 11 | 12 | 13 | 14 | 15 |
16 |

17 | N-Queens Visualiser 18 |

19 |
20 |
21 |
22 | 23 | 24 |
25 | 26 |
27 | 35 |
36 |
37 | 40 |
41 | 42 |
43 |
44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | margin: 0; 7 | padding: 0; 8 | font-family: Arial, Helvetica, sans-serif; 9 | } 10 | 11 | .header { 12 | position: relative; 13 | top: -20px; 14 | width: 100%; 15 | background-color: #011627; 16 | color: #fdfffc; 17 | } 18 | 19 | .header h2 { 20 | padding: 0.5em; 21 | } 22 | 23 | div.n-queen { 24 | position: absolute; 25 | left: 50%; 26 | transform: translate(-50%, -50%); 27 | width: 70%; 28 | max-width: 450px; 29 | /* border: 1px solid red; */ 30 | } 31 | 32 | .inputbox { 33 | position: relative; 34 | top: 1.5em; 35 | bottom: 2em; 36 | } 37 | 38 | .numberbox { 39 | width: 100%; 40 | font-size: 14px; 41 | padding: 4px; 42 | border: none; 43 | border-bottom: 2px solid #2ec4b6; 44 | outline: none; 45 | background: transparent; 46 | } 47 | 48 | .inputbox label { 49 | position: absolute; 50 | top: 4px; 51 | left: 0px; 52 | color: #2ec4b6; 53 | font-size: 14px; 54 | pointer-events: none; 55 | transition: 0.3s; 56 | } 57 | 58 | .inputbox input:focus ~ label, 59 | .inputbox input:disabled ~ label, 60 | .inputbox input:valid ~ label { 61 | top: -9px; 62 | font-size: 12px; 63 | font-weight: 400; 64 | } 65 | 66 | .slider-container { 67 | position: absolute; 68 | left: 5%; 69 | width: 90%; 70 | /* text-align: center; */ 71 | margin: 0 auto; 72 | top: 4em; 73 | /* border: 2px solid red; */ 74 | } 75 | 76 | .slider { 77 | -webkit-appearance: none; 78 | width: 100%; 79 | margin: 0 auto; 80 | height: 7px; 81 | border-radius: 7px; 82 | background: linear-gradient(90deg, #e8eddf 60%, #e8eddf 60%); 83 | outline: none; 84 | } 85 | 86 | .slider::after { 87 | content: "SLOW"; 88 | position: absolute; 89 | top: -10px; 90 | font-size: 14px; 91 | font-weight: 500; 92 | color: #fa7921; 93 | } 94 | 95 | .slider::before { 96 | content: "FAST"; 97 | position: absolute; 98 | top: -10px; 99 | right: 0px; 100 | font-size: 14px; 101 | font-weight: 500; 102 | color: #fa7921; 103 | } 104 | 105 | /* Google chrome */ 106 | .slider::-webkit-slider-thumb { 107 | -webkit-appearance: none; 108 | width: 20px; 109 | height: 20px; 110 | position: relative; 111 | top: -2px; 112 | cursor: pointer; 113 | background-color: #fa7921; 114 | border-radius: 50%; 115 | z-index: 2; 116 | } 117 | 118 | .slider::-webkit-slider-runnable-track { 119 | -webkit-appearance: none; 120 | height: 15px; 121 | width: 15px; 122 | z-index: 1; 123 | color: #ffba08; 124 | } 125 | 126 | /* Mozilla firefox */ 127 | .slider::-moz-range-thumb { 128 | width: 20px; 129 | height: 20px; 130 | background-color: #fa7921; 131 | cursor: pointer; 132 | position: relative; 133 | top: -2px; 134 | border-radius: 50%; 135 | z-index: 2; 136 | } 137 | 138 | .slider::-webkit-slider-thumb:hover { 139 | box-shadow: 0 0 0 2px white, 0 0 0 4px #fa7921; 140 | } 141 | 142 | #progress-bar { 143 | width: 60%; 144 | height: 7px; 145 | background: #ffd200; 146 | border-radius: 7px; 147 | position: absolute; 148 | top: 7px; 149 | } 150 | 151 | .play-button { 152 | position: relative; 153 | top: 80px; 154 | left: 35%; 155 | border: none; 156 | outline: none; 157 | color: #fdfffc; 158 | width: 80px; 159 | height: 35px; 160 | background-color: #f72585; 161 | border-radius: 10px; 162 | font-size: 16px; 163 | font-weight: 600; 164 | cursor: pointer; 165 | transition: all 0.3s ease-in-out; 166 | /* z-index: 1; */ 167 | } 168 | 169 | .play-button:hover { 170 | opacity: 0.8; 171 | transform: scale(1.05); 172 | } 173 | 174 | .queen-arrangement { 175 | position: relative; 176 | top: 140px; 177 | text-align: center; 178 | font-size: 18px; 179 | font-weight: 500; 180 | color: #247ba0; 181 | } 182 | 183 | #n-queen-board { 184 | position: relative; 185 | display: flex; 186 | width: 80%; 187 | top: 150px; 188 | margin: 0 auto; 189 | flex-wrap: wrap; 190 | justify-content: center; 191 | } 192 | 193 | #n-queen-board div { 194 | position: relative; 195 | display: flex; 196 | justify-content: center; 197 | flex-direction: column; 198 | margin: 0 10px; 199 | box-shadow: 0 4px 8px 0 rgb(0, 0, 0, 0.2); 200 | border-radius: 3px; 201 | bottom: 10px; 202 | } 203 | 204 | table { 205 | position: relative; 206 | border-collapse: collapse; 207 | margin: -10px 10px; 208 | padding: 10px; 209 | margin-bottom: 10px; 210 | align-self: center; 211 | } 212 | 213 | td { 214 | width: 35px; 215 | height: 35px; 216 | text-align: center; 217 | } 218 | 219 | h4 { 220 | position: relative; 221 | top: -5px; 222 | padding: 8px; 223 | width: 95%; 224 | background-color: #0582ca; 225 | align-self: center; 226 | color: #fdfffc; 227 | text-align: center; 228 | border-radius: 4px 4px 0 0; 229 | } 230 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const numberbox = document.getElementById("numberbox"); 3 | const slider = document.getElementById("slider"); 4 | const progressBar = document.getElementById("progress-bar") 5 | const playButton = document.getElementById('play-button'); 6 | const pauseButton = document.getElementById("pause-button"); 7 | 8 | const queen = ''; 9 | 10 | let n, speed, tempSpeed, q, Board = 0; 11 | // Board = 0; 12 | 13 | // Creating array for all the possible arrangements of the N-Queen 14 | let array = [0, 2, 1, 1, 3, 11, 5, 41, 93]; 15 | 16 | // Used to store the state of the boards; 17 | let pos = {}; 18 | // let position = {}; 19 | 20 | 21 | // Setting the slider value onSlide 22 | speed = (100 - slider.value) * 10; 23 | tempSpeed = speed; 24 | slider.oninput = function () { 25 | progressBar.style.width = this.value + "%"; 26 | speed = slider.value; 27 | speed = (100 - speed) * 10; 28 | } 29 | 30 | class Queen { 31 | constructor() { 32 | this.position = Object.assign({}, pos); 33 | // this.Board = 0; 34 | this.uuid = []; 35 | } 36 | 37 | nQueen = async () => { 38 | Board = 0; 39 | this.position[`${Board}`] = {}; 40 | numberbox.disabled = true; 41 | await q.solveQueen(Board, 0, n); 42 | await q.clearColor(Board); 43 | numberbox.disabled = false; 44 | } 45 | 46 | isValid = async (board, r, col, n) => { 47 | //Setting the current box color to orange 48 | const table = document.getElementById(`table-${this.uuid[board]}`); 49 | const currentRow = table.firstChild.childNodes[r]; 50 | const currentColumn = currentRow.getElementsByTagName("td")[col]; 51 | currentColumn.innerHTML = queen; 52 | // currentColumn.style.backgroundColor = "#FF9F1C"; 53 | await q.delay(); 54 | 55 | // Checking the queen in the same column 56 | for (let i = r - 1; i >= 0; --i) { 57 | const row = table.firstChild.childNodes[i]; 58 | const column = row.getElementsByTagName("td")[col]; 59 | 60 | const value = column.innerHTML; 61 | 62 | if (value == queen) { 63 | column.style.backgroundColor = "#FB5607"; 64 | currentColumn.innerHTML = "-" 65 | return false; 66 | } 67 | column.style.backgroundColor = "#ffca3a"; 68 | await q.delay(); 69 | } 70 | 71 | //Checking the upper left diagonal 72 | for (let i = r - 1, j = col - 1; i >= 0 && j >= 0; --i, --j) { 73 | const row = table.firstChild.childNodes[i]; 74 | const column = row.getElementsByTagName("td")[j]; 75 | const value = column.innerHTML; 76 | 77 | if (value == queen) { 78 | column.style.backgroundColor = "#fb5607"; 79 | currentColumn.innerHTML = "-" 80 | return false; 81 | } 82 | column.style.backgroundColor = "#ffca3a"; 83 | await q.delay(); 84 | } 85 | 86 | // Checking the upper right diagonal 87 | for (let i = r - 1, j = col + 1; i >= 0 && j < n; --i, ++j) { 88 | const row = table.firstChild.childNodes[i]; 89 | const column = row.getElementsByTagName("td")[j]; 90 | 91 | const value = column.innerHTML; 92 | 93 | if (value == queen) { 94 | column.style.backgroundColor = "#FB5607"; 95 | currentColumn.innerHTML = "-" 96 | return false; 97 | } 98 | column.style.backgroundColor = "#ffca3a"; 99 | await q.delay(); 100 | } 101 | return true; 102 | } 103 | 104 | clearColor = async (board) => { 105 | for (let j = 0; j < n; ++j) { 106 | const table = document.getElementById(`table-${this.uuid[board]}`); 107 | const row = table.firstChild.childNodes[j]; 108 | for (let k = 0; k < n; ++k) 109 | (j + k) & 1 110 | ? (row.getElementsByTagName("td")[k].style.backgroundColor = "#FF9F1C") 111 | : (row.getElementsByTagName("td")[k].style.backgroundColor = "#FCCD90"); 112 | } 113 | } 114 | 115 | delay = async () => { 116 | await new Promise((done) => setTimeout(() => done(), speed)); 117 | } 118 | 119 | solveQueen = async (board, r, n) => { 120 | if (r == n) { 121 | ++Board; 122 | let table = document.getElementById(`table-${this.uuid[Board]}`); 123 | for (let k = 0; k < n; ++k) { 124 | let row = table.firstChild.childNodes[k]; 125 | row.getElementsByTagName("td")[this.position[board][k]].innerHTML = queen; 126 | } 127 | this.position[Board] = this.position[board]; 128 | return; 129 | } 130 | 131 | for (let i = 0; i < n; ++i) { 132 | await q.delay(); 133 | // console.log("outside:" + board); 134 | await q.clearColor(board); 135 | if (await q.isValid(board, r, i, n)) { 136 | await q.delay(); 137 | // console.log("inside:" + board) 138 | await q.clearColor(board); 139 | let table = document.getElementById(`table-${this.uuid[board]}`); 140 | let row = table.firstChild.childNodes[r]; 141 | row.getElementsByTagName("td")[i].innerHTML = queen; 142 | 143 | this.position[board][r] = i; 144 | 145 | if (await q.solveQueen(board, r + 1, n)) 146 | await q.clearColor(board); 147 | 148 | await q.delay(); 149 | board = Board; 150 | // console.log(this.Board) 151 | table = document.getElementById(`table-${this.uuid[board]}`); 152 | // console.log(JSON.parse(JSON.stringify(table))); 153 | row = table.firstChild.childNodes[r]; 154 | row.getElementsByTagName("td")[i].innerHTML = "-"; 155 | 156 | delete this.position[`${board}`][`${r}`]; 157 | } 158 | } 159 | } 160 | } 161 | 162 | playButton.onclick = async function visualise() { 163 | const chessBoard = document.getElementById("n-queen-board"); 164 | const arrangement = document.getElementById("queen-arrangement"); 165 | 166 | n = numberbox.value; 167 | q = new Queen(); 168 | 169 | if (n > 8) { 170 | numberbox.value = ""; 171 | alert("Queen value is too large"); 172 | return; 173 | } else if (n < 1) { 174 | numberbox.value = ""; 175 | alert("Queen value is too small"); 176 | return; 177 | } 178 | 179 | // Removing all the of previous execution context 180 | while (chessBoard.hasChildNodes()) { 181 | chessBoard.removeChild(chessBoard.firstChild); 182 | } 183 | if (arrangement.hasChildNodes()) { 184 | arrangement.removeChild(arrangement.lastChild) 185 | } 186 | 187 | const para = document.createElement("p"); 188 | para.setAttribute("class", "queen-info"); 189 | para.innerHTML = `For ${n}x${n} board, ${array[n] - 1} arrangements are possible.`; 190 | arrangement.appendChild(para); 191 | 192 | //Adding boards to the Div 193 | if (chessBoard.childElementCount === 0) { 194 | for (let i = 0; i < array[n]; ++i) { 195 | q.uuid.push(Math.random()); 196 | let div = document.createElement('div'); 197 | let table = document.createElement('table'); 198 | let header = document.createElement('h4'); 199 | // div.setAttribute("id", `div-${100 + uuid[i]}`) 200 | header.innerHTML = `Board ${i + 1} ` 201 | table.setAttribute("id", `table-${q.uuid[i]}`); 202 | header.setAttribute("id", `paragraph-${i}`); 203 | chessBoard.appendChild(div); 204 | div.appendChild(header); 205 | div.appendChild(table); 206 | } 207 | } 208 | 209 | for (let k = 0; k < array[n]; ++k) { 210 | let table = document.getElementById(`table-${q.uuid[k]}`); 211 | for (let i = 0; i < n; ++i) { 212 | const row = table.insertRow(i); // inserting ith row 213 | row.setAttribute("id", `Row${i} `); 214 | for (let j = 0; j < n; ++j) { 215 | const col = row.insertCell(j); // inserting jth column 216 | (i + j) & 1 217 | ? (col.style.backgroundColor = "#FF9F1C") 218 | : (col.style.backgroundColor = "#FCCD90"); 219 | col.innerHTML = "-"; 220 | col.style.border = "0.3px solid #373f51"; 221 | } 222 | } 223 | await q.clearColor(k); 224 | } 225 | await q.nQueen(); 226 | }; 227 | --------------------------------------------------------------------------------