Sudoku Solver Python backtracking input - python

For school, we should program a sudoku solver and I just followed a tutorial to program one and it works:
board = [
[7,8,0,4,0,0,1,2,0],
[6,0,0,0,7,5,0,0,9],
[0,0,0,6,0,1,0,7,8],
[0,0,7,0,4,0,2,6,0],
[0,0,1,0,5,0,9,3,0],
[9,0,4,0,6,0,0,0,5],
[0,7,0,3,0,0,0,1,2],
[1,2,0,0,0,7,4,0,0],
[0,4,9,2,0,6,0,0,7]
]
def solve(bo):
find = find_empty(bo)
if not find:
return True
else:
row, col = find
for i in range(1,10):
if valid(bo, i, (row, col)):
bo[row][col] = i
if solve(bo):
return True
bo[row][col] = 0
return False
def valid(bo, num, pos):
# Check row
for i in range(len(bo[0])):
if bo[pos[0]][i] == num and pos[1] != i:
return False
# Check column
for i in range(len(bo)):
if bo[i][pos[1]] == num and pos[0] != i:
return False
# Check box
box_x = pos[1] // 3
box_y = pos[0] // 3
for i in range(box_y*3, box_y*3 + 3):
for j in range(box_x * 3, box_x*3 + 3):
if bo[i][j] == num and (i,j) != pos:
return False
return True
def print_board(bo):
for i in range(len(bo)):
if i % 3 == 0 and i != 0:
print("- - - - - - - - - - - - - ")
for j in range(len(bo[0])):
if j % 3 == 0 and j != 0:
print(" | ", end="")
if j == 8:
print(bo[i][j])
else:
print(str(bo[i][j]) + " ", end="")
def find_empty(bo):
for i in range(len(bo)):
for j in range(len(bo[0])):
if bo[i][j] == 0:
return (i, j) # row, col
return None
print_board(board)
solve(board)
print("___________________")
print_board(board)
But my problem is we have to handle strings like:
003020600
900305000
001806400
008102900
700000008
006708200
002609500
800203009
005010300
and couldn't separate them with a comma. Do you have an idea how to fix the problem?

You can transform a multiline string to a 2d-list of integers like:
s = """003020600
900305000
001806400
008102900
700000008
006708200
002609500
800203009
005010300"""
board = [[*map(int, line)] for line in s.splitlines()]
Or, if you are reading these lines as input from stdin:
board = []
for _ in range(9):
board.append([*map(int, input())])

Related

how to fix 'ValueError: math domain error' in Python

def distinctIntegers(n):
board = [n]
lenBoard = 0
while lenBoard != len(board):
lenBoard = len(board)
for num in board:
temp = num - 1
for i in range(2, int(math.sqrt(temp)) + 1):
if temp % i == 0:
if i not in board:
board.append(i)
if temp / i not in board:
board.append(temp / i)
return len(board)
it's fine for now.
i wanted put that (if temp not in board : board.append(temp)) in first for loop. 'ValueError: math domain error in Python' occured after putting that .
def distinctIntegers(n):
board = [n]
lenBoard = 0
while lenBoard != len(board):
lenBoard = len(board)
for num in board:
temp = num - 1
if temp not in board:
board.append(temp)
for i in range(2, int(math.sqrt(temp)) + 1):
if temp % i == 0:
if i not in board:
board.append(i)
if temp / i not in board:
board.append(temp / i)
return len(board)
this and
def distinctIntegers(n):
board = [n]
lenBoard = 0
while lenBoard != len(board):
lenBoard = len(board)
for num in board:
temp = num - 1
for i in range(2, int(math.sqrt(temp)) + 1):
if temp % i == 0:
if i not in board:
board.append(i)
if temp / i not in board:
board.append(temp / i)
if temp not in board:
board.append(temp)
return len(board)
this, both of them didn't work
i changed the location and put 'num - 1' instead of temp..
but still doesn't works. I dont know why..

why is this recursive sudoku code not working?

