Skip to content

Commit

Permalink
added doc
Browse files Browse the repository at this point in the history
  • Loading branch information
Aimen-prog committed Oct 1, 2023
1 parent 547f316 commit d318002
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 5 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,19 @@ Soduku Solver
**About this repository**
<br>
Sudoku Solver using backtracking and brute forcing - LaPlateforme Formation
<hr>
Backtracking approach:
Starts by finding the first empty cell in the grid and tries to place numbers
from 1 to 9 in that cell while checking if the placement is valid according to
Sudoku rules (no duplicates in the same row, column, or 3x3 subgrid). If a valid
placement is found, the method recursively attempts to solve the remaining puzzle.

<br>
Brute Force approach:
Iterates through the Sudoku grid, attempting to place numbers from 1 to 9
at empty cells while checking if the placement is valid. If a valid placement is found,
it continues solving the puzzle recursively.
<hr>

**Get started**

Expand Down
Binary file modified __pycache__/backtracking.cpython-38.pyc
Binary file not shown.
Binary file modified __pycache__/bruteForce.cpython-38.pyc
Binary file not shown.
Binary file removed __pycache__/main.cpython-38.pyc
Binary file not shown.
Binary file removed __pycache__/methods.cpython-38.pyc
Binary file not shown.
32 changes: 32 additions & 0 deletions backtracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,35 @@ def __init__(self, grid):

@staticmethod
def isEmpty(grid):
"""
Check if a Sudoku grid has an empty cell (cell with value 0).
Parameters:
- grid (list of lists): the 9x9 Sudoku grid to check.
Returns:
- tuple or None: If an empty cell is found, returns a tuple (row, column)
containing the coordinates of the first empty cell encountered. If the
grid has no empty cells, returns None.
"""
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):
"""
Check if a number can be placed in a Sudoku grid at a specific position.
Parameters:
- grid (list of lists): The 9x9 Sudoku grid to check.
- nb (int): The number to be placed in the grid.
- pos (tuple): The (row, column) coordinates where the number is to be placed.
Returns:
- bool: True if the number can be placed at the given position without violating
Sudoku rules (no duplicates in the same row, column, or 3x3 subgrid); False otherwise.
"""
for i in range(len(grid)):
if grid[i][pos[1]] == nb and pos[0] != i:
return False
Expand All @@ -26,6 +49,15 @@ def isValid(self, grid, nb, pos):
return True

def solve(self, grid):
"""
Solve a Sudoku puzzle using a backtracking algorithm.
Parameters:
- grid (list of lists): The 9x9 Sudoku grid to be solved.
Returns:
- bool: True if a valid solution is found and the grid is solved; False otherwise.
"""
empty = self.isEmpty(grid)
if not empty:
return True
Expand Down
26 changes: 26 additions & 0 deletions benchmarking.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,37 @@
from bruteForce import BruteForce

def file_holder(file_name):
"""
Read a text file, clean its contents, and convert it into a 9x9 NumPy array of integers.
Parameters:
- file_name (str): The name of the text file to read.
Returns:
- numpy.ndarray: A 9x9 NumPy array containing the cleaned and converted data from the file.
"""
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():
"""
Benchmark the solving time of Sudoku puzzles using different solving methods.
This function iterates through Sudoku puzzle files in a specified directory, allows the
user to choose between Brute Force and Backtracking solvers for each puzzle, and measures
the time it takes to solve each puzzle. It then calculates and prints the average execution
times for both solving methods.
Puzzle files in the directory should be named and formatted appropriately for the solvers
to work correctly.
Note: Make sure the 'sudoku_puzzles' directory contains valid puzzle files.
Returns:
- None
"""
puzzle_directory = "./sudoku_puzzles"
puzzle_files = os.listdir(puzzle_directory)
brute_force_times = []
Expand Down
23 changes: 23 additions & 0 deletions bruteForce.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ def __init__(self, grid):
self.counter = 0

def solve(self, grid):
"""
Attempt to solve the Sudoku puzzle using a brute force approach.
Parameters:
- grid (list of lists): The 9x9 Sudoku grid to be solved.
Returns:
- bool: True if a valid solution is found and the grid is solved; False otherwise.
"""
for i in range(9):
for j in range(9):
if grid[i][j] == 0:
Expand All @@ -21,6 +30,20 @@ def solve(self, grid):
return True

