|
| 1 | +import tkinter as tk |
| 2 | +import time |
| 3 | +from itertools import product |
| 4 | + |
| 5 | +def is_valid_move(puzzle, row, col, num): |
| 6 | + if num in puzzle[row] or num in [puzzle[i][col] for i in range(9)]: |
| 7 | + return False |
| 8 | + |
| 9 | + subgrid_row, subgrid_col = 3 * (row // 3), 3 * (col // 3) |
| 10 | + for i in range(subgrid_row, subgrid_row + 3): |
| 11 | + for j in range(subgrid_col, subgrid_col + 3): |
| 12 | + if puzzle[i][j] == num: |
| 13 | + return False |
| 14 | + |
| 15 | + return True |
| 16 | + |
| 17 | +def solve_sudoku_csp(puzzle): |
| 18 | + def is_valid_move_with_forward_checking(puzzle, row, col, num): |
| 19 | + if num in puzzle[row] or num in [puzzle[i][col] for i in range(9)]: |
| 20 | + return False |
| 21 | + |
| 22 | + subgrid_row, subgrid_col = 3 * (row // 3), 3 * (col // 3) |
| 23 | + for i in range(subgrid_row, subgrid_row + 3): |
| 24 | + for j in range(subgrid_col, subgrid_col + 3): |
| 25 | + if puzzle[i][j] == num: |
| 26 | + return False |
| 27 | + |
| 28 | + # Check for forward checking in the row |
| 29 | + if any(puzzle[row][c] == num for c in range(9) if c != col and puzzle[row][c] == 0): |
| 30 | + return False |
| 31 | + |
| 32 | + # Check for forward checking in the column |
| 33 | + if any(puzzle[r][col] == num for r in range(9) if r != row and puzzle[r][col] == 0): |
| 34 | + return False |
| 35 | + |
| 36 | + return True |
| 37 | + |
| 38 | + def solve(puzzle): |
| 39 | + for row, col in product(range(9), repeat=2): |
| 40 | + if puzzle[row][col] == 0: |
| 41 | + for num in range(1, 10): |
| 42 | + if is_valid_move_with_forward_checking(puzzle, row, col, num): |
| 43 | + puzzle[row][col] = num |
| 44 | + set_puzzle(puzzle) |
| 45 | + app.update() |
| 46 | + time.sleep(0.1) |
| 47 | + if solve(puzzle): |
| 48 | + return True |
| 49 | + puzzle[row][col] = 0 |
| 50 | + return False |
| 51 | + return True |
| 52 | + |
| 53 | + if solve(puzzle): |
| 54 | + return puzzle |
| 55 | + return None |
| 56 | + |
| 57 | +app = tk.Tk() |
| 58 | +app.title("CSP Sudoku Solver") |
| 59 | + |
| 60 | +sudoku_labels = [[0 for _ in range(9)] for _ in range(9)] |
| 61 | + |
| 62 | +for i in range(9): |
| 63 | + for j in range(9): |
| 64 | + label = tk.Label(app, width=4, height=2, relief="ridge", borderwidth=2) |
| 65 | + label.grid(row=i, column=j, padx=5, pady=5) |
| 66 | + label.config(font=("Arial", 16)) |
| 67 | + sudoku_labels[i][j] = label |
| 68 | + |
| 69 | +# Create bold borders for 3x3 subgrids |
| 70 | +for i in range(0, 9, 3): |
| 71 | + for j in range(0, 9, 3): |
| 72 | + for x in range(3): |
| 73 | + for y in range(3): |
| 74 | + label = sudoku_labels[i + x][j + y] |
| 75 | + label.config(borderwidth=2 if x == 1 and y == 1 else 1) |
| 76 | + |
| 77 | +def set_puzzle(puzzle): |
| 78 | + for i in range(9): |
| 79 | + for j in range(9): |
| 80 | + value = puzzle[i][j] |
| 81 | + label = sudoku_labels[i][j] |
| 82 | + if value == 0: |
| 83 | + label.config(text="", bg="white") |
| 84 | + else: |
| 85 | + label.config(text=str(value), bg="lightgray") |
| 86 | + |
| 87 | +def clear_puzzle(): |
| 88 | + for i in range(9): |
| 89 | + for j in range(9): |
| 90 | + label = sudoku_labels[i][j] |
| 91 | + label.config(text="", bg="white") |
| 92 | + |
| 93 | +clear_button = tk.Button(app, text="Clear", command=clear_puzzle) |
| 94 | +clear_button.grid(row=10, column=4, padx=5, pady=10) |
| 95 | + |
| 96 | +solve_button = tk.Button(app, text="Solve CSP", command=lambda: solve_sudoku_csp(puzzle)) |
| 97 | +solve_button.grid(row=10, column=3, padx=5, pady=10) |
| 98 | + |
| 99 | +puzzle = [ |
| 100 | + [5, 3, 0, 0, 7, 0, 0, 0, 0], |
| 101 | + [6, 0, 0, 1, 9, 5, 0, 0, 0], |
| 102 | + [0, 9, 8, 0, 0, 0, 0, 6, 0], |
| 103 | + [8, 0, 0, 0, 6, 0, 0, 0, 3], |
| 104 | + [4, 0, 0, 8, 0, 3, 0, 0, 1], |
| 105 | + [7, 0, 0, 0, 2, 0, 0, 0, 6], |
| 106 | + [0, 6, 0, 0, 0, 0, 2, 8, 0], |
| 107 | + [0, 0, 0, 4, 1, 9, 0, 0, 5], |
| 108 | + [0, 0, 0, 0, 8, 0, 0, 7, 9] |
| 109 | +] |
| 110 | + |
| 111 | +set_puzzle(puzzle) |
| 112 | + |
| 113 | +app.mainloop() |
0 commit comments