Unable to modify variable outside of the method - python

I'm trying to make a bot for a sudoku game. It seem to work, but there's a small problem the solved grid is only printed inside the method. When I run it, the print(game.board) print the unsolved one.
this is my code:
import numpy as np
class Game:
def solve(self):
def possible(y,x,n):
for i in range(9):
if self.board[y][i] == n:
return(False)
for i in range(9):
if self.board[i][x] == n:
return(False)
gridx = (x // 3) * 3
gridy = (y // 3) * 3
for i in range(3):
for j in range(3):
if self.board[gridy + i][gridx + j] == n:
return(False)
return(True)
def solving():
for y in range(9):
for x in range(9):
if self.board[y][x] == 0:
for n in range(1,10):
if possible(y,x,n):
self.board[y][x] = n
solving()
self.board[y][x] = 0
return
print(np.matrix(self.board))
solving()
game = Game()
game.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]
]
game.solve()
print(game.board)

Your code is calling recursively solving() however, it unsets the tried out numbers afterwards.
What you had to do is abort as soon as you find a solution.
Just change solving, such, that it stops when a solution is found:
def solving():
for y in range(9):
for x in range(9):
if self.board[y][x] == 0:
for n in range(1,10):
if possible(y,x,n):
self.board[y][x] = n
solved = solving()
if solved:
return True
self.board[y][x] = 0
return False
return True
solving()
Bonus:
Here a flattened out version (without function nesting) of your solver:
I also added an __init__ function, so that the board is passed to the class.
import numpy as np
class Game:
def __init__(self, board):
self.board = board
def possible(self, y, x, n):
for i in range(9):
if self.board[y][i] == n:
return False
for i in range(9):
if self.board[i][x] == n:
return False
gridx = (x // 3) * 3
gridy = (y // 3) * 3
for i in range(3):
for j in range(3):
if self.board[gridy + i][gridx + j] == n:
return False
return True
def solving(self):
for y in range(9):
for x in range(9):
if self.board[y][x] == 0:
for n in range(1,10):
if self.possible(y,x,n):
self.board[y][x] = n
solved = self.solving()
if solved:
return True
self.board[y][x] = 0
return False
return True
def solve(self):
self.solving()
return self.board
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]
]
game = Game(board)
print(np.matrix(game.board))
game.solve()
print(np.matrix(game.board))

Currently, once a solution is found, the backtracking still sets each cell to zero and when the solve call returns, you're left with your original board.
This design is quite awkward, though. Typically, you'd not reach into a class and set a self property from outside:
game.board = [...]
This breaks encapsulation. The Game class' logic will fail if the caller doesn't do this properly. Better to pass a parameter into the initializer or into the solve function. Since solving sudoku is stateless and is done here with just a couple of functions, it feels odd to create an object.
Game is a vague class name. SudokuSolver is clearer.
Similarly, solving is confusingly named; method names should be commands or actions, not participles.
return is not a function: return True rather than return(True).
Avoid 5-6 level nested loops and conditional blocks. Such code is difficult to reason about. Work can be saved by precomputing all of the empty positions once, then skipping all other squares.
Here's a quick rewrite with room for improvement:
class SudokuSolver:
#staticmethod
def possible_move(board, x, y, n):
for i in range(9):
if board[y][i] == n or board[i][x] == n:
return False
grid_x = x // 3 * 3
grid_y = y // 3 * 3
for i in range(3):
for j in range(3):
if board[grid_y+i][grid_x+j] == n:
return False
return True
#staticmethod
def solve(board):
empty_squares = [(x, y) for y, row in enumerate(board)
for x, n in enumerate(row) if n == 0]
def backtrack(i=0):
if i >= len(empty_squares):
return board
x, y = empty_squares[i]
for n in range(1, 10):
if SudokuSolver.possible_move(board, x, y, n):
board[y][x] = n
if soln := backtrack(i + 1):
return soln
board[y][x] = 0
return backtrack()
if __name__ == "__main__":
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]
]
if soln := SudokuSolver.solve(board):
print("\n".join(",".join(map(str, x)) for x in soln))
else:
print("unsolvable board")

