Amazing-Python-Scripts

Форк
0
217 строк · 7.5 Кб
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,
17
                                height=680, bg='#F8C8DC', highlightthickness=0)
18
        self.canvas.pack(side=tk.TOP, padx=0, pady=0)
19

20
        self.draw_board()
21

22
        self.button_frame = tk.Frame(self.master, bg='#ECECEC')
23
        self.button_frame.pack(side=tk.TOP, pady=20)
24

25
        self.check_button = tk.Button(self.button_frame, text='Check', font=('Inter', 12, 'bold'),
26
                                      bg='#E75442', fg='#FFFFFF', bd=0, command=self.check_solution)
27
        self.check_button.pack(side=tk.LEFT, padx=10)
28

29
        self.solve_button = tk.Button(self.button_frame, text='Solve', font=('Inter', 12, 'bold'),
30
                                      bg='#3AC6FF', fg='#FFFFFF', bd=0, command=self.solve_puzzle)
31
        self.solve_button.pack(side=tk.LEFT, padx=10)
32

33
        self.level_frame = tk.Frame(self.master, bg='#ECECEC')
34
        self.level_frame.pack(side=tk.TOP, pady=0)
35

36
        self.level_label = tk.Label(self.level_frame, text='Select Level:', font=(
37
            'Inter', 12, "bold"), bg='#77DD77', fg='#ECECEC')
38
        self.level_label.pack(side=tk.LEFT, padx=10)
39

40
        self.level_var = tk.StringVar()
41
        self.level_var.set('Easy')
42
        self.level_dropdown = tk.OptionMenu(self.level_frame, self.level_var, 'Easy', 'Medium', 'Hard',
43
                                            command=self.new_game)
44
        self.level_dropdown.config(
45
            font=('Arial', 12, "bold"), bg='#ffb347', fg='#ECECEC', bd=0)
46
        self.level_dropdown.pack(side=tk.LEFT, padx=10)
47

48
        self.new_game_button = tk.Button(self.level_frame, text='New Game', font=('Inter', 12, 'bold'),
49
                                         bg='#FFD700', fg='#ECECEC', bd=0, command=self.new_game_wrapper)
50
        self.new_game_button.pack(side=tk.LEFT, padx=10)
51
        self.canvas.bind("<Button-1>", self.on_cell_click)
52

53
    def new_game_wrapper(self):
54
        level = self.level_var.get()
55
        self.new_game(level)
56

57
    def new_game(self, level):
58
        if level == 'Easy':
59
            num_cells = 40
60
        elif level == 'Medium':
61
            num_cells = 50
62
        elif level == 'Hard':
63
            num_cells = 60
64

65
        self.board = [[0] * 9 for _ in range(9)]
66
        self.generate_puzzle()
67
        self.remove_cells(num_cells)
68
        self.empty_cells = self.get_empty_cells(self.board)
69
        self.draw_board()
70

71
    def generate_puzzle(self):
72
        self.solve_board(self.board)
73
        for _ in range(81):
74
            row = random.randint(0, 8)
75
            col = random.randint(0, 8)
76
            temp = self.board[row][col]
77
            self.board[row][col] = 0
78
            count = 0
79
            solution_copy = [row[:] for row in self.board]
80
            self.solve_board(solution_copy)
81
            for i in range(9):
82
                if 0 in solution_copy[i]:
83
                    count += 1
84
            if count != 1:
85
                self.board[row][col] = temp
86

87
    def solve_board(self, board):
88
        empty_cell = self.get_empty_cell(board)
89
        if not empty_cell:
90
            return True
91

92
        row, col = empty_cell
93
        for num in range(1, 10):
94
            if self.is_valid_move(board, row, col, num):
95
                board[row][col] = num
96
                if self.solve_board(board):
97
                    return True
98
                board[row][col] = 0
99
        return False
100

101
    def on_cell_click(self, event):
102
        x, y = event.x, event.y
