Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Aimen-prog committed Sep 29, 2023
0 parents commit 52a7ea3
Show file tree
Hide file tree
Showing 21 changed files with 423 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/sudokuSolver-main.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added __pycache__/backtracking.cpython-38.pyc
Binary file not shown.
Binary file added __pycache__/bruteForce.cpython-38.pyc
Binary file not shown.
Binary file added __pycache__/main.cpython-38.pyc
Binary file not shown.
Binary file added __pycache__/methods.cpython-38.pyc
Binary file not shown.
40 changes: 40 additions & 0 deletions backtracking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
class Backtracking:

def __init__(self, grid):
self.grid = grid

@staticmethod
def isEmpty(grid):
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 0:
return (i, j)

def isValid(self, grid, nb, pos):
for i in range(len(grid)):
if grid[i][pos[1]] == nb and pos[0] != i:
return False
for i in range(len(grid[0])):
if grid[pos[0]][i] == nb and pos[1] != i:
return False
subgrid_col_index = pos[1] // 3
subgrid_row_index = pos[0] // 3
for i in range(subgrid_row_index * 3, subgrid_row_index * 3 + 3):
for j in range(subgrid_col_index * 3, subgrid_col_index * 3 + 3):
if grid[i][j] == nb and (i, j) != pos:
return False
return True

def solve(self, grid):
empty = self.isEmpty(grid)
if not empty:
return True
else:
row, col = empty
for i in range(1, 10):
if self.isValid(grid, i, (row, col)):
grid[row][col] = i
if self.solve(grid):
return True
grid[row][col] = 0
return False
52 changes: 52 additions & 0 deletions benchmarking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import os, time
import numpy as np
from backtracking import Backtracking
from bruteForce import BruteForce

def file_holder(file_name):
with open(file_name, 'r') as f:
file = f.read()
file = file.replace(' ', '').replace('\n', '').replace('_', "0")
return (np.array(list(file)).astype(int)).reshape((9, 9))
def benchmark_all_puzzles():
puzzle_directory = "./sudoku_puzzles"
puzzle_files = os.listdir(puzzle_directory)
brute_force_times = []
backtracking_times = []

for puzzle_file in puzzle_files:
puzzle_path = os.path.join(puzzle_directory, puzzle_file)

if os.path.isfile(puzzle_path):
sudoku = file_holder(puzzle_path)
back_or_brute = input("Select 1 for the Brute Force solution or 2 for the Backtrack solution: ")

if back_or_brute == '1':
solver = BruteForce(sudoku)
else:
solver = Backtracking(sudoku)

start_time = time.time()
if solver.solve(sudoku):
end_time = time.time()
execution_time = end_time - start_time

print(f"Solved {puzzle_file} in {execution_time} seconds")

if back_or_brute == '1':
brute_force_times.append(execution_time)
else:
backtracking_times.append(execution_time)
else:
print(f"No solution found for {puzzle_file}")
#calculate and print average execution times for all puzzles
if brute_force_times:
avg_brute_force_time = sum(brute_force_times) / len(brute_force_times)
print(f"Average Brute Force execution time: {avg_brute_force_time} seconds")

if backtracking_times:
avg_backtracking_time = sum(backtracking_times) / len(backtracking_times)
print(f"Average Backtracking execution time: {avg_backtracking_time} seconds")


benchmark_all_puzzles()
39 changes: 39 additions & 0 deletions bruteForce.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

class BruteForce:
def __init__(self, grid):
self.grid = grid
self.counter = 0

def solve(self, grid):
for i in range(9):
for j in range(9):
if grid[i][j] == 0:
for k in range(1, 10):
if self.check(grid, i, j, k):
grid[i][j] = k
self.counter += 1
if self.solve(grid):
return True
else:
grid[i][j] = 0
self.counter -= 1
return False
return True

def check(self, grid, row, column, num):
if num in grid[row]:
return False
for i in range(9):
if grid[i][column] == num:
return False

x = (row - (row % 3))
y = (column - (column % 3))

for i in range(3):
for j in range(3):
if (i, j) == (row, column):
continue
if grid[x + j][y + i] == num:
return False
return True
66 changes: 66 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import os
import numpy as np
from backtracking import Backtracking
from bruteForce import BruteForce


def file_holder(file_name):
with open(file_name, 'r') as f:
file = f.read()
file = file.replace(' ', '').replace('\n', '').replace('_', "0")
return (np.array(list(file)).astype(int)).reshape((9, 9))