Related

Having trouble getting Miller-Rabin primality test in Python

I have been trying to implement Miller-Rabin primality test in Python. Unfortunately there seems to be a problem on some prime numbers. Any help is appreciated.
Code:
def _isPrime(n):
if n % 2 == 0:
return False
a = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]
s, d = _Apart(n) # turns it into 2^s x d
print(s, d)
basePrime = False
isPrime = True
for base in a:
if base >= n-2:
break
if isPrime == False and basePrime == False:
return False
witness = pow(base, d)
if (witness % n) == 1 or (witness % n) == (n-1):
basePrime = True
continue
else:
basePrime = False
for r in range(1, s):
witness = pow(base, pow(2, r) * d)
if (witness % n) != ( n - 1 ):
isPrime = False
return True
Test:
isPrime(17)
Expected:
True
Result:
False
I wrote a Miller Rabin test that is deterministic, no need for random numbers. This implementation is for python 3.7. In python 3.8, llinear_diophantinex can be replaced with pow(x, -1, y). Also i used gmpy2 as it's very fast, but you can just replace the gmpy2 statements with normal pow if you can't use that, and just remove the gmpy2.mpz() wrappers since those are just used to overload operators.
import gmpy2
sinn = 2110229697309202254897383305762150945330987087513434511395506048950594976569434432057019507105035289374307720719984431280856161609820548842778454256113246763860786119268583367543952735347969627478873317341364209555365064365565504232770227619462128918701942169785585423104678142850200975026619010035331023744330713985615650556129731348659986462960062760308034462660525448390420668021248422741300646552941285862310410598374242189448623917196191138254637812716211329113836605859918549332304189053950819346551095911511755911832183789503704294770046935064469435830299623205136625543859303686699678929069468518950480476841246805908501510754550017255944080874819287974625925494008373883250410775902993163965873632474224574883242826458163446781002284368017611606202344050570737818087202137703099075773680753707346415849787963446390136517016131227807076254668461445862154978026041507116570585784569893773262639243954090283224759975513502582494002154146757110676408972377044584495342170277522887809749465855954126593100747444378301829661568735873345178089061677917127496915956539418931430313218084338374827152407795095072639044306222222695685778907958272820576498682506540189586657786292950574081739269257159839589987847266550007783514316481286222515710538845836151864127815058116482680058626451349913138908040817800742009650450811565324184631847563730941344941348929727603343965091116543702880556850922077216848669966268219928808236163268726995495688157209747596437162960244538054993785127947211290438554095851924381172697827312534174244295581184309147813790451951453564726742200569263225639113681905176376701339808868274637448606821696026703034737428319530072483125495383057919894902076566679023694181381398377144302767983385253577700652358431959604517728821603076762965129019244904679015099154368058005173028200266632883632953133017055122970338782493475762548347258351148037427739052271661340801912188203749647918379812483260399614599813650518046331670764766419886619324840045611486524123102046413946014624119568013100078163986683199814025915420877588778260860713148420321896163326473203441644820182490479899368048072263481024886708136521847014624735722333931331098969321911443978386868675912141648200500219168920887757573018380579532261231821382787339600631297820996466930957801607217549420247654458172818940238337170577825003408756362106088558651381993611741503374243481167926898332728164900189941804942580426055589622673679047058619682175301326905577843405270203660160407401675700528981573327582844330828861745574031416926871562443652858767649050943181353635950301154441954046214987718582670685455252774874198771086552440702483933126644594300464549471422237478151976561680719370424626162642534252062987911763456822609569209140676822858933588602318066530038691463577379331113471591913447226829868760176810195567325921301390329055242213842898142597360121925124635965685365925901913816717677946911762631634793638450106377437599347740569467683272089859392249351406815344105961234868327316964137925419770514177021722214309784062017826024217906664090209434553785436385765927274067126192143337589109608949427467825999057058702263715338956534536892852849984934736685814891286495169007648767081688963426768409476169071460997622740467533572971356017575900999100928776382541052696124463195981888715845688808970103527288822088031150716134784735332326775370417950625124642515148342694377095213470544739900830244879573205335578256682901821773047071352497997708791157012233232529777513203024818391621220967964874173106990772425289900446640237659116713251437567138729645677868024033209183367071421651937808005637679844370347367922676824239404492688418047080583797577102267329067247758368597488680401670673861120323439239792549053895366970423259196919428554146265587250617656401028722578111927104663315250291888502226235291264834968061065817079511872899991276288365723969841290984981957389126603952133124328219936785870274843554107325931034103072894378438818494802517594594270034007832922248742746517915210656205746338575621725899098414488628833412591266637224507533934158213117522503993423240638893845121918647788013
def llinear_diophantinex(a, b, divmodx=1, x=1, y=0, offset=0, withstats=False, pow_mod_p2=False):
origa, origb = a, gmpy2.mpz(b)
r=a
q = a//b
prevq=1
if a == 1:
return 1
if withstats == True:
print(f"a = {a}, b = {b}, q = {q}, r = {r}")
while r != 0:
prevr = r
a,r,b = b, b, r
q,r = divmod(a,b)
x, y = y, x - q * y
if withstats == True:
print(f"a = {a}, b = {b}, q = {q}, r = {r}, x = {x}, y = {y}")
y = gmpy2.mpz(1 - origb*x // origa - 1)
if withstats == True:
print(f"x = {x}, y = {y}")
x,y=y,x
modx = (-abs(x)*divmodx)%origb
if withstats == True:
print(f"x = {x}, y = {y}, modx = {modx}")
if pow_mod_p2==False:
return (x*divmodx)%origb, y, modx, (origa)%origb
else:
if x < 0: return (modx*divmodx)%origb
else: return (x*divmodx)%origb
def ffs(x):
"""Returns the index, counting from 0, of the
least significant set bit in `x`.
"""
return (x&-x).bit_length()-1
def MillerRabin(arglist):
N = arglist[0]
primetest = arglist[1]
iterx = arglist[2]
powx = arglist[3]
withstats = arglist[4]
primetest = gmpy2.powmod(primetest, powx, N)
if withstats == True:
print("first: ", primetest)
if primetest == 1 or primetest == N - 1:
return True
else:
for x in range(0, iterx):
primetest = gmpy2.powmod(primetest, 2, N)
if withstats == True:
print("else: ", primetest)
if primetest == N - 1: return True
if primetest == 1: return False
return False
def sfactorint_isprime(N, withstats=False):
N = gmpy2.mpz(N)
from multiprocessing import Pool
if N <= 1: return False
if N == 2:
return True
if N % 2 == 0:
return False
if N < 2:
return False
# Add Trial Factoring here to speed up smaller factored number testing
iterx = ffs(N-1)
""" This k test is an algorithmic test builder instead of using
random numbers. The offset of k, from -2 to +2 produces pow tests
that fail or pass instead of having to use random numbers and more
iterations. All you need are those 5 numbers from k to get a
primality answer.
"""
k = llinear_diophantinex(N, 1<<N.bit_length(), pow_mod_p2=True) - 1
t = N >> iterx
tests = [k-2, k-1, k, k+1, k+2]
for primetest in range(len(tests)):
if tests[primetest] >= N:
tests[primetest] %= N
arglist = []
for primetest in range(len(tests)):
if tests[primetest] >= 2:
arglist.append([N, tests[primetest], iterx, t, withstats])
with Pool(5) as p:
s=p.map(MillerRabin, arglist)
if s.count(True) == len(arglist): return True
else: return False
return s
Recently I also tried to implement this algorithm in the deterministic form, as shown in Miller Test, and ran into the same problem. I couldn't figure out why it failed for some numbers so I decided to implement the 'complete' Miller-Rabin Test and it worked.
I should warn that it gets slow quickly as n increases. It's advised to use some numeric library like Numpy to optimize the calculations.
With some tweaks on your code it can be achieved:
import random
def _isPrime(n):
if n % 2 == 0:
return False
rounds = 40 # Determines the accuracy of the test
s, d = _Apart(n) # Turns it into 2^s x d + 1
for _ in range(rounds):
base = random.randrange(2, n-1) # Randomly selects a base
witness = pow(base, d)
if (witness % n) == 1 or (witness % n) == (n-1):
continue
for _ in range(1, s):
witness = pow(witness, 2) % n
if witness == (n-1):
break
else: # if the for-loop is not 'broken', n is not prime
return False
return True
def is_prime(n):
"""returns True if n is prime else False"""
if n < 5 or n & 1 == 0 or n % 3 == 0:
return 2 <= n <= 3
s = ((n - 1) & (1 - n)).bit_length() - 1
d = n >> s
for a in [2, 325, 9375, 28178, 450775, 9780504, 1795265022]:
p = pow(a, d, n)
if p == 1 or p == n - 1 or a % n == 0:
continue
for _ in range(s):
p = (p * p) % n
if p == n - 1:
break
else:
return False
return True

Recursive Sudoku solver not solving anything

I was working on a Sudoku solver, and when I ran it, it just didn't work- the function f returned a none type. After debugging, I found out the code didn't solve some of the squares. I don't know why this happened, but I suspect the loop checking all the numbers possible in a square stops after finding one possible number and doesn't check the rest too. Can you please pinpoint me the problem in my code? Thanks.
Note: for empty spaces in the Sudoku, enter 0.
# enter the Sudoku as a two-dimensional array (a[i][j])
def square_check(array, loc_x, loc_y, val):
added_x = loc_x - (loc_x % 3)
added_y = loc_y - (loc_y % 3)
for i in range(3):
for j in range(3):
if i+added_y != loc_y or j+added_x != loc_x:
if array[i+added_y][j+added_x] == val:
return False
return True
def line_check(array, loc_x, loc_y, val):
for i in range(9):
if i != loc_x:
if array[loc_y][i] == val:
return False
return True
def col_check(array, loc_x, loc_y, val):
for i in range(9):
if i != loc_y:
if array[i][loc_x] == val:
return False
return True
def f(array):
flag = True
mark = True
for i in range(0, 9):
for j in range(0, 9):
if array[i][j] == 0:
flag = False
if flag:
return array
for i in range(0, 9):
for j in range(0, 9):
if array[i][j] == 0:
for num in range(1, 10):
if square_check(array, j, i, num):
if col_check(array, j, i, num):
if line_check(array, j, i, num):
new_array = array.copy()
new_array[i][j] = num
mark = False
f(new_array)
if mark:
break
def to_str(array):
for i in range(len(array)):
print(array[i])
print("")
to_str(f(sudoku))

Global variable resets in Python

I created a sudoku solver with backtracking algorithm (Python 3.8). It is a recursive algorithm. The sudoku board (puzzle) is a global variable (multiple functions need to share it). The solve() function does its task, but the value of the board doesn't change even after using the global keyword. Your help is needed.
The code:
board = [
[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,7,9]]
def isPossible(y, x, val): # checks if it is legal to put a value at a certain position
for row in board: # row condition
if val == row[x]:
return False
for col in board[y]: # column condition
if val == col:
return False
# subcell condition
subCellRow = (y // 3) * 3
subCellCol = (x // 3) * 3
for row in board[subCellRow:subCellRow + 3]:
for col in row[subCellCol:subCellCol + 3]:
if val == col:
return False
return True
def solve():
global board
for y in range(9):
for x in range(9):
if board[y][x] == 0:
for n in range(1, 10):
if isPossible(y, x, n): # python stairs
board[y][x] = n
solve() # recursion starts
board[y][x] = 0 # 1-line backtracking algorithm
return
printPuzzle() # prints the solved puzzle
return True
def printPuzzle(): # to display the puzzle
print()
for row in board:
for val in row:
print(val, end = ' ')
print()
printPuzzle()
solve()
printPuzzle() # prints the unsolved board
This wasn't the mistake of the global variable, this is happening because there is a slight mistake in your implementation of the algorithm which is reassigning the value to zero at board[y][x] = 0.
Here is the implementation which I think is correct.
board = [
[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,7,9]]
def isPossible(y, x, val): # checks if it is legal to put a value at a certain position
for row in board: # row condition
if val == row[x]:
return False
for col in board[y]: # column condition
if val == col:
return False
# subcell condition
subCellRow = (y // 3) * 3
subCellCol = (x // 3) * 3
for row in board[subCellRow:subCellRow + 3]:
for col in row[subCellCol:subCellCol + 3]:
if val == col:
return False
return True
def solve():
global board
for y in range(9):
for x in range(9):
if board[y][x] == 0:
for n in range(1, 10):
if isPossible(y, x, n): # python stairs
board[y][x] = n
if solve():
return True # recursion starts
board[y][x] = 0
return False
printPuzzle() # prints the solved puzzle
return True
def printPuzzle(): # to display the puzzle
print()
for row in board:
for val in row:
print(val, end = ' ')
print()
printPuzzle()
solve()
printPuzzle() # prints the unsolved board
Output I am getting:

how to change print in the end of the function for return?

I found a sudoku solver code however, I need the function to return the grid instead of printing it. Any idea how?
import numpy as np
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,0,0,7,0,0]
]
def checker(y,x,n):
global grid
for i in range(0,9):
if grid[y][i] == n:
return False
for i in range(0,9):
if grid[i][x] == n:
return False
x0 = (x//3)*3
y0 = (y//3)*3
for i in range(0,3):
for j in range(0,3):
if grid[y0+i][x0+j] == n:
return False
return True
def solver(grid):
for y in range(9):
for x in range(9):
if grid[y][x] == 0:
for n in range(1,10):
if checker(y,x,n):
grid[y][x] = n
solver(grid)
grid[y][x] = 0
return
print(np.matrix(grid))
input("More?")
solver(grid)
This function does give you the correct solution however, I would like to call this function in my other project but I am not able to as the output is a print and not the grid itself.
Thanks!
On "def solver" function change print to return. Then call the function like , a=solver(grid) so the returned value is stored in the a variable.

Vector's cross product and if statement in function

My program is working but not all of it's parts, I listed my problems in comment of program
class MyVector:
def __init__(self, vector):
self.vector = vector
def get_vector(self):
return self.vector
def __mul__(self, other):
scalar_result = 0 # or 0.0
for i in range(0, len(self.vector)):
scalar_result += self.vector[i] * other.vector[i]
return scalar_result
def is_perpendicular_to(self, other): #is there a way that I could make function which will print wheter they are perpendicular or not?
if (scalar_result == 0): #this isn't seem to work
print("They are perpendicular")
"""
Also I was hoping that I can get crossdot product of these two vectors, but I can not make it functional
def crossProd(vector):
dimension = len(a)
c = []
for i in range(dimension):
c.append(0)
for j in range(dimension):
if j <> i:
for k in range(dimension):
if k <> i:
if k > j:
c[i] += a[j] * b[k]
elif k < j:
c[i] -= a[j] * b[k]
return c
"""
if __name__ == "__main__":
vec1 = MyVector([1, 0, 3, 0])
vec2 = MyVector([0, 4, 0, 4])
print(vec1.get_vector())
print(vec2.get_vector())
scalar_result = vec1 * vec2
print(scalar_result)
In the upper part I created logical algorithm that I think should work, but I can't put it to the program, for me it is not functional

Categories

Resources