Python: Recursion problems - python

I am trying to make a sudoku solver that solves boards very quickly. At the moment my solver works on easy boards but never terminates on harder boards. I believe it has something to do with my recursion because easy boards do not require recursion and hard boards do. Any help is appreciated.
import sys
def rowno(i):
return i // 9
def colno(i):
return i % 9
def boxno(i):
return (i // 9 // 3 )*3 + (i // 3) % 3
def isNeighbor(i, j):
if rowno(i) == rowno(j) or colno(i) == colno(j) or boxno(i) == boxno(j):
return True
else:
return False
def getFileName():
if sys.platform == "win32":
filename = input("Filename? ")
else:
filename = sys.argv[-1]
return filename
solutionlist = []
class Board(object):
def __init__(self, puzzle):
self.puzzle = puzzle
self.board = [Cell(int(value), idx) for idx, value in enumerate(puzzle)]
self.change = False
def printAll(self):
print [cell.candidates for cell in self.board]
#return str(" ")
def update(self):
self.change = False
l = [cell for cell in self.board if len(cell.candidates) == 1]
for i in l:
for j in xrange(81):
if isNeighbor(i.dex, j) and i.dex != j:
old = self.board[j].candidates
self.board[j].delCandidate(i.value)
if len(old) != len(self.board[j].candidates):
self.change = True
def toString(self):
str1 = ''.join(str(e.value) for e in self.board)
return str1
def solved(self):
for cell in self.board:
if len(cell.candidates) != 1:
return False
return True
def solve(self):
self.change = True
while self.change == True:
self.update()
if self.solved():
solutionlist.append(self.board)
return
l = [cell for cell in self.board if len(cell.candidates) > 1]
for i in l:
for j in i.candidates:
newBoard = Board(self.toString())
curLen = 12
curCell = -1
for u in l:
if len(u.candidates)<curLen:
curLen=len(u.candidates)
curCell = u.dex
for c in newBoard.board[curCell].candidates:
newBoard.board[curCell].candidates = [int(c)]
newBoard.board[curCell].value = int(c)
newBoard.solve()
return
def __repr__(self):
l = [cell.value for cell in self.board]
return str(l)
class Cell(object):
def __init__(self, value, dex):
self.value = value
self.dex = dex
if value == 0:
self.candidates = [1,2,3,4,5,6,7,8,9]
else:
self.candidates = [int(value)]
def __str__(self):
return str(self.value)
def delCandidate(self, value):
# deletes value from candidate list
#return self.candidate.remove(value);
self.candidates = [x for x in self.candidates if x != value]
if len(self.candidates) == 1:
self.value = self.candidates[0]
easy = "700583006006001405052006083300200958500078060648010300060802500003150072215600030"
twosol = "000805200800000401705040009000100702040000000006430000030900000010006080000000000"
hard = "040090008000000070060000120030020000005839060080600700050170600000043000003000200"
#easy solution: 794583216836721495152496783371264958529378164648915327967832541483159672215647839
b = Board(hard)
print b
b.solve()
print "end of the line"
for i in solutionlist:
print [cell.value for cell in i]
print "\n"

One major issue is the line for i in l: in the solve method. Since you're recursing, you only need to fill in one cell - the recursion will take care of the rest. So instead of for i in l:, just recurse on the one cell that is the best candidate (curCell):
l = [cell for cell in self.board if len(cell.candidates) > 1]
if len(l) > 0:
newBoard = Board(self.toString())
curLen = 12
curCell = -1
for u in l:
if len(u.candidates)<curLen:
curLen=len(u.candidates)
curCell = u.dex
for c in newBoard.board[curCell].candidates:
newBoard.board[curCell].candidates = [int(c)]
newBoard.board[curCell].value = int(c)
newBoard.solve()

Related

N Puzzle with Depth First Search

I'm trying solve N Puzzle with Depth First Search using python 3.
With 3 x 3 puzzle it run good and fast but with 4 x 4 puzzle, it runs too slow and can't find solution with error: "MemoryError".
I also use "h(n) = depth + number of wrong tiles" to evaluate priority of each node.
I'm a newbie to python so hope you can help me with this
Here is my code:
import sys
import getopt
import random
import time
class State:
def __init__(self, parent, board, move, depth):
self.parent = parent
self.previousMove = move
self.board = board
self.map = ''.join(str(e) for e in board)
self.depth = depth
self.cost = self.calculateCost()
def calculateCost(self):
pos = 1
count = 0
for tile in self.board:
if tile == pos:
count += 1
pos += 1
return self.depth + 8 - count
class Puzzle:
def __init__(self, k, customBoard = None):
self.k = k
self.n = k*k - 1
self.sizeOfBoard = k*k
self.timeOfSolving = 0
self.timeOfGenerateSuccessors = 0
self.maxDeepSearch = 0
self.inititalState = State(None, self.createInitialBoard(customBoard), 'Start', 0)
self.goalBoard = self.createGoalBoard()
self.finalState = None
self.stateStorage = set() # Store states that have visited
self.path = [] # Store states that lead to goalstate
self.stack = []
def isSolvable(self, board):
# count invertion in puzzle's board
invCount = 0
for i in range(0, self.sizeOfBoard - 1):
if board[i] == 0:
continue
for j in range(i+1, self.sizeOfBoard):
if board[j] == 0:
continue
if board[i] > board[j]:
invCount += 1
# print(invCount)
if (invCount % 2 == 0):
return True
return False
def createInitialBoard(self, customBoard):
print("Creating initial state")
if customBoard is None:
board = []
lstAddSuccess = []
while 1:
board.clear()
lstAddSuccess.clear()
for count in range(0, self.k*self.k):
newTile = random.randint(0, self.n)
while newTile in lstAddSuccess:
newTile = random.randint(0, self.n)
lstAddSuccess += [newTile]
board += [newTile]
if self.isSolvable(board):
break
else:
board = [int(e) for e in customBoard]
if not self.isSolvable(board):
print("Cant find solution with this puzzle! Exiting...")
exit(-1)
return board
def createGoalBoard(self):
board = []
for count in range(1, self.n + 1):
board += [count]
board += [0]
return board
def printBoard(self, board):
for row in range(0, self.sizeOfBoard, self.k):
# for col in range(row, row + self.k):
print(board[row:row + self.k])
def generateSuccessors(self, currentState):
indexOfZero = currentState.board.index(0)
rowIndexOfZero = indexOfZero % self.k
colIndexOfZero = indexOfZero // self.k
lstSuccessors = []
# Slide to zero to up
if colIndexOfZero != 0:
newState = currentState.board.copy()
newState[indexOfZero] = newState[indexOfZero - self.k]
newState[indexOfZero - self.k] = 0
lstSuccessors.append(
State(currentState, newState, 'up', currentState.depth + 1))
# Slide zero to down
if colIndexOfZero != self.k - 1:
newState = currentState.board.copy()
newState[indexOfZero] = newState[indexOfZero + self.k]
newState[indexOfZero + self.k] = 0
lstSuccessors.append(
State(currentState, newState, 'down', currentState.depth + 1))
# slide zero to left
if rowIndexOfZero != 0:
newState = currentState.board.copy()
newState[indexOfZero] = newState[indexOfZero - 1]
newState[indexOfZero - 1] = 0
lstSuccessors.append(
State(currentState, newState, 'left', currentState.depth + 1))
# Slide zero to right
if rowIndexOfZero != self.k - 1:
newState = currentState.board.copy()
newState[indexOfZero] = newState[indexOfZero + 1]
newState[indexOfZero + 1] = 0
lstSuccessors.append(
State(currentState, newState, 'right', currentState.depth + 1))
lstSuccessorsCost = [ele.cost for ele in lstSuccessors]
lstSuccessorsInOrderOfCost = []
for i in range(0, len(lstSuccessorsCost)):
lstSuccessorsInOrderOfCost.append(lstSuccessors[lstSuccessorsCost.index(min(lstSuccessorsCost))])
lstSuccessorsCost[lstSuccessorsCost.index(min(lstSuccessorsCost))] = 100
return lstSuccessorsInOrderOfCost
def solvePuzzle(self, currentState):
self.stack.append(currentState)
self.stateStorage.add(currentState.map)
while len(self.stack) > 0:
currentState = self.stack.pop()
if currentState.board == self.goalBoard:
# find path
# self.printBoard(currentState.board)
self.finalState = currentState
print("Solving " + str(self.n) + " puzzle done!")
return
start_time_gen = time.time()
lstSuccessor = self.generateSuccessors(currentState)
end_time_gen = time.time()
timeOfGen = end_time_gen - start_time_gen
self.timeOfGenerateSuccessors += timeOfGen
for successor in lstSuccessor[::-1]:
if successor.map not in self.stateStorage:
self.stack.append(successor)
self.stateStorage.add(successor.map)
if successor.depth > self.maxDeepSearch:
self.maxDeepSearch += 1
print("Cant solve puzzle! Exiting...")
exit(-1)
def solve(self):
start_time = time.time()
self.solvePuzzle(self.inititalState)
end_time = time.time()
self.timeOfSolving = end_time - start_time
print("Running time: " + str(self.timeOfSolving))
print("Max Search Dept: " + str(self.maxDeepSearch))
print("Final State Dept: " + str(self.finalState.depth))
def printInitialBoard(self):
self.printBoard(self.inititalState.board)
def printPath(self):
if self.finalState is None:
print("No solution found!")
return
path = []
state = self.finalState
while (state is not None):
if state.previousMove is not None:
path.append(state.previousMove)
state = state.parent
print("path: "),
print(path[::-1])
def main(argv):
# if (len(argv) != 1 or int(argv[0]) not in range(1, 10000)):
# print("Input must be k of integer, which is k*k matrix of puzzle")
# exit()
# eight_puzzle = Puzzle(int(argv[0]))
k = int(input("Enter size of k * k puzzle, k = "))
while k not in range(2, 100):
print("k must be in range 2 - 100")
k = int(input("Enter size of k * k puzzle, k = "))
print("""
Choose:
1. Randome puzzle
2. Custome puzzle
""")
file = input()
if int(file) == 1:
puzzle = Puzzle(k)
elif int(file) == 2:
board = input("Enter puzzle: ")
puzzle = Puzzle(k ,list(board.split(" ")))
puzzle.printInitialBoard()
puzzle.solve()
puzzle.printPath()
if __name__ == "__main__":
main(sys.argv[1:])

How do I create a Set method for a class with a variable-dimension container?

If I have a list class that can be initialized with a variable number of dimensions, how do I set an entry at the lowest level of the list with an element? (Also would like to know if my get method should work in theory)
I'm trying to simulate board games that use multiple dimensions (Can you even imagine 5-th dimensional chess? How about 17th?)
class Board():
DIMENSIONS = [8, 8]
#board and pieces have their respective rules.
def __init__(self, D=[8,8]):
if len(D) <= 0:
board = [None for i in range(D)]
else:
board = [None for i in range(D[0])]
for j in range(1,len(D)):
board = [board for i in range(D[j])]
def get(self, location):
try:
for coordinate in location:
result = board[coordinate]
return result
except:
print('Error: Cannot get coordinate')
return None
def set(self, location, piece):
try:
for coordinate in location:
result = self.board[coordinate]
result = piece
except:
print('Error: Cannot set coordinate')
def move(self, start, end):
x = self.get(start)
if x is not None:
for m, r in x.moves, x.rules:
if self.get(is_legitimate(self, start, m, r)) == end:
= x
pass
#Check alignment and position, if it's transformable react according to board rules.
#returns false if not, but returns location if legit.
def is_legitimate(self, start, move, rule):
location = start
forwardback = True
while move != 1:
primes = [2]
while move % primes[-1] == 0:
if forwardback:
location[len(primes) // 2]+=1
else:
location[len(primes) // 2]-=1
move = move % primes[-1]
if not self.bounds(location):
return False
primes.append(next_prime(primes))
forwardback = not forwardback
def bounds(self, location):
for coordinate, d in location, self.DIMENSIONS:
if coordinate < 0 or coordinate > d:
return False
return True
#using prime numbers?
def next_prime(primes):
if len(primes) == 0:
return 2
prev_result = 1
result = 2
while prev_result != result:
prev_result = result
for x in primes:
if result == x or result % x == 0:
result += 1
break
return result
Code is mostly rough draft, don't play just look.

How to improve performance of this python code?

I am solving a puzzle (Finding if there exists an input for a given automata for which no matter what the starting state is, final state would be same everytime) and have written following python code. A few testcases are written in check method in the code. For these cases program is running fairly fast. However, for testcases where 50 lists(nodes) are present, the programis taking forever to execute. I am storing intermediate results to use further as well. Can someone please review the code and give suggestions on how to increase the performance of the code?
from itertools import product
from copy import deepcopy
class Node:
def __init__(self,id):
self.id = id
self.dict = {}
def __str__(self):
return str(id) + " : " + str(self.dict)
def __repr__(self):
return str(id) + " : " + str(self.dict)
def tryDelete(nodes,_len):
for id in nodes:
y = deepcopy(nodes)
x = y[id]
del y[id]
for id,node in y.items():
for input,result in node.dict.items():
if result == x:
if x.dict[input] == x:
node.dict[input] = node
else:
node.dict[input] = x.dict[input]
pass
if pathPossible(y,_len ,False) == -1:
return x.id
return -2
target = {}
def FindTarget(node,p):
if len(p) == 1:
return node.dict[p[0]]
if node not in target or p not in target[node]:
x = FindTarget(node,p[:-1]).dict[p[-1]]
if node not in target:
target[node] = {}
target[node][p] = x
return target[node][p]
def allSatisy(nodes,p):
x = None
for key,node in nodes.items():
if x is None:
x = FindTarget(node,p)
elif FindTarget(node,p) != x:
return False
return True
def allPossiblePaths(l,n):
#x = int(((l+1)*(l+2))/2)
for i in range(1, n+1):
for p in product(range(l),repeat=i):
yield p
def pathPossible(nodes,_len ,isItereate=True):
i = 1
isFound = False
for p in allPossiblePaths(_len,len(nodes)):
if allSatisy(nodes,p):
isFound = True
break
if isFound:
return -1
elif not isItereate:
return -2
else:
return tryDelete(nodes,_len)
def answer(li):
nodes = {}
for i in range(len(li)):
nodes[i] = Node(i)
for i in range(len(li)):
for j in range(len(li[i])):
nodes[i].dict[j] = nodes[li[i][j]]
return pathPossible(nodes,len(nodes[0].dict))
def check(li,ans):
# each item in the list is a node, each item i-th in the inner list tells to what node the transition happens for input i
x = answer(li)
print(str(li) + " : " + str(ans) + " : " + str(x))
def main():
check([[2,1],[2,0],[3,1],[1,0]],-1)
check([[1,2],[1,1],[2,2]],1)
check([[1,3,0],[1,0,2],[1,1,2],[3,3,3]],-1)
if __name__ == '__main__':
main()
UPDATE: I have done few code changes, but still this needs some review from you guys. Changed code:
from itertools import product
from copy import deepcopy
class Node:
def __init__(self,id):
self.id = id
self.dict = {}
def __str__(self):
return str(self.id) + " : " + str(self.dict)
def __repr__(self):
return str(self.id) + " : " + str(self.dict)
def tryDelete(nodes,_len):
for i in range(len(nodes)):
y = nodes[:]
x = y[i]
del y[i]
tNodes = []
for node in y:
for input,result in node.dict.items():
if result == x:
node.tDict = deepcopy(node.dict)
if x.dict[input] == x.id:
node.dict[input] = node
else:
node.dict[input] = x.dict[input]
if pathPossible(y,_len ,False) == -1:
return x.id
for n in tNodes:
n.dict = n.tDict
del n.tDict
return -2
target = {}
def FindTarget(node,p):
if len(p) == 1:
return node.dict[p[0]]
if node not in target or p not in target[node]:
x = Gnodes[FindTarget(node,p[:-1])].dict[p[-1]]
if node not in target:
target[node] = {}
target[node][p] = x
return target[node][p]
def allSatisy(nodes,p):
x = None
for node in nodes:
if x is None:
x = FindTarget(node,p)
elif FindTarget(node,p) != x:
return False
return True
def allPossiblePaths(l,n):
#x = int(((l+1)*(l+2))/2)
for i in range(1, n + 1):
for p in product(range(l),repeat=i):
yield p
def pathPossible(nodes,_len ,isItereate=True):
i = 1
isFound = False
for p in allPossiblePaths(_len,len(nodes)):
if allSatisy(nodes,p):
isFound = True
break
if isFound:
return -1
elif not isItereate:
return -2
else:
return tryDelete(nodes,_len)
Gnodes = []
def answer(li):
Gnodes[:] = []
for i in range(len(li)):
Gnodes.append(Node(i))#[i] = Node(i)
for i in range(len(li)):
for j in range(len(li[i])):
Gnodes[i].dict[j] = li[i][j]
return pathPossible(Gnodes,len(Gnodes[0].dict))
def check(li,ans):
x = answer(li)
print(str(li) + " : " + str(ans) + " : " + str(x))
def main():
check([[2,1],[2,0],[3,1],[1,0]],-1)
check([[1,2],[1,1],[2,2]],1)
check([[1,3,0],[1,0,2],[1,1,2],[3,3,3]],-1)
if __name__ == '__main__':
main()
There is a wonderful graph library called NetworkX. It deals with creating graphs and path finding. You specify what edges or paths exist in your Graph and you can find paths using a plethora of algorithms like breadth first search, or A*, and many others in the algorithms section. The best way to optimize your time is code reuse.
https://networkx.github.io

how to return false and problematic row(python sudoku checker)

I'm having a problem returning both False, and the append number in the def checkit function. I'm not sure if I have miscoded the checkrow functions. It is able to return true when given a correctly solved Sudoku puzzle, but when we are to call an incorrect Sudoku puzzle, it is to return False, and provide the problematic row. Currently, it is only returning the problematic row, aka the location of what makes the puzzle fail, but not including false. any idea on how to make it so that it returns both?
import sys
from scanner import *
def createList(size):
if size == 0: return []
else:
return [0] + createList(size -1)
def printGrid(gridlist):
for row in gridlist:
print (str(row)+"\n")
def rows(g):
return len(g)
def cols(g):
return len(g[0])
def printMatrix(g):
for i in range(0,rows(g),1):
for j in range(0,cols(g),1):
print(g[i][j],end=' ')
print('')
print('')
def readinput(filename,grid):
s = Scanner(filename)
r = s.readtoken()
while r != "":
r = int(r)
c = s.readint()
v = s.readint()
grid[r][c]=v
r = s.readtoken()
def checkRows(g):
for rows in g:
numbersInRow = []
for number in rows:
if number != 0 and number in numbersInRow:
return g.index(rows)
else:
numbersInRow.append(number)
return True
def checkIt(g):
checkRows(g)
rowSuccess = checkRows(g)
print(rowSuccess)
def main():
grid = createList(9)
for i in range(9):
grid[i] = createList(9)
readinput(sys.argv[1],grid)
printMatrix(grid)
checkIt(grid)
main()
You can return both of them:
def checkRows(g):
for rows in g:
numbersInRow = []
for number in rows:
if number != 0 and number in numbersInRow:
return g.index(rows), False
else:
numbersInRow.append(number)
And to read it:
problematic_row, result = checkRows(g)
return False, g.index(rows) will return two values as a tuple.

Python minimax for tictactoe

After completely failing the minimax implementation for tic tac toe, I fail to see what's wrong. Right now, my AI just goes around in a circle...
import collections
class InvalidLocationError(Exception): pass
import copy
class Board(object):
def __init__(self, board=None):
if board is None:
self.clear()
else:
self._board = board[:]
def place(self, i, row, column):
if not ((0 <= row <= 2) and (0 <= column <= 2)):
raise InvalidLocationError("Invalid Location.")
if self._board[row][column]:
raise InvalidLocationError("There's already a piece there")
self._board[row][column] = i
return self.checkVictory()
def check(self, row, column):
return self._board[row][column]
def checkVictory(self, board=None):
if board is None:
board = self._board
draw = True
for i in xrange(3):
r = self.rowcount(i)
c = self.colcount(i)
if i < 3:
d = self.diagcount(i)
else:
d = {0: 0, 1: 0, 2: 0}
for j in xrange(1, 3):
if d[j] == 3 or r[j] == 3 or c[j] == 3:
return j
if r[0] > 0 or c[0] > 0:
draw = False
if draw:
return -1
return 0
def rowcount(self, row):
return collections.Counter(self._board[row])
def colcount(self, col):
return collections.Counter([self._board[i][col] for i in xrange(3)])
def diagcount(self, left=True):
if left:
a = [self._board[0][0], self._board[1][1], self._board[2][2]]
else:
a = [self._board[0][2], self._board[1][1], self._board[2][0]]
return collections.Counter(a)
def clear(self):
self._board = ([0, 0, 0], [0, 0, 0], [0, 0, 0])
def __str__(self):
return "\n".join(map(lambda x: " ".join(map(lambda y : str(y), x)), self._board))
#staticmethod
def flipPiece(p):
return int(not (p - 1)) + 1
class AI(object):
class Node(object):
def __init__(self, board, nextMove):
self.board = board
self.nextMove = nextMove
self.paths = []
self.score = None
template = self.board._board[:]
for r, row in enumerate(template):
for c, val in enumerate(row):
if val == 0:
template[r][c] = nextMove
self.paths.append(copy.deepcopy(template))
template[r][c] = 0
def __init__(self, mypiece, depth=8):
self.mypiece = mypiece
self.enemypiece = Board.flipPiece(mypiece)
self.depth = depth
def decide(self, board):
startNode = self.Node(board, self.mypiece)
best = self.minimax(startNode, self.depth)
for node in startNode.paths:
if node.value == best:
break
found = False
for row in xrange(3):
for col in xrange(3):
if board.check(row, col) != node.board.check(row, col):
found = True
break
if found:
break
print row, col
return row, col
def minimax(self, node, depth):
victory = node.board.checkVictory()
if victory:
if victory == self.mypiece:
h = 1
elif victory == -1:
h = 0
else:
h = -1
node.value = h
return h
if depth <= 0:
# h = self.heuristic(node.board, node.nextMove) # This is to the heuristic, which uses nextMove to evalate.
node.value = 0
return 0
h = -1
flip = Board.flipPiece(node.nextMove)
for i, board in enumerate(node.paths):
node.paths[i] = self.Node(Board(board), flip) # This is to the Node, which takes the nextMove of itself (which translates to the next next move from the current node)
score = self.minimax(node.paths[i], depth-1)
h = max(h, score) if node.nextMove == self.mypiece else min(h, score)
node.value = h
return h
Why is this happening?

Categories