im learning python, I wanted the sudoku numbers to be read from a csv file and to be reconstructed. that part works. but it does not solve the sudoku. it just prints the same input again.
Can somebody please help me? Any idea why?
Question number 2: Any Tipps how i could modify this code to give the number of possible sudoku solutions? In case, there are multiple solutions possible.
Thank you so much in Advanced! :)
import csv
with open('sudoko.csv') as f:
board = list(csv.reader(f,delimiter=';'))
def solve(bo):
find = find_empty(bo)
if not find:
return True
else:
row, col = find
for num in range(1,10):
if valid(bo, num, (row, col)):
bo[row][col] = num
if solve(bo):
return True
bo[row][col] = 0
return False
def valid(bo, num, pos):
# Check row
for field in range(len(bo[0])):
if bo[pos[0]][field] == num and pos[1] != field:
return False
# Check column
for line in range(len(bo)):
if bo[line][pos[1]] == num and pos[0] != line:
return False
# Check box
box_x = pos[1] // 3
box_y = pos[0] // 3
for i in range(box_y*3, box_y*3 + 3):
for j in range(box_x * 3, box_x*3 + 3):
if bo[i][j] == num and (i,j) != pos:
return False
return True
def print_board(bo):
for i in range(len(bo)):
if i % 3 == 0 and i != 0:
print("- - - - - - - - - - - - - ")
for j in range(len(bo[0])):
if j % 3 == 0 and j != 0:
print(" | ", end="")
if j == 8:
print(bo[i][j])
else:
print(str(bo[i][j]) + " ", end="")
def find_empty(bo):
for i in range(len(bo)):
for j in range(len(bo[0])):
if bo[i][j] == 0:
return (i, j) # row, col
return None
if __name__ == "__main__":
print_board(board)
solve(board)
print("___________________")
print("")
print_board(board)

Is there a way such that I can refresh a board on the screen instead of having it pile on and on in the console?