def check(self, grid, row, column, num):
"""
Check if it's valid to place a number at a specific position in the Sudoku grid.
Parameters:
- grid (list of lists): The 9x9 Sudoku grid to be checked.
- row (int): The row index of the cell being checked.
- column (int): The column index of the cell being checked.
- num (int): The number to be checked for validity.
Returns:
- bool: True if placing the number at the specified position is valid;
False otherwise.
"""
if num in grid[row]:
return False
for i in range(9):
Expand Down
43 changes: 42 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,32 @@


def file_holder(file_name):
"""
Read a text file, clean its contents, and convert it into a 9x9 NumPy array of integers.
Parameters:
- file_name (str): The name of the text file to read.
Returns:
- numpy.ndarray: A 9x9 NumPy array containing the cleaned and converted data from the file.
"""
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):
"""
Get the coordinates of non-zero elements in a 2D grid.
Parameters:
- grid (list of lists): The 2D grid to analyze.
Returns:
- list of tuples: A list of tuples containing the (row, column) coordinates
of non-zero elements in the grid.
"""
coordinates = []
for i in range(len(grid)):
for j in range(len(grid[i])):
Expand All @@ -21,6 +40,16 @@ def get_coordinates(grid):


def print_grid(grid, coordinates):
"""
Print a 9x9 Sudoku grid with highlighted coordinates.
Parameters:
- grid (list of lists): The 9x9 Sudoku grid to print.
- coordinates (list of tuples): A list of (row, column) coordinates to highlight.
Returns:
- str: The final horizontal separator line for the grid.
"""
hsep = "\033[34m" + " _______________________" + "\033[0m"
vsep = "\033[34m" + "|" + "\033[0m"
print(hsep)
Expand All @@ -41,6 +70,17 @@ def print_grid(grid, coordinates):


def execute():
"""
Run a Sudoku solver program with user interaction.
This function prompts the user to enter the name of a valid Sudoku puzzle file (.txt).
It then reads the puzzle from the file, allows the user to choose between Brute Force
and Backtracking solvers, and attempts to solve the Sudoku puzzle using the selected
solver. If a solution is found, it displays the solved Sudoku grid.
The user can choose to solve another puzzle or exit the program.
The function runs in a loop until the user decides to exit.
"""
while True:
file_name = input("Please enter a valid file (.txt): ")
if os.path.exists(file_name):
Expand All @@ -61,6 +101,7 @@ def execute():
print("See ya!")
break

execute()
if __name__ == "__main__":
execute()


37 changes: 33 additions & 4 deletions pygame_sudoku.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,32 @@
from tkinter import filedialog, simpledialog

def file_holder(file_name):
"""
Read a text file, clean its contents, and convert it into a 9x9 NumPy array of integers.
Parameters:
- file_name (str): The name of the text file to read.
Returns:
- numpy.ndarray: A 9x9 NumPy array containing the cleaned and converted data from the file.
"""
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):
"""
Get the coordinates of non-zero elements in a 2D grid.
Parameters:
- grid (list of lists): The 2D grid to analyze.
Returns:
- list of tuples: A list of tuples containing the (row, column) coordinates
of non-zero elements in the grid.
"""
coordinates = []
for i in range(len(grid)):
for j in range(len(grid[i])):
Expand All @@ -36,6 +55,13 @@ def get_coordinates(grid):
font = pygame.font.Font(None, FONT_SIZE)

def draw_grid(grid, coordinates):
"""
Draw the Sudoku grid on the Pygame window.
Parameters:
- grid (list of lists): The 9x9 Sudoku grid to be drawn.
- coordinates (list of tuples): A list of (row, column) coordinates to highlight.
"""
window.fill(WHITE)
for i in range(GRID_SIZE):
for j in range(GRID_SIZE):
Expand All @@ -56,6 +82,9 @@ def draw_grid(grid, coordinates):
pygame.display.flip()

def brute_or_backtrack():
"""
Prompt the user to choose a solving method (Brute Force or Backtracking).
"""
root = tk.Tk()
root.withdraw()
choice = simpledialog.askstring("Solving Method", "Enter 1 for the Brute Force solution or 2 for the Backtrack solution:")
Expand All @@ -69,11 +98,11 @@ def brute_or_backtrack():
return None

def execute():
# Create a Tkinter root window (it will be hidden)
"""
Main execution function for solving Sudoku puzzles using Pygame.
"""
root = tk.Tk()
root.withdraw() # Hide the main root window

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

if file_name:
Expand Down

0 comments on commit d318002

Please sign in to comment.