Skip to content

Commit 18fde43

Browse files
Uploaded Sudoku solver
1 parent d31cb53 commit 18fde43

File tree

9 files changed

+428
-0
lines changed

9 files changed

+428
-0
lines changed

Sudoku-Solver/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Dhruv Panchal
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Sudoku-Solver/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<h1>A Sudoku Solver using Python.</h1>
2+
3+
Run the SudokuGUI file directly in your Terminal using
4+
5+
--> python SudokuGUI.py
6+
or
7+
--> python3 SudokuGUI.py

Sudoku-Solver/SudokuGUI.py

Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
from sudokutools import valid, solve, find_empty
4+
from copy import deepcopy
5+
from sys import exit
6+
import pygame
7+
import time
8+
import random
9+
pygame.init()
10+
11+
12+
def generate():
13+
14+
while True:
15+
for event in pygame.event.get():
16+
if event.type == pygame.QUIT:
17+
exit()
18+
board = [[0 for i in range(9)] for j in range(9)]
19+
20+
for i in range(9):
21+
for j in range(9):
22+
if random.randint(1, 10) >= 5:
23+
board[i][j] = random.randint(1, 9)
24+
if valid(board, (i, j), board[i][j]):
25+
continue
26+
else:
27+
board[i][j] = 0
28+
partialBoard = deepcopy(board)
29+
if solve(board):
30+
return partialBoard
31+
32+
33+
class Board:
34+
35+
def __init__(self, window):
36+
self.board = generate()
37+
self.solvedBoard = deepcopy(self.board)
38+
solve(self.solvedBoard)
39+
self.tiles = [[Tile(self.board[i][j], window, i * 60, j * 60)
40+
for j in range(9)] for i in range(9)]
41+
self.window = window
42+
43+
def draw_board(self):
44+
45+
for i in range(9):
46+
for j in range(9):
47+
if j % 3 == 0 and j != 0:
48+
pygame.draw.line(self.window, (0, 0, 0), (j // 3
49+
* 180, 0), (j // 3 * 180, 540), 4)
50+
51+
if i % 3 == 0 and i != 0:
52+
pygame.draw.line(self.window, (0, 0, 0), (0, i // 3
53+
* 180), (540, i // 3 * 180), 4)
54+
55+
self.tiles[i][j].draw((0, 0, 0), 1)
56+
57+
if self.tiles[i][j].value != 0:
58+
self.tiles[i][j].display(self.tiles[i][j].value,
59+
(21 + j * 60, 16 + i * 60), (0, 0, 0))
60+
61+
62+
pygame.draw.line(self.window, (0, 0, 0), (0, (i + 1) // 3
63+
* 180), (540, (i + 1) // 3 * 180), 4)
64+
65+
def deselect(self, tile):
66+
67+
for i in range(9):
68+
for j in range(9):
69+
if self.tiles[i][j] != tile:
70+
self.tiles[i][j].selected = False
71+
72+
def redraw(
73+
self,
74+
keys,
75+
wrong,
76+
time,
77+
):
78+
79+
self.window.fill((255, 255, 255))
80+
self.draw_board()
81+
for i in range(9):
82+
for j in range(9):
83+
if self.tiles[j][i].selected:
84+
self.tiles[j][i].draw((50, 205, 50), 4)
85+
elif self.tiles[i][j].correct:
86+
87+
self.tiles[j][i].draw((34, 139, 34), 4)
88+
elif self.tiles[i][j].incorrect:
89+
90+
self.tiles[j][i].draw((255, 0, 0), 4)
91+
92+
if len(keys) != 0:
93+
for value in keys:
94+
self.tiles[value[0]][value[1]].display(keys[value], (21
95+
+ value[0] * 60, 16 + value[1] * 60), (128,
96+
128, 128))
97+
98+
if wrong > 0:
99+
font = pygame.font.SysFont('Bauhaus 93', 30)
100+
text = font.render('X', True, (255, 0, 0))
101+
self.window.blit(text, (10, 554))
102+
103+
font = pygame.font.SysFont('Bahnschrift', 40)
104+
text = font.render(str(wrong), True, (0, 0, 0))
105+
self.window.blit(text, (32, 542))
106+
107+
font = pygame.font.SysFont('Bahnschrift', 40)
108+
text = font.render(str(time), True, (0, 0, 0))
109+
self.window.blit(text, (388, 542))
110+
pygame.display.flip()
111+
112+
def visualSolve(self, wrong, time):
113+
114+
for event in pygame.event.get():
115+
if event.type == pygame.QUIT:
116+
exit()
117+
118+
empty = find_empty(self.board)
119+
if not empty:
120+
return True
121+
122+
for nums in range(9):
123+
if valid(self.board, (empty[0], empty[1]), nums + 1):
124+
self.board[empty[0]][empty[1]] = nums + 1
125+
self.tiles[empty[0]][empty[1]].value = nums + 1
126+
self.tiles[empty[0]][empty[1]].correct = True
127+
pygame.time.delay(63)
128+
self.redraw({}, wrong, time)
129+
130+
if self.visualSolve(wrong, time):
131+
return True
132+
133+
self.board[empty[0]][empty[1]] = 0
134+
self.tiles[empty[0]][empty[1]].value = 0
135+
self.tiles[empty[0]][empty[1]].incorrect = True
136+
self.tiles[empty[0]][empty[1]].correct = False
137+
pygame.time.delay(63)
138+
self.redraw({}, wrong, time)
139+
140+
def hint(self, keys):
141+
142+
while True:
143+
i = random.randint(0, 8)
144+
j = random.randint(0, 8)
145+
if self.board[i][j] == 0:
146+
if (j, i) in keys:
147+
del keys[(j, i)]
148+
self.board[i][j] = self.solvedBoard[i][j]
149+
self.tiles[i][j].value = self.solvedBoard[i][j]
150+
return True
151+
elif self.board == self.solvedBoard:
152+
153+
return False
154+
155+
156+
class Tile:
157+
158+
159+
def __init__(
160+
self,
161+
value,
162+
window,
163+
x1,
164+
y1,
165+
):
166+
self.value = value
167+
self.window = window
168+
self.rect = pygame.Rect(x1, y1, 60, 60)
169+
self.selected = False
170+
self.correct = False
171+
self.incorrect = False
172+
173+
def draw(self, color, thickness):
174+
175+
pygame.draw.rect(self.window, color, self.rect, thickness)
176+
177+
def display(
178+
self,
179+
value,
180+
position,
181+
color,
182+
):
183+
184+
font = pygame.font.SysFont('lato', 45)
185+
text = font.render(str(value), True, color)
186+
self.window.blit(text, position)
187+
188+
def clicked(self, mousePos):
189+
190+
if self.rect.collidepoint(mousePos):
191+
self.selected = True
192+
return self.selected
193+
194+
195+
def main():
196+
197+
screen = pygame.display.set_mode((540, 590))
198+
screen.fill((255, 255, 255))
199+
pygame.display.set_caption('Sudoku Solver')
200+
icon = pygame.image.load('assets/thumbnail.png')
201+
pygame.display.set_icon(icon)
202+
203+
font = pygame.font.SysFont('Bahnschrift', 40)
204+
text = font.render('Generating', True, (0, 0, 0))
205+
screen.blit(text, (175, 245))
206+
207+
font = pygame.font.SysFont('Bahnschrift', 40)
208+
text = font.render('Random Grid', True, (0, 0, 0))
209+
screen.blit(text, (156, 290))
210+
pygame.display.flip()
211+
212+
wrong = 0
213+
board = Board(screen)
214+
selected = (-1, -1)
215+
keyDict = {}
216+
running = True
217+
startTime = time.time()
218+
while running:
219+
elapsed = time.time() - startTime
220+
passedTime = time.strftime('%H:%M:%S', time.gmtime(elapsed))
221+
222+
if board.board == board.solvedBoard:
223+
for i in range(9):
224+
for j in range(9):
225+
board.tiles[i][j].selected = False
226+
running = False
227+
228+
for event in pygame.event.get():
229+
if event.type == pygame.QUIT:
230+
exit()
231+
elif event.type == pygame.MOUSEBUTTONUP:
232+
233+
mousePos = pygame.mouse.get_pos()
234+
for i in range(9):
235+
for j in range(9):
236+
if board.tiles[i][j].clicked(mousePos):
237+
selected = (i, j)
238+
board.deselect(board.tiles[i][j])
239+
elif event.type == pygame.KEYDOWN:
240+
241+
if board.board[selected[1]][selected[0]] == 0 \
242+
and selected != (-1, -1):
243+
if event.key == pygame.K_1:
244+
keyDict[selected] = 1
245+
246+
if event.key == pygame.K_2:
247+
keyDict[selected] = 2
248+
249+
if event.key == pygame.K_3:
250+
keyDict[selected] = 3
251+
252+
if event.key == pygame.K_4:
253+
keyDict[selected] = 4
254+
255+
if event.key == pygame.K_5:
256+
keyDict[selected] = 5
257+
258+
if event.key == pygame.K_6:
259+
keyDict[selected] = 6
260+
261+
if event.key == pygame.K_7:
262+
keyDict[selected] = 7
263+
264+
if event.key == pygame.K_8:
265+
keyDict[selected] = 8
266+
267+
if event.key == pygame.K_9:
268+
keyDict[selected] = 9
269+
elif event.key == pygame.K_BACKSPACE or event.key \
270+
== pygame.K_DELETE:
271+
272+
if selected in keyDict:
273+
board.tiles[selected[1]][selected[0]].value = \
274+
0
275+
del keyDict[selected]
276+
elif event.key == pygame.K_RETURN:
277+
278+
if selected in keyDict:
279+
if keyDict[selected] \
280+
!= board.solvedBoard[selected[1]][selected[0]]:
281+
wrong += 1
282+
board.tiles[selected[1]][selected[0]].value = \
283+
0
284+
del keyDict[selected]
285+
break
286+
287+
board.tiles[selected[1]][selected[0]].value = \
288+
keyDict[selected]
289+
board.board[selected[1]][selected[0]] = \
290+
keyDict[selected]
291+
del keyDict[selected]
292+
293+
if event.key == pygame.K_h:
294+
board.hint(keyDict)
295+
296+
if event.key == pygame.K_SPACE:
297+
for i in range(9):
298+
for j in range(9):
299+
board.tiles[i][j].selected = False
300+
keyDict = {}
301+
board.visualSolve(wrong, passedTime)
302+
for i in range(9):
303+
for j in range(9):
304+
board.tiles[i][j].correct = False
305+
board.tiles[i][j].incorrect = False
306+
running = False
307+
308+
board.redraw(keyDict, wrong, passedTime)
309+
while True:
310+
for event in pygame.event.get():
311+
if event.type == pygame.QUIT:
312+
return
313+
314+
315+
main()
316+
pygame.quit()
Binary file not shown.
162 KB
Loading

Sudoku-Solver/assets/Visualizer.gif

486 KB
Loading

Sudoku-Solver/assets/thumbnail.png

33.7 KB
Loading

Sudoku-Solver/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pygame==2.0.1

0 commit comments

Comments
 (0)