|
@@ -1,19 +1,7 @@
|
|
|
-import sys
|
|
|
import copy
|
|
|
from contextlib import suppress
|
|
|
from heapq import heappush, heappop
|
|
|
-
|
|
|
-board = sys.argv[1]
|
|
|
-algotype = sys.argv[2]
|
|
|
-
|
|
|
-# import board
|
|
|
-with open(board) as file:
|
|
|
- board = file.read().splitlines()
|
|
|
- board = board[:-1]
|
|
|
-
|
|
|
-# convert to list of list of ints
|
|
|
-for l in board:
|
|
|
- board[board.index(l)] = list(map(lambda x: int(x), l.split()))
|
|
|
+import matplotlib.pyplot as plt
|
|
|
|
|
|
# return a board that is like the board b, but has domains for each element of b (always 1-9)
|
|
|
def genDomains(b):
|
|
@@ -59,7 +47,10 @@ def naive(start):
|
|
|
assumptions = []
|
|
|
|
|
|
if(len(unassigned) == 0):
|
|
|
- return True
|
|
|
+ return (working, 0)
|
|
|
+
|
|
|
+ # count assignments
|
|
|
+ count = 0
|
|
|
|
|
|
# while there are unassigned vars, keep going
|
|
|
while(len(unassigned)):
|
|
@@ -69,8 +60,18 @@ def naive(start):
|
|
|
# iterate over all values in the domain list
|
|
|
while solution[index[0]][index[1]]:
|
|
|
i = solution[index[0]][index[1]].pop()
|
|
|
+ count += 1
|
|
|
+ # took too long
|
|
|
+ if (count >= 10000):
|
|
|
+ print("took too long")
|
|
|
+ return 10000
|
|
|
+
|
|
|
# check if this part of the domain(solution) is valid
|
|
|
if (valid(working, index[0], index[1], i)):
|
|
|
+ #count += 1
|
|
|
+ #if (count >= 10000):
|
|
|
+ # print("took too long")
|
|
|
+ # return False
|
|
|
solution[index[0]][index[1]].append(i) # keep in the domain
|
|
|
working[index[0]][index[1]] = i
|
|
|
assumptions.append(index)
|
|
@@ -91,9 +92,9 @@ def naive(start):
|
|
|
|
|
|
|
|
|
# if we exit without assigning everything, we should have failed
|
|
|
- if (unassigned): return False
|
|
|
+ if (unassigned): return 10000
|
|
|
|
|
|
- return working
|
|
|
+ return count
|
|
|
|
|
|
|
|
|
# returns a board (domains) where inferences are made for the cell at row, col
|
|
@@ -130,42 +131,63 @@ def gen2Domains(b):
|
|
|
|
|
|
|
|
|
# recursive solver for forward-checking
|
|
|
-def solve(working, domains, unassigned):
|
|
|
+def solve(working, domains, unassigned, count):
|
|
|
if (not unassigned):
|
|
|
- return working
|
|
|
-
|
|
|
+ return (True, count)
|
|
|
+
|
|
|
index = unassigned.pop()
|
|
|
|
|
|
# for every value in the domain, check if using it works. if all fail, backtrack.
|
|
|
for i in domains[index[0]][index[1]]:
|
|
|
working[index[0]][index[1]] = i
|
|
|
newdomains = infer(domains, working, index[0], index[1], i)
|
|
|
- result = solve(working, newdomains, copy.deepcopy(unassigned))
|
|
|
- if (result):
|
|
|
+ domains[index[0]][index[1]].remove(i)
|
|
|
+ count += 1
|
|
|
+ # took too long
|
|
|
+ if (count >= 10000):
|
|
|
+ print("took too long")
|
|
|
+ return (True, 10000)
|
|
|
+
|
|
|
+ # check for invalidated nodes (empty domains)
|
|
|
+ flag = True
|
|
|
+ result = False
|
|
|
+ for i in range(0, 9):
|
|
|
+ for j in range(0, 9):
|
|
|
+ if (len(newdomains[i][j]) <= 0):
|
|
|
+ flag = False
|
|
|
+
|
|
|
+ if (flag): result = solve(working, newdomains, copy.deepcopy(unassigned), count)
|
|
|
+ if (not result):
|
|
|
+ return (False, count)
|
|
|
+ if (result[0]):
|
|
|
return result
|
|
|
else:
|
|
|
- continue
|
|
|
+ #domains[index[0]][index[1]].remove(i)
|
|
|
+ count = result[1]
|
|
|
|
|
|
- return False
|
|
|
+ return (False, count)
|
|
|
|
|
|
# forward checking solver
|
|
|
def forward(start):
|
|
|
working = copy.deepcopy(start) # this is only "filled in values" and 0s
|
|
|
- domains = gen2Domains(start)
|
|
|
+ domains = gen2Domains(working)
|
|
|
# unassigned will be a list of positions we have to fill
|
|
|
unassigned = []
|
|
|
for i in range(0, 9):
|
|
|
for j in range(0, 9):
|
|
|
if (len(domains[i][j]) == 9):
|
|
|
unassigned.append((i, j))
|
|
|
-
|
|
|
+
|
|
|
# forward-checking on pre-assigned values
|
|
|
for i in range(0, 9):
|
|
|
for j in range(0, 9):
|
|
|
if (working[i][j] != 0):
|
|
|
domains = infer(domains, working, i, j, working[i][j])
|
|
|
|
|
|
- return solve(working, domains, unassigned)
|
|
|
+ result = solve(working, domains, unassigned, 0)
|
|
|
+ return result[1]
|
|
|
+ #if (result[0]): return result[1]
|
|
|
+ #else: return 10000
|
|
|
|
|
|
|
|
|
# returns size of domain for a given index
|
|
@@ -258,9 +280,9 @@ def genVal(domains, working, unassigned):
|
|
|
|
|
|
|
|
|
# recursive solver that uses heuristics to decide what node to explore
|
|
|
-def solveh(working, domains, unassigned):
|
|
|
+def solveh(working, domains, unassigned, count):
|
|
|
if (not unassigned):
|
|
|
- return working
|
|
|
+ return (True, count)
|
|
|
|
|
|
# while there are unassigned values keep trying
|
|
|
while(unassigned):
|
|
@@ -270,26 +292,35 @@ def solveh(working, domains, unassigned):
|
|
|
val = nextThing[1]
|
|
|
working[index[0]][index[1]] = val
|
|
|
unassigned.remove(index)
|
|
|
-
|
|
|
+
|
|
|
# check for invalidated nodes (empty domain)
|
|
|
flag = True
|
|
|
result = False
|
|
|
newdomains = infer(domains, working, index[0], index[1], val)
|
|
|
for i in range(0, 9):
|
|
|
for j in range(0, 9):
|
|
|
- if (not domains[i][j]):
|
|
|
+ if (not newdomains[i][j]):
|
|
|
flag = False
|
|
|
|
|
|
+ count += 1
|
|
|
+ # took too long
|
|
|
+ if (count >= 10000):
|
|
|
+ print("took too long")
|
|
|
+ return (False, count)
|
|
|
+
|
|
|
# success! recurse
|
|
|
- if (flag): result = solveh(working, newdomains, copy.deepcopy(unassigned))
|
|
|
- if (result):
|
|
|
+ if (flag): result = solveh(working, newdomains, copy.deepcopy(unassigned), count)
|
|
|
+ if (not result): pass
|
|
|
+ elif (result[0]):
|
|
|
return result
|
|
|
elif (len(domains[index[0]][index[1]]) > 1): # remove from domain, keep going
|
|
|
working[index[0]][index[1]] = 0
|
|
|
domains[index[0]][index[1]].remove(val)
|
|
|
unassigned.append(index)
|
|
|
+ if (flag): count = result[1]
|
|
|
else: # no values worked :( return false
|
|
|
- return False
|
|
|
+ if (flag): return (False, result[1])
|
|
|
+ return (False, count)
|
|
|
|
|
|
|
|
|
# forward checking solver with heuristics
|
|
@@ -309,25 +340,49 @@ def heuristic(start):
|
|
|
if (working[i][j] != 0):
|
|
|
domains = infer(domains, working, i, j, working[i][j])
|
|
|
|
|
|
- return solveh(working, domains, unassigned)
|
|
|
+ result = solveh(working, domains, unassigned, 0)
|
|
|
+ if (result[0]): return result[1]
|
|
|
+ else: return 10000
|
|
|
|
|
|
|
|
|
def main():
|
|
|
- print("###########")
|
|
|
- print(*board, sep='\n')
|
|
|
- print("##########")
|
|
|
-
|
|
|
- if (algotype == str(0)):
|
|
|
- result = naive(board)
|
|
|
- elif (algotype == str(1)):
|
|
|
- result = forward(board)
|
|
|
- elif (algotype == str(2)):
|
|
|
- result = heuristic(board)
|
|
|
- else:
|
|
|
- print("No valid algorithm selected. RIP.")
|
|
|
+ plt.ioff()
|
|
|
+ plt.switch_backend('agg')
|
|
|
+ averages = []
|
|
|
+ bverages = []
|
|
|
+ cverages = []
|
|
|
+
|
|
|
+ for i in range(1, 72):
|
|
|
+ avgA = 0
|
|
|
+ avgB = 0
|
|
|
+ avgC = 0
|
|
|
+ for j in range(1, 11):
|
|
|
+ filepath = "sudoku_problems/" + str(i) + "/" + str(j) + ".sd"
|
|
|
+
|
|
|
+ # import board
|
|
|
+ with open(filepath) as file:
|
|
|
+ board = file.read().splitlines()
|
|
|
+ board = board[:-1]
|
|
|
|
|
|
- print("###########")
|
|
|
- print(*result, sep='\n')
|
|
|
- print("##########")
|
|
|
+ # convert to list of list of ints
|
|
|
+ for l in board:
|
|
|
+ board[board.index(l)] = list(map(lambda x: int(x), l.split()))
|
|
|
+
|
|
|
+ avgA += naive(copy.deepcopy(board));print(i, j)
|
|
|
+ avgB += forward(copy.deepcopy(board));print(i, j)
|
|
|
+ avgC += heuristic(copy.deepcopy(board));print(i, j)
|
|
|
+
|
|
|
+ averages.append(avgA / 10.0)
|
|
|
+ bverages.append(avgB / 10.0)
|
|
|
+ cverages.append(avgC / 10.0)
|
|
|
+
|
|
|
+ figure, axes = plt.subplots(1, 1, True)
|
|
|
+ axes.plot(range(1, 72), averages, label='Naive Algorithm')
|
|
|
+ axes.plot(range(1, 72), bverages, label='Forward-Checking Algorithm')
|
|
|
+ axes.plot(range(1, 72), cverages, label='Heuristics')
|
|
|
+ axes.legend()
|
|
|
+ plt.xlabel("Number of Initial Valued Filled In")
|
|
|
+ plt.ylabel("Average Number of Variable Assignments in 10 Runs")
|
|
|
+ plt.savefig("graph.pdf")
|
|
|
|
|
|
main()
|