├── 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 | 
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 |
20 |
21 |
22 |
23 | Enter total Queens
24 |
25 |
26 |
37 |
38 | Play
39 |
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 |
--------------------------------------------------------------------------------