Skip to content

Commit 7a8c111

Browse files
authored
Merge pull request #1805 from smty2018/master
[GSSOC'23]Sudoku Game
2 parents d8a3794 + 08b43dc commit 7a8c111

File tree

2 files changed

+244
-0
lines changed

2 files changed

+244
-0
lines changed

Sudoku_Game/READ_ME.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Sudoku Game
2+
The Sudoku game in Python.
3+
4+
Rules of the Game
5+
Sudoku is a number placement puzzle game that is played on a 9x9 grid. The goal of the game is to fill in the empty cells of the grid with numbers from 1 to 9, such that each column, each row, and each of the nine 3x3 sub-grids (also called "boxes" or "regions") contains all of the numbers from 1 to 9 without repetition.
6+
7+
The rules of Sudoku are as follows:
8+
9+
Each row must contain all numbers from 1 to 9 without repetition.
10+
Each column must contain all numbers from 1 to 9 without repetition.
11+
Each 3x3 sub-grid (box) must contain all numbers from 1 to 9 without repetition.
12+
The puzzle initially provides some numbers (called "givens") as clues. These numbers cannot be changed.
13+
The player's task is to fill in the remaining empty cells with numbers from 1 to 9, following the rules above.
14+
15+
Opening the game:
16+
Clone the repository or download the sudoku.py file.
17+
Open the file in a Python environment (e.g., IDLE, Jupyter Notebook, or any text editor with Python support).
18+
Run the script to start the game.
19+
20+
Requirements:
21+
import tkinter as tk
22+
from tkinter import messagebox,simpledialog
23+
import random
24+
25+
26+
Instructions to Play
27+
1. Run the game.Maximize the window.
28+
2. Select the level ("Easy","Medium","Hard") from the select level drop down. The grid will appear
29+
3. Select the cell you want to input. ("Input from 1-9")
30+
4. Finish Solving the puzzle and check your answer.
31+
5. Stuck at a particular stage? Use Solve button to view the solution
32+
6. You can use the new game button to create a new puzzle.
33+
34+
Screenshots:![Screenshot 2023-06-14 151023](https://github.com/smty2018/Amazing-Python-Scripts/assets/74114936/ba3f4aa4-277f-4458-acb3-c148d57dd5f9)
35+
![Screenshot 2023-06-14 151045](https://github.com/smty2018/Amazing-Python-Scripts/assets/74114936/ed63d309-1292-421c-8c84-02d1f9ea7ab8)
36+
![Screenshot 2023-06-14 171242](https://github.com/smty2018/Amazing-Python-Scripts/assets/74114936/b66a8f2f-c0b7-4916-a11d-eb4783cf7813)

Sudoku_Game/sudoku.py

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import tkinter as tk
2+
from tkinter import messagebox,simpledialog
3+
import random
4+
5+
6+
class Sudoku:
7+
def __init__(self, master):
8+
self.master = master
9+
self.board = [[0] * 9 for _ in range(9)]
10+
self.solution = [[num for num in row] for row in self.board]
11+
self.empty_cells = self.get_empty_cells(self.board)
12+
self.create_widgets()
13+
14+
def create_widgets(self):
15+
self.master.configure(bg='#ECECEC')
16+
self.canvas = tk.Canvas(self.master, width=680, height=680, bg='#F8C8DC', highlightthickness=0)
17+
self.canvas.pack(side=tk.TOP, padx=0, pady=0)
18+
19+
self.draw_board()
20+
21+
self.button_frame = tk.Frame(self.master, bg='#ECECEC')
22+
self.button_frame.pack(side=tk.TOP, pady=20)
23+
24+
self.check_button = tk.Button(self.button_frame, text='Check', font=('Inter', 12, 'bold'),
25+
bg='#E75442', fg='#FFFFFF', bd=0, command=self.check_solution)
26+
self.check_button.pack(side=tk.LEFT, padx=10)
27+
28+
self.solve_button = tk.Button(self.button_frame, text='Solve', font=('Inter', 12, 'bold'),
29+
bg='#3AC6FF', fg='#FFFFFF', bd=0, command=self.solve_puzzle)
30+
self.solve_button.pack(side=tk.LEFT, padx=10)
31+
32+
self.level_frame = tk.Frame(self.master, bg='#ECECEC')
33+
self.level_frame.pack(side=tk.TOP, pady=0)
34+
35+
self.level_label = tk.Label(self.level_frame, text='Select Level:', font=('Inter', 12,"bold"), bg='#77DD77', fg='#ECECEC')
36+
self.level_label.pack(side=tk.LEFT, padx=10)
37+
38+
self.level_var = tk.StringVar()
39+
self.level_var.set('Easy')
40+
self.level_dropdown = tk.OptionMenu(self.level_frame, self.level_var, 'Easy', 'Medium', 'Hard',
41+
command=self.new_game)
42+
self.level_dropdown.config(font=('Arial', 12,"bold"), bg='#ffb347', fg='#ECECEC', bd=0)
43+
self.level_dropdown.pack(side=tk.LEFT, padx=10)
44+
45+
self.new_game_button = tk.Button(self.level_frame, text='New Game', font=('Inter', 12, 'bold'),
46+
bg='#FFD700', fg='#ECECEC', bd=0, command=self.new_game_wrapper)
47+
self.new_game_button.pack(side=tk.LEFT, padx=10)
48+
self.canvas.bind("<Button-1>", self.on_cell_click)
49+
50+
51+
def new_game_wrapper(self):
52+
level = self.level_var.get()
53+
self.new_game(level)
54+
55+
def new_game(self, level):
56+
if level == 'Easy':
57+
num_cells = 40
58+
elif level == 'Medium':
59+
num_cells = 50
60+
elif level == 'Hard':
61+
num_cells = 60
62+
63+
self.board = [[0] * 9 for _ in range(9)]
64+
self.generate_puzzle()
65+
self.remove_cells(num_cells)
66+
self.empty_cells = self.get_empty_cells(self.board)
67+
self.draw_board()
68+
69+
def generate_puzzle(self):
70+
self.solve_board(self.board)
71+
for _ in range(81):
72+
row = random.randint(0, 8)
73+
col = random.randint(0, 8)
74+
temp = self.board[row][col]
75+
self.board[row][col] = 0
76+
count = 0
77+
solution_copy = [row[:] for row in self.board]
78+
self.solve_board(solution_copy)
79+
for i in range(9):
80+
if 0 in solution_copy[i]:
81+
count += 1
82+
if count != 1:
83+
self.board[row][col] = temp
84+
85+
def solve_board(self, board):
86+
empty_cell = self.get_empty_cell(board)
87+
if not empty_cell:
88+
return True
89+
90+
row, col = empty_cell
91+
for num in range(1, 10):
92+
if self.is_valid_move(board, row, col, num):
93+
board[row][col] = num
94+
if self.solve_board(board):
95+
return True
96+
board[row][col] = 0
97+
return False
98+
99+
def on_cell_click(self, event):
100+
x, y = event.x, event.y
101+
row, col = (y - 80) // 60, (x - 80) // 60
102+
if self.board[row][col] != 0:
103+
messagebox.showinfo('Invalid Move', 'Cannot change pre-filled cells!')
104+
return
105+
num = tk.simpledialog.askinteger('Input', 'Enter a number (1-9):', minvalue=1, maxvalue=9)
106+
if num:
107+
self.board[row][col] = num
108+
self.draw_board()
109+
110+
111+
def get_empty_cell(self, board):
112+
for i in range(9):
113+
for j in range(9):
114+
if board[i][j] == 0:
115+
return i, j
116+
return None
117+
118+
def is_valid_move(self, board, row, col, num):
119+
return (
120+
self.is_valid_row(board, row, num)
121+
and self.is_valid_col(board, col, num)
122+
and self.is_valid_box(board, row - row % 3, col - col % 3, num)
123+
)
124+
125+
def is_valid_row(self, board, row, num):
126+
for i in range(9):
127+
if board[row][i] == num:
128+
return False
129+
return True
130+
131+
def is_valid_col(self, board, col, num):
132+
for i in range(9):
133+
if board[i][col] == num:
134+
return False
135+
return True
136+
137+
def is_valid_box(self, board, start_row, start_col, num):
138+
for i in range(3):
139+
for j in range(3):
140+
if board[start_row + i][start_col + j] == num:
141+
return False
142+
return True
143+
144+
def draw_board(self):
145+
self.clear_board()
146+
for i in range(9):
147+
for j in range(9):
148+
x = i * 60 + 80
149+
y = j * 60 + 80
150+
cell_value = self.board[j][i]
151+
if cell_value != 0:
152+
# Adjust the coordinates to avoid intersection
153+
text_x = x + 15
154+
text_y = y + 15
155+
self.canvas.create_text(text_x, text_y, text=str(cell_value), font=('Inter', 20, 'bold'), fill='#333333')
156+
157+
self.draw_grid()
158+
159+
def draw_grid(self):
160+
for i in range(10):
161+
if i % 3 == 0:
162+
line_width = 2
163+
else:
164+
line_width = 1
165+
self.canvas.create_line(60 * i + 80, 80, 60 * i + 80, 620, width=line_width, fill='#333333')
166+
self.canvas.create_line(80, 60 * i + 80, 620, 60 * i + 80, width=line_width, fill='#333333')
167+
168+
def clear_board(self):
169+
self.canvas.delete('all')
170+
171+
def check_solution(self):
172+
for i in range(9):
173+
for j in range(9):
174+
if self.board[i][j] != self.solution[i][j]:
175+
messagebox.showinfo('Incorrect', 'The solution is not correct!')
176+
return
177+
messagebox.showinfo('Correct', 'Congratulations! You solved the puzzle!')
178+
179+
def remove_cells(self, num_cells):
180+
cells = [(i, j) for i in range(9) for j in range(9)]
181+
random.shuffle(cells)
182+
for i in range(num_cells):
183+
row, col = cells[i]
184+
self.board[row][col] = 0
185+
186+
def get_empty_cells(self, board):
187+
empty_cells = []
188+
for i in range(9):
189+
for j in range(9):
190+
if board[i][j] == 0:
191+
empty_cells.append((i, j))
192+
return empty_cells
193+
194+
def solve_puzzle(self):
195+
solution_board = [row[:] for row in self.board]
196+
if self.solve_board(solution_board):
197+
self.solution = solution_board
198+
self.board = solution_board
199+
self.draw_board()
200+
else:
201+
messagebox.showinfo('Unsolvable', 'The puzzle does not have a solution.')
202+
203+
204+
if __name__ == '__main__':
205+
root = tk.Tk()
206+
root.title('Sudoku')
207+
gui = Sudoku(root)
208+
root.mainloop()

0 commit comments

Comments
 (0)