I've just completed a Connect Four game and now I'm wondering how I can keep the board in one place without having it refresh over and over again in the console. I've searched far and wide on the web for any solutions but couldn't find anything.
Below is my full code. Feel free to run it on your IDEs. Any help would be greatly appreciated!
import random
import ast
def winner(board):
"""This function accepts the Connect Four board as a parameter.
If there is no winner, the function will return the empty string "".
If the user has won, it will return 'X', and if the computer has
won it will return 'O'."""
row = 0
while row <= len(board) - 1:
count = 0
last = ''
col = 0
while col <= len(board[0]) - 1:
row_win = board[row][col]
if row_win == " ":
count = 0
col += 1
continue
if row_win == last:
count += 1
else:
count = 1
if count >= 4:
return row_win
last = row_win
col += 1
row += 1
col = 0
while col <= len(board[0]) - 1:
count = 0
last = ''
row = 0
while row <= len(board) - 1:
col_win = board[row][col]
if col_win == " ":
count = 0
row += 1
continue
if col_win == last:
count += 1
else:
count = 1
if count >= 4:
return col_win
last = col_win
row += 1
col += 1
row = 0
while row <= len(board) - 1:
col = 0
while col <= len(board[0]) - 1:
try:
if (board[row][col] == board[row + 1][col + 1] and board[row + 1][col + 1] == board[row + 2][
col + 2] and
board[row + 2][col + 2] == board[row + 3][col + 3]) and (
board[row][col] != " " or board[row + 1][col + 1] != " " or board[row + 2][col + 2] != " " or
board[row + 3][col + 3] != " "):
return board[row][col]
except:
IndexError
col += 1
row += 1
row = 0
while row <= len(board) - 1:
col = 0
while col <= len(board[0]) - 1:
try:
if (board[row][col] == board[row + 1][col - 1] and board[row + 1][col - 1] == board[row + 2][
col - 2] and
board[row + 2][col - 2] == board[row + 3][col - 3]) and (
board[row][col] != " " or board[row + 1][col - 1] != " " or board[row + 2][col - 2] != " " or
board[row + 3][col - 3] != " "):
return board[row][col]
except:
IndexError
col += 1
row += 1
# No winner: return the empty string
return ""
def display_board(board):
"""This function accepts the Connect Four board as a parameter.
It will print the Connect Four board grid (using ASCII characters)
and show the positions of any X's and O's. It also displays
the column numbers on top of the board to help
the user figure out the coordinates of their next move.
This function does not return anything."""
header = " "
i = 1
while i < len(board[0]):
header = header + str(i) + " "
i += 1
header = header + str(i)
print(header)
separator = "+---+"
i = 1
while i < len(board[0]):
separator = separator + "---+"
i += 1
print(separator)
for row in board:
print(" ", " | ".join(row))
separator = "+---+"
i = 1
while i < len(board[0]):
separator = separator + "---+"
i += 1
print(separator)
print()
def make_user_move(board):
"""This function accepts the Connect Four board as a parameter.
It will ask the user for a row and column. If the row and
column are each within the range of 1 and 7, and that square
is not already occupied, then it will place an 'X' in that square."""
valid_move = False
while not valid_move:
try:
col_num = "What col would you like to move to (1 - " + str(len(board[0])) + ")? "
col = int(input(col_num))
if board[0][col - 1] != ' ':
print("Sorry, that column is full. Please try again!\n")
else:
col = col - 1
for row in range(len(board) - 1, -1, -1):
if board[row][col] == ' ' and not valid_move:
board[row][col] = 'X'
valid_move = True
except:
ValueError
print("Please enter a valid option! ")
return board
def make_computer_move(board):
"""This function accepts the Connect Four board as a parameter.
It will randomly pick row and column values between 0 and 6.
If that square is not already occupied it will place an 'O'
in that square. Otherwise, another random row and column
will be generated."""
computer_valid_move = False
while not computer_valid_move:
col = random.randint(0, len(board) - 1)
if board[0][col] != ' ':
print("Sorry, that column is full. Please try again!\n")
else:
for row in range(len(board) - 1, -1, -1):
if board[row][col] == ' ' and not computer_valid_move:
board[row][col] = 'O'
computer_valid_move = True
return board
def main():
"""The Main Game Loop:"""
cf_board = []
row = int(input("How many rows do you want your game to have? "))
col = int(input("How many columns do you want your game to have? "))
move_order = input("Would you like to move first? (y/n) ")
while move_order.lower() != "y" and move_order.lower() != "n":
print("Invalid input! Please choose y (yes) or n (no) - case insensitive. ")
move_order = input("Would you like to move first? (y/n) ")
if move_order.lower() == "y":
users_turn = True
elif move_order.lower() == "n":
users_turn = False
free_cells = col * row
row_str = "\" \""
board_str = "\" \""
i = 0
j = 0
while i < col - 1:
row_str = row_str + "," + "\" \""
i += 1
board_list = [row_str]
while j < row - 1:
board_list.append(row_str)
j += 1
cf_board = [list(ast.literal_eval(x)) for x in board_list]
# for i in range(row-1):
# cf_board.append(row_str)
while not winner(cf_board) and (free_cells > 0):
display_board(cf_board)
if users_turn:
cf_board = make_user_move(cf_board)
users_turn = not users_turn
else:
cf_board = make_computer_move(cf_board)
users_turn = not users_turn
free_cells -= 1
display_board(cf_board)
if (winner(cf_board) == 'X'):
print("Y O U W O N !")
elif (winner(cf_board) == 'O'):
print("T H E C O M P U T E R W O N !")
elif free_cells == 0:
print("S T A L E M A T E !")
print("\n*** GAME OVER ***\n")
# Start the game!
main()
I guess the idea you want to implement is similar to make a terminal based progress bar;
For example on unix/linux systems you can update a progress bar or a simple sentence in one place with "\r" character instead of "\n" which used on print() function by default:
from sys import stdout
from time import sleep
def realtime_sentence():
name = 0
while name <= 100:
stdout.write("\r My name is {}".format(name))
name += 1
sleep(0.2)
def realtime_progress_bar():
progress = 0
while progress <= 100:
stdout.write("\r Progress: {} {}%".format(progress*"#", progress))
progress += 1
sleep(0.2)
realtime_sentence()
realtime_progress_bar()
Also check this question:
Rewrite multiple lines in the console

