diff --git a/Search_Algorithms/Heuristics.py b/Search_Algorithms/Heuristics.py index cf5fa56e4ecf28ebb02ed4b1b7cbdab6de3b6d7a..069822967d37b2b015a5c8934b009fab4dd1abd4 100644 --- a/Search_Algorithms/Heuristics.py +++ b/Search_Algorithms/Heuristics.py @@ -1,4 +1,5 @@ import is_goal +import Sucessors @@ -16,21 +17,9 @@ def puzzle_opt(path): def sudoku_opt(path): - # state = path[-1] - # box_value, row_value, col_value = 0, 0, 0 - # # check each box to see the least empty - # for down in range(0, 9, 3): - # for across in range(0, 9, 3): - # box_value += 9 - () - # box_value = 0 - # - # # check each row for the one with the least zeros - # row_value = 0 - # - # # check each column for the one with the least zeros - # col_value = 0 - - pass + starting_point = [Sucessors.choose_best_subsquare(path[-1]), Sucessors.choose_best_rows(path[-1]), + Sucessors.choose_best_column(path[-1])] + return max(starting_point, key=lambda w: w[2])[-1] def queens_opt(path): diff --git a/Search_Algorithms/Search_Algorithms.py b/Search_Algorithms/Search_Algorithms.py index 6558e36bc21821219080d2e28ef2e19f9af02bee..242844794e9e912521abe6ecebd62712c4509f81 100644 --- a/Search_Algorithms/Search_Algorithms.py +++ b/Search_Algorithms/Search_Algorithms.py @@ -34,7 +34,6 @@ def DepthFirstSearch(state, successor, isgoal): if next_state not in explored: explored.add(next_state) path2 = path + [next_state] - print(path2) toDo.append(path2) return "Error Path not found" diff --git a/Search_Algorithms/Sucessors.py b/Search_Algorithms/Sucessors.py index 0de1748da760bb55db475c1c3638c8c07ff0795f..1baefd29db00388c8318db08115f39e8c272ebc6 100644 --- a/Search_Algorithms/Sucessors.py +++ b/Search_Algorithms/Sucessors.py @@ -9,11 +9,8 @@ def maze_successor(state): def sudoku_successor(state): new_state = list(map(list, state)) # Convert state to a list of lists - y, x = -1, -1 - for i, s in enumerate(state): - if 0 in s: - (y, x) = (i, s.index(0)) - break + starting_point = [choose_best_subsquare(new_state), choose_best_rows(new_state), choose_best_column(new_state)] + x, y, dummy = max(starting_point, key=lambda w: w[2]) next_states = [] for j in range(1, len(new_state) + 1): new_state[y][x] = j @@ -22,45 +19,6 @@ def sudoku_successor(state): return next_states -def maze_allowed(state): - maze = [[' ', 'W', ' ', ' ', 'G'], - [' ', 'W', ' ', 'W', ' '], - [' ', 'W', ' ', ' ', ' '], - [' ', ' ', 'W', 'W', ' '], - [' ', ' ', ' ', ' ', ' ']] - if state[0] >= len(maze[0]) or state[0] < 0: - return False - if state[1] >= len(maze) or state[1] < 0: - return False - return maze[state[0]][state[1]] == ' ' or maze[state[0]][state[1]] == 'G' - - -def sudoku_allowed(state): - (y, x, grid) = state - """I'm making the state a triple on this one""" - # (y, x, z): x,y is the coordinate and z is the value in the square - - # check if still inside the box - if y < 0 or y >= len(grid[0]): - return False - if x < 0 or x >= len(grid): - return False - - # inspect columns and rows - if ([row[x] for row in grid].count(grid[y][x]) > 1) or (grid[y].count(grid[y][x]) > 1): - return False - - # inspect minor square in teh sudoku - inner_x = ((x - (x % 3)), (x - (x % 3) + 3)) - inner_y = (y - (y % 3)) - inner_square = grid[inner_y][inner_x[0]:inner_x[1]] + grid[inner_y + 1][inner_x[0]:inner_x[1]] + \ - grid[inner_y + 2][inner_x[0]:inner_x[1]] - if inner_square.count(grid[y][x]) > 1: - return False - - return True - - def puzzle_successor(state): y, x = -1, -1 for i in range(len(state)): @@ -103,10 +61,52 @@ def queens_successor(state): return next_states +# Allowed moves Functions def puzzle_allowed(state): return True + +def maze_allowed(state): + maze = [[' ', 'W', ' ', ' ', 'G'], + [' ', 'W', ' ', 'W', ' '], + [' ', 'W', ' ', ' ', ' '], + [' ', ' ', 'W', 'W', ' '], + [' ', ' ', ' ', ' ', ' ']] + if state[0] >= len(maze[0]) or state[0] < 0: + return False + if state[1] >= len(maze) or state[1] < 0: + return False + return maze[state[0]][state[1]] == ' ' or maze[state[0]][state[1]] == 'G' + + +def sudoku_allowed(state): + (y, x, grid) = state + """I'm making the state a triple on this one""" + # (y, x, z): x,y is the coordinate and z is the value in the square + + # check if still inside the box + if y < 0 or y >= len(grid[0]): + return False + if x < 0 or x >= len(grid): + return False + + # inspect columns and rows + if ([row[x] for row in grid].count(grid[y][x]) > 1) or (grid[y].count(grid[y][x]) > 1): + return False + + # inspect minor square in teh sudoku + inner_x = ((x - (x % 3)), (x - (x % 3) + 3)) + inner_y = (y - (y % 3)) + inner_square = grid[inner_y][inner_x[0]:inner_x[1]] + grid[inner_y + 1][inner_x[0]:inner_x[1]] + \ + grid[inner_y + 2][inner_x[0]:inner_x[1]] + if inner_square.count(grid[y][x]) > 1: + return False + + return True + + + def queens_allowed(state): """in this case the state is also y, x, grid""" y, x, grid = state @@ -137,3 +137,49 @@ def queens_allowed(state): return False return True + + +# Helper Functions +def choose_best_rows(grid): + best_row = -1 + x = -1 + min_empty = len(grid) + for i in range(len(grid)): + empty_cells = grid[i].count(0) + if 0 < empty_cells < min_empty: + best_row = i + min_empty = empty_cells + x = grid[i].index(0) + return x, best_row, min_empty + + +def choose_best_column(grid): + best_col = -1 + y = -1 + min_empty = len(grid) + for i in range(len(grid)): + col = [row[i] for row in grid] + empty_cells = col.count(0) + if 0 < empty_cells < min_empty: + best_col = i + min_empty = empty_cells + y = col.index(0) + return best_col, y, min_empty + + +def choose_best_subsquare(grid): + x = -1 + y = -1 + best_val = len(grid) + for down in range(0, 9, 3): + for across in range(0, 9, 3): + subsquare = [grid[i][across: across + 3] for i in range(down, down + 3)] + zeros = sum([subsquare[i].count(0) for i in range(len(subsquare))]) + if 0 < zeros < best_val: + best_val = zeros + for j in range(len(subsquare)): + if 0 in subsquare[j]: + x = across + subsquare[j].index(0) + y = down + j + break + return (x, y, best_val) diff --git a/Search_Algorithms/solution testing.py b/Search_Algorithms/solution testing.py index d34c13505f48ef42031e591b23861a05497c1c51..6a537e262497f2d05956953e95819e3a2f8807e1 100644 --- a/Search_Algorithms/solution testing.py +++ b/Search_Algorithms/solution testing.py @@ -5,26 +5,29 @@ import Heuristics # Maze Problem, note, the maze is fixed in the allowed state. -# print(Search_Algorithms.BreadthFirstSearch((4, 0), Sucessors.maze_successor, is_goal.is_goal_maze)) +print(Search_Algorithms.BreadthFirstSearch((4, 0), Sucessors.maze_successor, is_goal.is_goal_maze)) # Sudoku -grid = ((1, 0, 0, 0, 0, 0, 0, 0, 0), - (0, 0, 0, 0, 0, 0, 0, 0, 0), - (0, 0, 0, 0, 0, 0, 0, 0, 0), - (0, 0, 0, 0, 0, 0, 0, 0, 0), - (0, 0, 0, 0, 0, 0, 0, 0, 0), - (0, 0, 0, 0, 0, 0, 0, 0, 0), - (0, 0, 0, 0, 0, 0, 0, 0, 0), - (0, 0, 0, 0, 0, 0, 0, 0, 0), +grid = ((5, 3, 0, 0, 7, 0, 0, 0, 0), + (6, 0, 0, 1, 9, 5, 0, 0, 0), + (0, 9, 8, 0, 0, 0, 0, 6, 0), + (8, 0, 0, 0, 6, 0, 0, 0, 3), + (4, 0, 0, 8, 0, 3, 0, 0, 1), + (7, 0, 0, 0, 2, 0, 0, 0, 6), + (0, 6, 0, 0, 0, 0, 2, 8, 0), + (0, 0, 0, 4, 1, 9, 0, 0, 5), (0, 0, 0, 0, 8, 0, 0, 0, 0)) -# sln = (Search_Algorithms.BreadthFirstSearch(grid, Sucessors.sudoku_successor, is_goal.is_goal_sudoku)[-1]) +sln = (Search_Algorithms.BreadthFirstSearch(grid, Sucessors.sudoku_successor, is_goal.is_goal_sudoku)[-1]) -# sln = (Search_Algorithms.DepthFirstSearch( -# grid, Sucessors.sudoku_successor, is_goal.is_goal_sudoku)[-1]) +for rows in sln: + print(rows) +print("--------------------------------") +sln = (Search_Algorithms.DepthFirstSearch( + grid, Sucessors.sudoku_successor, is_goal.is_goal_sudoku)[-1]) # -# for rows in sln: -# print(rows) +for rows in sln: + print(rows) # N Queens board = ((False, False, False, False, False, False, False, False, False), @@ -38,15 +41,15 @@ board = ((False, False, False, False, False, False, False, False, False), (False, False, False, False, False, False, False, False, False)) -# sln = (Search_Algorithms.BreadthFirstSearch(board, Sucessors.queens_successor, is_goal.is_goal_queens)[-1]) -# +sln = (Search_Algorithms.BreadthFirstSearch(board, Sucessors.queens_successor, is_goal.is_goal_queens)[-1]) + # sln = (Search_Algorithms.DepthFirstSearch( # board, Sucessors.queens_successor, is_goal.is_goal_queens)[-1]) -# -# output_tuple = tuple(tuple("Q" if value else "." for value in sln) -# for sln in sln) -# for rows in output_tuple: -# print(rows) + +output_tuple = tuple(tuple("Q" if value else "." for value in sln) + for sln in sln) +for rows in output_tuple: + print(rows) # Sliding Puzzle @@ -55,14 +58,14 @@ initial_puzzle = ( (5, 0, 6), (8, 3, 1) ) -# -# sln = (Search_Algorithms.BreadthFirstSearch(initial_puzzle, Sucessors.puzzle_successor, is_goal.is_goal_puzzle)[-1]) -# -# if sln: -# for rows in sln: -# print(rows) -# else: -# print("No solution found") + +sln = (Search_Algorithms.BreadthFirstSearch(initial_puzzle, Sucessors.puzzle_successor, is_goal.is_goal_puzzle)[-1]) + +if sln: + for rows in sln: + print(rows) +else: + print("No solution found") # # sln = (Search_Algorithms.DepthFirstSearch(initial_puzzle, Sucessors.puzzle_successor, is_goal.is_goal_puzzle)[-1]) @@ -73,7 +76,13 @@ initial_puzzle = ( # else: # print("No solution found") -print(Search_Algorithms.A_StarSearch((4, 0), Sucessors.maze_successor, is_goal.is_goal_maze, Heuristics.maze_opt)) +# print(Search_Algorithms.A_StarSearch((4, 0), Sucessors.maze_successor, is_goal.is_goal_maze, Heuristics.maze_opt)) + +sln = (Search_Algorithms.A_StarSearch(grid, Sucessors.sudoku_successor, + is_goal.is_goal_sudoku, Heuristics.sudoku_opt))[-1] + +for rows in sln: + print(rows)