luke77
December 14th, 2008, 07:06 PM
Hi guys,
I am a new programmer, and I'm doing it on my own so I'm finding that it's easy to develop bad habits. I came across the "eight queens" problem online and decided to write a script to solve it iteratively, without using recursion. I know it can be done with much less code with a recursive method, but I did it this way to try to develop good program design. My first try was a disaster; I tend to try to go as quickly as possible and not split up different methods into different functions, so when I come across a problem it's impossible to find out where it is. So for my second try I rewrote things, trying to separate processes into smaller methods (like makeBoard, isValidPos,etc.) instead of cramming it into one function. I also made a "Queens" class so that I don't have to pass the board to every single function. Anyways, I've spent quite a bit of time debugging "version two" and my code still is not working properly, so, I'd appreciate it if anyone could take a look to see where my code is hanging up. I'm also welcome to any comments or criticisms of my structure - like I said, I'm pretty much coming up with this on my own so I'm sure there is probably a better way to organize things. Thanks very much (code below).
Also, a bit of a related question: as I get more experience, I'm coming across complex problems for which the solution is not obvious and sometimes I can't figure it out at all. The Queens problem is not that difficult to figure out "how" to approach, at least with a inefficient method like this one, because there are several clear steps that you can break the problem down into. But some are not so obvious, and even for the Queens problem, a recursive solution is not obvious and I'm not sure that I'd be able to come up with it on my own. It seems like there are common patterns/approaches that programmers use, and when I read the ways advanced programmers have solved complex problems I think, "Wow, that was really smart"...but that doesn't help me when I come across a unique problem with a pattern I haven't seen before. Are there resources that cover common approaches to complex problems, or can anyone suggest ways to improve in this area?
Code for question 1:
class Queens:
def __init__(self,sides):
self.board=self.makeBoard(sides)
self.length=sides
def makeBoard(self,side):
#returns 2X2 array with board dimensions
return [[0]*side for i in range(side)]
def isValidPos(self,row,col):
try :
self.board[row][col]
return True
except:
return False
def colClear(self,colNum):
for row in range(len(self.board)):
if self.board[row][colNum]:
return False
return True
def diagClear(self,rowNum,colNum):
for row in range(len(self.board)):
dist=abs(rowNum-row)
if not self.isValidPos(row,(colNum+dist)):
pass
else:
if (self.board[row][colNum+dist]):
return False
if not self.isValidPos(row,(colNum-dist)):
pass
else:
if (self.board[row][colNum-dist]):
return False
return True
def rowClear(self,rowNum):
for cell in self.board[rowNum]:
if cell:
return False
return True
def addQueen(self,rowNum,colNum):
self.board[rowNum][colNum]="Q"
def getQueenPos(self,rowNum):
#Returns the column number of queen in a row. False if no queen.
try:
return self.board[rowNum].index("Q")
except:
return False
def clearRow(self,rowNum):
newRow=[0 for i in range(len(self.board))]
self.board[rowNum]=newRow
def findBestPos(self,rowNum,startCol):
for cell in range(startCol,self.length):
if self.isValidPos(rowNum,cell) and self.colClear(cell) and self.diagClear(rowNum,cell) and self.rowClear(rowNum):
self.addQueen(rowNum,cell)
return True
return False
def solved(self):
for row in self.board:
if "Q" not in row:
return False
return True
def solveBoard(self):
testrow=0
testcol=0
#Begin at square (0,0) and insert a queen in each row, testing for queens in the same column and diagonal. If there is no legal move, return to the previous row, get the position of its queen, remove the queen, and look for a valid position AFTER the previous position. If no new legal position is found, return to the previous row, etc.
while not self.solved():
if self.findBestPos(testrow,testcol):
testrow+=1
testcol=0
else:
testrow-=1
testcol=self.getQueenPos(testrow)+1
self.clearRow(testrow)
for row in self.board:
print row
board=Queens(8)
board.solveBoard()
I am a new programmer, and I'm doing it on my own so I'm finding that it's easy to develop bad habits. I came across the "eight queens" problem online and decided to write a script to solve it iteratively, without using recursion. I know it can be done with much less code with a recursive method, but I did it this way to try to develop good program design. My first try was a disaster; I tend to try to go as quickly as possible and not split up different methods into different functions, so when I come across a problem it's impossible to find out where it is. So for my second try I rewrote things, trying to separate processes into smaller methods (like makeBoard, isValidPos,etc.) instead of cramming it into one function. I also made a "Queens" class so that I don't have to pass the board to every single function. Anyways, I've spent quite a bit of time debugging "version two" and my code still is not working properly, so, I'd appreciate it if anyone could take a look to see where my code is hanging up. I'm also welcome to any comments or criticisms of my structure - like I said, I'm pretty much coming up with this on my own so I'm sure there is probably a better way to organize things. Thanks very much (code below).
Also, a bit of a related question: as I get more experience, I'm coming across complex problems for which the solution is not obvious and sometimes I can't figure it out at all. The Queens problem is not that difficult to figure out "how" to approach, at least with a inefficient method like this one, because there are several clear steps that you can break the problem down into. But some are not so obvious, and even for the Queens problem, a recursive solution is not obvious and I'm not sure that I'd be able to come up with it on my own. It seems like there are common patterns/approaches that programmers use, and when I read the ways advanced programmers have solved complex problems I think, "Wow, that was really smart"...but that doesn't help me when I come across a unique problem with a pattern I haven't seen before. Are there resources that cover common approaches to complex problems, or can anyone suggest ways to improve in this area?
Code for question 1:
class Queens:
def __init__(self,sides):
self.board=self.makeBoard(sides)
self.length=sides
def makeBoard(self,side):
#returns 2X2 array with board dimensions
return [[0]*side for i in range(side)]
def isValidPos(self,row,col):
try :
self.board[row][col]
return True
except:
return False
def colClear(self,colNum):
for row in range(len(self.board)):
if self.board[row][colNum]:
return False
return True
def diagClear(self,rowNum,colNum):
for row in range(len(self.board)):
dist=abs(rowNum-row)
if not self.isValidPos(row,(colNum+dist)):
pass
else:
if (self.board[row][colNum+dist]):
return False
if not self.isValidPos(row,(colNum-dist)):
pass
else:
if (self.board[row][colNum-dist]):
return False
return True
def rowClear(self,rowNum):
for cell in self.board[rowNum]:
if cell:
return False
return True
def addQueen(self,rowNum,colNum):
self.board[rowNum][colNum]="Q"
def getQueenPos(self,rowNum):
#Returns the column number of queen in a row. False if no queen.
try:
return self.board[rowNum].index("Q")
except:
return False
def clearRow(self,rowNum):
newRow=[0 for i in range(len(self.board))]
self.board[rowNum]=newRow
def findBestPos(self,rowNum,startCol):
for cell in range(startCol,self.length):
if self.isValidPos(rowNum,cell) and self.colClear(cell) and self.diagClear(rowNum,cell) and self.rowClear(rowNum):
self.addQueen(rowNum,cell)
return True
return False
def solved(self):
for row in self.board:
if "Q" not in row:
return False
return True
def solveBoard(self):
testrow=0
testcol=0
#Begin at square (0,0) and insert a queen in each row, testing for queens in the same column and diagonal. If there is no legal move, return to the previous row, get the position of its queen, remove the queen, and look for a valid position AFTER the previous position. If no new legal position is found, return to the previous row, etc.
while not self.solved():
if self.findBestPos(testrow,testcol):
testrow+=1
testcol=0
else:
testrow-=1
testcol=self.getQueenPos(testrow)+1
self.clearRow(testrow)
for row in self.board:
print row
board=Queens(8)
board.solveBoard()