Can someone help explain the recursion in this back tracking algorithm?

This is a program that solves a sudoku board using python and the back-tracking algorithm, but I don't seem to understand the recursion in solve(bo). Like it seems like if the condition is not met, then the index is reset to 0 and it continues to try numbers at the same position.
Can someone help explain in simpler terms perhaps, how the function back tracks and rechecks conditions?
board = [
[7,8,0,4,0,0,1,2,0],
[6,0,0,0,7,5,0,0,9],
[0,0,0,6,0,1,0,7,8],
[0,0,7,0,4,0,2,6,0],
[0,0,1,0,5,0,9,3,0],
[9,0,4,0,6,0,0,0,5],
[0,7,0,3,0,0,0,1,2],
[1,2,0,0,0,7,4,0,0],
[0,4,9,2,0,6,0,0,7]
]
def solve(bo):
find = find_empty(bo)
if not find:
return True
else:
row, col = find
for i in range(1,10):
if valid(bo, i, (row, col)):
bo[row][col] = i
if solve(bo):
return True
bo[row][col] = 0
return False
def valid(bo, num, pos):
# Check row
for i in range(len(bo[0])):
if bo[pos[0]][i] == num and pos[1] != i:
return False
# Check column
for i in range(len(bo)):
if bo[i][pos[1]] == num and pos[0] != i:
return False
# Check box
box_x = pos[1] // 3
box_y = pos[0] // 3
for i in range(box_y*3, box_y*3 + 3):
for j in range(box_x * 3, box_x*3 + 3):
if bo[i][j] == num and (i,j) != pos:
return False
return True
def print_board(bo):
for i in range(len(bo)):
if i % 3 == 0 and i != 0:
print("- - - - - - - - - - - - - ")
for j in range(len(bo[0])):
if j % 3 == 0 and j != 0:
print(" | ", end="")
if j == 8:
print(bo[i][j])
else:
print(str(bo[i][j]) + " ", end="")
def find_empty(bo):
for i in range(len(bo)):
for j in range(len(bo[0])):
if bo[i][j] == 0:
return (i, j) # row, col
return None
print_board(board)
solve(board)
print("___________________")
print_board(board)
Right! So the way this solution operates is it finds the next empty field on the board, attempts to insert number from range 1..9 there and then check the validity. The validity check is a tentative answer to whether a given number is correct, i.e. whether it does not produce a violation of the rules. If so, the number gets inserted into the array and solve is called recursively. Now, here the implicit backtracking is taking place. If this recursive call to solve fails to produce a fully consistent solution to the puzzle, then the whole "branch" starting with our tentative guess gets removed from the call stack, the failed guess is reset on the board (removed), and we continue to the next guess.

Customisation on Connect 4 game