def get_coordinates(grid):
coordinates = []
for i in range(len(grid)):
for j in range(len(grid[i])):
if grid[i][j] > 0:
coordinates.append((i, j))
return coordinates


def print_grid(grid, coordinates):
hsep = "\033[34m" + " _______________________" + "\033[0m"
vsep = "\033[34m" + "|" + "\033[0m"
print(hsep)
for i in range(len(grid)):
print(vsep, end=" ")
for j in range(len(grid[i])):
current = str(grid[i][j])
if (i, j) in coordinates:
current = f"\033[32m{current}\033[0m" # Set text color to green
if j % 3 == 0 and j != 0:
print(vsep, end=" ")
print(current, end=" ")
print(vsep, end=" ")
print("")
if i != 8 and i % 3 == 2:
print(hsep)
return hsep


def execute():
while True:
file_name = input("Please enter a valid file (.txt): ")
if os.path.exists(file_name):
sudoku = file_holder(file_name)
coordinates = get_coordinates(sudoku)
# Use Brute Force or Backtracking solver
back_or_brute = input("Select 1 for the Brute Force solution or 2 for the Backtrack solution: ")
if back_or_brute == 1:
solver = BruteForce(sudoku)
else:
solver = Backtracking(sudoku)
if solver.solve(sudoku):
print(print_grid(solver.grid, coordinates))
else:
print("No solution found.")
choice = input("Do you want to solve another one? (y/n) ")
if choice.lower() not in ['y', 'yes']:
print("See ya!")
break

execute()


102 changes: 102 additions & 0 deletions pygame_sudoku.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import pygame
import os
import numpy as np
from backtracking import Backtracking
from bruteForce import BruteForce
import tkinter as tk
from tkinter import filedialog, simpledialog

def file_holder(file_name):
with open(file_name, 'r') as f:
file = f.read()
file = file.replace(' ', '').replace('\n', '').replace('_', "0")
return (np.array(list(file)).astype(int)).reshape((9, 9))


def get_coordinates(grid):
coordinates = []
for i in range(len(grid)):
for j in range(len(grid[i])):
if grid[i][j] > 0:
coordinates.append((i, j))
return coordinates

## initialize Pygame
pygame.init()
WIDTH, HEIGHT = 600, 600
GRID_SIZE = 9
CELL_SIZE = WIDTH // GRID_SIZE
FPS = 60
WHITE = (255, 255, 255)
FONT_SIZE = 36

#create a Pygame window
window = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Sudoku Solver")
font = pygame.font.Font(None, FONT_SIZE)

def draw_grid(grid, coordinates):
window.fill(WHITE)
for i in range(GRID_SIZE):
for j in range(GRID_SIZE):
x = j * CELL_SIZE
y = i * CELL_SIZE
pygame.draw.rect(window, (0, 0, 0), (x, y, CELL_SIZE, CELL_SIZE), 1)

if grid[i][j] != 0:
text = font.render(str(grid[i][j]), True, (0, 0, 0))
text_rect = text.get_rect(center=(x + CELL_SIZE // 2, y + CELL_SIZE // 2))
window.blit(text, text_rect)

# Highlight the given coordinates
for coord in coordinates:
i, j = coord
pygame.draw.rect(window, (0, 255, 0), (j * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE), 2)

pygame.display.flip()

def brute_or_backtrack():
root = tk.Tk()
root.withdraw()
choice = simpledialog.askstring("Solving Method", "Enter 1 for the Brute Force solution or 2 for the Backtrack solution:")
try:
choice = int(choice)
if choice == 1 or choice == 2:
return choice
else:
raise ValueError("Invalid choice")
except (ValueError, TypeError):
return None

def execute():
# Create a Tkinter root window (it will be hidden)
root = tk.Tk()
root.withdraw() # Hide the main root window

# Use a file dialog to select a file
file_name = filedialog.askopenfilename(filetypes=[("Text Files", "*.txt")])

if file_name:
if os.path.exists(file_name):
sudoku = file_holder(file_name)
coordinates = get_coordinates(sudoku)

solver_choice = brute_or_backtrack()

if solver_choice == 1:
solver = BruteForce(sudoku)
else:
solver = Backtracking(sudoku)

running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if solver.solve(sudoku):
draw_grid(solver.grid, coordinates)

if __name__ == "__main__":
pygame.init()
execute()
pygame.quit()
9 changes: 9 additions & 0 deletions sudoku1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
_729___3_
__1__6_8_
____4__6_
96___41_8
_487_5_96
__56_8__3
___4_2_1_
85__6_327
1__85____
Loading

0 comments on commit 52a7ea3

Please sign in to comment.