103
        row, col = (y - 80) // 60, (x - 80) // 60
104
        if self.board[row][col] != 0:
105
            messagebox.showinfo(
106
                'Invalid Move', 'Cannot change pre-filled cells!')
107
            return
108
        num = tk.simpledialog.askinteger(
109
            'Input', 'Enter a number (1-9):', minvalue=1, maxvalue=9)
110
        if num:
111
            self.board[row][col] = num
112
            self.draw_board()
113

114
    def get_empty_cell(self, board):
115
        for i in range(9):
116
            for j in range(9):
117
                if board[i][j] == 0:
118
                    return i, j
119
        return None
120

121
    def is_valid_move(self, board, row, col, num):
122
        return (
123
            self.is_valid_row(board, row, num)
124
            and self.is_valid_col(board, col, num)
125
            and self.is_valid_box(board, row - row % 3, col - col % 3, num)
126
        )
127

128
    def is_valid_row(self, board, row, num):
129
        for i in range(9):
130
            if board[row][i] == num:
131
                return False
132
        return True
133

134
    def is_valid_col(self, board, col, num):
135
        for i in range(9):
136
            if board[i][col] == num:
137
                return False
138
        return True
139

140
    def is_valid_box(self, board, start_row, start_col, num):
141
        for i in range(3):
142
            for j in range(3):
143
                if board[start_row + i][start_col + j] == num:
144
                    return False
145
        return True
146

147
    def draw_board(self):
148
        self.clear_board()
149
        for i in range(9):
150
            for j in range(9):
151
                x = i * 60 + 80
152
                y = j * 60 + 80
153
                cell_value = self.board[j][i]
154
                if cell_value != 0:
155
                    # Adjust the coordinates to avoid intersection
156
                    text_x = x + 15
157
                    text_y = y + 15
158
                    self.canvas.create_text(text_x, text_y, text=str(
159
                        cell_value), font=('Inter', 20, 'bold'), fill='#333333')
160

161
        self.draw_grid()
162

163
    def draw_grid(self):
164
        for i in range(10):
165
            if i % 3 == 0:
166
                line_width = 2
167
            else:
168
                line_width = 1
169
            self.canvas.create_line(
170
                60 * i + 80, 80, 60 * i + 80, 620, width=line_width, fill='#333333')
171
            self.canvas.create_line(
172
                80, 60 * i + 80, 620, 60 * i + 80, width=line_width, fill='#333333')
173

174
    def clear_board(self):
175
        self.canvas.delete('all')
176

177
    def check_solution(self):
178
        for i in range(9):
179
            for j in range(9):
180
                if self.board[i][j] != self.solution[i][j]:
181
                    messagebox.showinfo(
182
                        'Incorrect', 'The solution is not correct!')
183
                    return
184
        messagebox.showinfo(
185
            'Correct', 'Congratulations! You solved the puzzle!')
186

187
    def remove_cells(self, num_cells):
188
        cells = [(i, j) for i in range(9) for j in range(9)]
189
        random.shuffle(cells)
190
        for i in range(num_cells):
191
            row, col = cells[i]
192
            self.board[row][col] = 0
193

194
    def get_empty_cells(self, board):
195
        empty_cells = []
196
        for i in range(9):
197
            for j in range(9):
198
                if board[i][j] == 0:
199
                    empty_cells.append((i, j))
200
        return empty_cells
201

202
    def solve_puzzle(self):
203
        solution_board = [row[:] for row in self.board]
204
        if self.solve_board(solution_board):
205
            self.solution = solution_board
206
            self.board = solution_board
207
            self.draw_board()
208
        else:
209
            messagebox.showinfo(
210
                'Unsolvable', 'The puzzle does not have a solution.')
211

212

213
if __name__ == '__main__':
214
    root = tk.Tk()
215
    root.title('Sudoku')
216
    gui = Sudoku(root)
217
    root.mainloop()
218

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.