I am currently working on a connect 4 game in python and I was hoping to allow the player to customise the board (be able to choose the size of the board. However when I try to add this in it breaks my code. Is there any way around this? Or will I just have to hard code the board size in?
def CreateBoard(r, c, b, n):
for i in range(1,(r+1)):
n.append(str(i))
b.append(n)
for i in range(c):
b.append(['*']*(r))
return(b)
def printBoard(b):
for lst in b:
print(" ".join(lst))
return b
def check(board, n):
n = []
for i in range(1,len(board[1])+1):
if board[1][i-1] == '*':
n.append(i)
print(n)
user = (input('Enter column: '))
if(user.isdigit() == True):
user = int(user)
if (user in n):
return(user)
print('Invalid input')
return check(board, n)
def WinningCon(b, r, u, c):
'row'
loop1 = True
rowCon = ""
colCon = ""
for i in range(0,len(b[1])):
rowCon += b[r][i]
if('X'*4 in rowCon) or('O'*4 in rowCon):
return(True)
for i in range(1,c+1):
colCon += b[i][u-1]
if('X'*4 in colCon) or('O'*4 in colCon):
return(True)
def Diag2(u, r, b, row, column):
utemp1 = u-1
utemp2 = u-1
rtemp1 = r
rtemp2 = r
end = ""
beg = ""
while(True):
beg += b[rtemp1][utemp1]
if(rtemp1 == 1):
break
elif(utemp1 == column):
break
rtemp1 -= 1
utemp1 += 1
while(True):
if(rtemp2 == row-1):
break
elif(utemp2 == 0):
break
rtemp2 +=1
utemp2 -=1
end += b[rtemp2][utemp2]
beg = beg[::-1]
fullstring = beg+end
if('X'*4 in fullstring) or('O'*4 in fullstring):
return(True)
def Diag1(u, r, b, row, column):
utemp1 = u-1
utemp2 = u-1
rtemp1 = r
rtemp2 = r
end = ""
beg = ""
while(True):
beg += b[rtemp1][utemp1]
if(rtemp1 == 1):
break
elif(utemp1 == 0):
break
rtemp1 -= 1
utemp1 -= 1
while(True):
if(rtemp2 == row-1):
break
elif(utemp2 == column):
break
rtemp2 +=1
utemp2 +=1
end += b[rtemp2][utemp2]
beg = beg[::-1]
fullstring = beg+end
if('X'*4 in fullstring) or('O'*4 in fullstring):
return(True)
def ProcessInput(u, s, b, r):
rowNum = r-1
u = u-1
while(not b[rowNum][u] == '*'):
rowNum -= 1
b[rowNum][u] = s
return(rowNum)
def EndGame(g, b, p):
printBoard(b)
print("Congrats %s, you've won!" %p)
replayGame = input('Would you like to play again? Yes or No?\n').lower()
if replayGame == 'yes':
MainGame()
else:
g = False
return(g)
def MainGame():
row = 7 #input('Enter number of rows')
column = 6 #input('Enter number of columns')
board = []
nums = []
board = CreateBoard(row, column, board, nums)
player1 = 'K'#input('Enter name: ')
player2 = 'A'#input('Enter name: ')
turn = 1
GameOn = True
while(GameOn):
board = printBoard(board)
if(not turn%2 == 0):
print("It's %s's turn" %player1)
user = check(board, nums)
rc = ProcessInput(user, "X", board, row)
if(WinningCon(board, rc , user, column) == True):
GameOn = EndGame(GameOn, board, player1)
elif(Diag1(user, rc, board, row, column) == True):
GameOn = EndGame(GameOn, board, player1)
elif(Diag2(user, rc, board, row, column) == True):
GameOn = EndGame(GameOn, board, player1)
else:
print("It's %s's turn" %player2)
user = check(board, nums)
rc = ProcessInput(user, "O", board, row)
if(WinningCon(board, rc , user, column) == True):
GameOn = EndGame(GameOn, board, player2)
elif(Diag1(user, rc, board, row, column) == True):
GameOn = EndGame(GameOn, board, player2)
elif(Diag2(user, rc, board, row, column) == True):
GameOn = EndGame(GameOn, board, player2)
turn +=1
MainGame()
An example of an error message it throws up:
Enter number of columns4
Enter number of rows5
1 2 3 4
* * * *
* * * *
* * * *
* * * *
* * * *
It's K's turn
[1, 2, 3, 4]
Enter column: 4
Traceback (most recent call last):
File "C:\Users\609380145\Python\Code Dojo\Connect 4\Connect 4 v3.py", line 169, in <module>
MainGame()
File "C:\Users\609380145\Python\Code Dojo\Connect 4\Connect 4 v3.py", line 150, in MainGame
GameOn = EndGame(GameOn, board, player1)
File "C:\Users\609380145\Python\Code Dojo\Connect 4\Connect 4 v3.py", line 127, in EndGame
MainGame()
File "C:\Users\609380145\Python\Code Dojo\Connect 4\Connect 4 v3.py", line 153, in MainGame
elif(Diag2(user, rc, board, row, column) == True):
File "C:\Users\609380145\Python\Code Dojo\Connect 4\Connect 4 v3.py", line 66, in Diag2
beg += b[rtemp1][utemp1]
IndexError: list index out of range
def CreateBoard(r, c, b, n):
for i in range(1,(r+1)):
n.append(str(i))
b.append(n)
for i in range(c):
b.append(['*']*(r))
return(b)
def printBoard(b):
for lst in b:
print(" ".join(lst))
return b
def check(board, n):
n = []
for i in range(1,len(board[1])+1):
if board[1][i-1] == '*':
n.append(i)
print(n)
user = (input('Enter column: '))
if(user.isdigit() == True):
user = int(user)
if (user in n):
return(user)
print('Invalid input')
return check(board, n)
def WinningCon(b, r, u, c):
loop1 = True
rowCon = ""
colCon = ""
for i in range(0,len(b[1])):
rowCon += b[r][i]
if('X'*4 in rowCon) or('O'*4 in rowCon):
return(True)
for i in range(1,c+1):
colCon += b[i][u-1]
if('X'*4 in colCon) or('O'*4 in colCon):
return(True)
def Diag2(u, r, b, column, row):
utemp1 = u-1
utemp2 = u-1
rtemp1 = r
rtemp2 = r
end = ""
beg = ""
while(True):
beg += b[rtemp1][utemp1]
rtemp1 -= 1
utemp1 += 1
if(rtemp1 == 1):
break
elif(utemp1 >= column - 1):
break
while(True):
end += b[rtemp2][utemp2]
rtemp2 +=1
utemp2 -=1
if(rtemp2 >= row):
break
elif(utemp2 == 0):
break
beg = beg[::-1]
fullstring = beg+end
if('X'*4 in fullstring) or('O'*4 in fullstring):
return(True)
def Diag1(u, r, b, column, row):
utemp1 = u-1
utemp2 = u-1
rtemp1 = r
rtemp2 = r
end = ""
beg = ""
while(True):
beg += b[rtemp1][utemp1]
rtemp1 -= 1
utemp1 -= 1
if(rtemp1 == 1):
break
elif(utemp1 == 0):
break
while(True):
print('Row ' + str(rtemp2))
print('Colum ' +str(utemp2))
end += b[rtemp2][utemp2]
rtemp2 +=1
utemp2 +=1
if(rtemp2 >= row):
break
elif(utemp2 >= column-1):
break
beg = beg[::-1]
fullstring = beg+end
if('X'*4 in fullstring) or('O'*4 in fullstring):
return(True)
def ProcessInput(u, s, b, r):
rowNum = r
u = u-1
print('Row: ' + str(rowNum))
print('Col: ' + str(u))
while(not b[rowNum][u] == '*'):
rowNum -= 1
print('New Row Num: ' + str(rowNum))
b[rowNum][u] = s
printBoard(b)
return(rowNum)
def EndGame(g, b, p):
printBoard(b)
print("Congrats %s, you've won!" %p)
replayGame = input('Would you like to play again? Yes or No?\n').lower()
if replayGame == 'yes':
MainGame()
else:
g = False
return(g)
def MainGame():
column = int(input('Enter number of columns'))
row = int(input('Enter number of rows'))
board = []
nums = []
board = CreateBoard(column, row, board, nums)
player1 = 'K'#input('Enter name: ')
player2 = 'A'#input('Enter name: ')
turn = 1
GameOn = True
while(GameOn):
board = printBoard(board)
user = check(board, nums)
if(turn%2 != 0):
print("It's %s's turn" %player1)
rc = ProcessInput(user, "X", board, row)
else:
print("It's %s's turn" %player2)
rc = ProcessInput(user, "O", board, row)
if(WinningCon(board, rc , user, row) == True):
GameOn = EndGame(GameOn, board, player1)
elif(Diag1(user, rc, board, column, row) == True):
GameOn = EndGame(GameOn, board, player1)
elif(Diag2(user, rc, board, column, row) == True):
GameOn = EndGame(GameOn, board, player1)
turn +=1
MainGame()

Categories

Resources