Recursion function cooperating with another function python - python

I am trying to make a game solver. It should be able to solve Sudoku i.e.
find each possible number useable in each square.
This is what I have:
def next_possible_moves(board,row,col):
possible_moves = set(range(1,len(board)+1))
rows = set(board[row])
cols = []
for j in range(0,len(board)):
cols.append(board[j][col])
cols = set(cols)
possible_moves = possible_moves - rows.union(cols)
return list(possible_moves)
def solve(board):
for i in range(0,len(board)):
if len(board) == 8 and len(board[i]):
print "Found a solution:", board
return True
for next_move in next_possible_moves(board):
if is_valid(board, next_move):
if solve(board + [next_move]):
return True
return False
Both are working, but I am not able to get them to work together. I am using recursion to make it use one number, and while going through the code, it will backtrack if it fails.
What I want is for next_possible_moves to use only one parameter, so I can remove "row" and "col".
Using a list with X lists inside, so it represent an "X times X" board.

Related

Python noob question. Looping through all to find correct combination

Sorry for noob question. Just started learning coding with Python - beginners level.
Wasn't able to find in the net what I require.
Creating function to loop through the entire line, in order to find right combination - 7,8,9 - regardless of input length and of target position, and return 'true' if found. Wasn't able to devise the function correctly. Not sure how to devise function clearly and at all this far.
Your help is much appreciated.
This is what I came up with so far (not working of course):
def _11(n):
for loop in range(len(n)):
if n[loop]==[7,8,9]:
return True
else:
return False
print(_11([1000,10,11,34,67,89,334,5567,6534,765,2,3,5,6,112,7,8,9,11111]))
It always returns False. Tried with (*n) to no avail.
The answer offered by #Carson is entirely correct.
I offer this not really as an answer to the question but as an alternative and more efficient approach.
In OP's question he is looking for an occurrence of 3 consecutive values described by way of a list. Let's call that a triplet.
If we iterate over the input list one element at a time we create lots of triplets before comparing them.
However, we can make this more efficient by searching the input list for any occurrence of the first item in the target triplet. In that way we are likely to slice the input list far less often.
Here are two implementations with timings...
from timeit import timeit
def _11(n, t):
offset = 0
lt = len(t)
m = len(n) - lt
while offset < m:
try:
offset += n[offset:].index(t[0])
if n[offset:offset+lt] == t:
return True
offset += 1
except ValueError:
break
return False
def _11a(n, t):
for index in range(len(n) - len(t)):
if n[index:index + len(t)] == t:
return True
return False
n = [1000,10,11,34,67,89,334,5567,6534,765,2,3,5,6,112,7,8,9,11111]
t = [7, 8, 9]
for func in _11, _11a:
print(func.__name__, timeit(lambda: func(n, t)))
Output:
_11 0.43439731000012216
_11a 1.8685798310000337
There are two mistakes with your code.
Indexing into a loop returns 1 element, not multiple. When you write n[loop], you're getting 1 value, not a list.
You shouldn't return false that early. Your code exits after the first step in the loop, but it should go through the entire loop before returning false.
Consider the following snippet:
def has_subarr(arr, subarr):
"""Tests if `subarr` exists in arr"""
for i in range(len(arr)):
if arr[i:i+len(subarr)] == subarr:
return True
return False
This code is more general than your example, it accepts the value to check for as another argument. Notice the use of : in the array access. This allows you to return multiple elements in an array. Also notice how the return False is only reached once the entire loop has completed.
First, n[loop] return a single element, not a sublist. You should use n[loop+3]. But this will introduce a problem where loop+3 exceeds the length of the list. So the solution may be:
def _11(n):
for loop in range(len(n)-3):
if n[loop:loop+3]==[7,8,9]:
return True
else:
return False
print(_11([1000,10,11,34,67,89,334,5567,6534,765,2,3,5,6,112,7,8,9,11111]))
Your actual code return during the first iteration. You only test once. You must modify the indentation as in:
def _11(n):
target = [7,8,9]
for index in range( len(n) - len(target)):
if n[index:index + len(target)] == [7,8,9]:
return True
return False
print(_11([1000,10,11,34,67,89,334,5567,6534,765,2,3,5,6,112,7,8,9,11111]))
You can try checking the str representation of the 2 lists:
import re
def _11(n):
if re.search("(?<![0-9-.'])7, 8, 9(?![0-9.])",str(n)):
return True
return False
print(_11([27,8,9]))
The Output:
False

How to make this greedy function faster?

I am trying to solve a problem and my code fails at one test case where the list is of length 25000. Is there any way I can make this faster. I tried using functools.lru_cache and I still can not run within the time required to complete.
This is the problem from the site
Given an array of non-negative integers nums, you are initially
positioned at the first index of the array.
Each element in the array represents your maximum jump length at that
position.
Determine if you are able to reach the last index.
This is what I have tried
def can_jump(input_list):
#lru_cache
def helper(idx = 0):
if idx == len(input_list) - 1:
return True
return any(helper(new_idx) for x in range(input_list[idx]) \
if (new_idx := idx + x + 1) < len(input_list)) # increasing order of jumps
return helper()
Sample test cases work
input_list = [2,3,1,1,4]
print(can_jump(input_list)) # True
input_list = [3,2,1,0,4]
print(can_jump(input_list)) # False
I have also tried going from the other direction,
return any(helper(new_idx) for x in range(input_list[idx], 0, -1) \
if (new_idx := idx + x) < len(input_list)) # decreasing order of jumps
But I still can not make this run fast enough to clear the last test case of 25000 element list, what is it that I am doing wrong here?
Ok, I think I get it. Can you try this? Please note, this is taken straight from: https://codereview.stackexchange.com/questions/223612/jump-game-leetcode
def canjump(nums):
maximum_reachable_index = 0
for index, max_jump in enumerate(nums):
if index > maximum_reachable_index:
return False
maximum_reachable_index = max(index + max_jump, maximum_reachable_index)
return True

Trouble understanding this sudoku solver recursion function (python)

So basically I decided to make a sudoku solver in python and recursive functions is most efficient, but I've been trying to understand this code from a youtuber and don't understand why each space (bo[row][col]) doesn't immediately reset to 0. The resetting of one space to 0 only occurs if solve(bo) is True, but if I look through the code, the board will only return True if the board is completely solved, so why doesn't this function just lead nowhere since solve(bo) will never be True?
def solve(bo):
find = find_empty(bo)
if not find:
return True # This is the only time that solve(bo) == 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 # Yet here it resets the space to 0 if solve(bo) is False
return False
def valid(bo, num, pos):
for i in range(9):
if bo[pos[0]][i] == num and pos[1] != i:
return False
for i in range(9):
if bo[i][pos[1]] == num and pos[0] != i:
return False
box_x = (pos[1] // 3) * 3
box_y = (pos[0] // 3) * 3
for i in range(box_y, box_y + 3):
for j in range(box_x, box_x + 3):
if bo[i][j] == num and (i, j) != pos:
return False
return True
def find_empty(bo):
for y in range(9):
for x in range(9):
if bo[y][x] == 0:
return (y, x)
return False
There is some discrepancy between your explanation and comments in the code, but I'll do my best to explain the code anyway.
First solve() will try to find the first empty spot (i.e. one that is 0). If it can't find any, then the board is solved so it returns true.
If it does find a spot, then it will try to place numbers 1-9 there and check if it works with the previously entered numbers. Say 7 works (we don't know if 8 or 9 work as well because we haven't checked that yet). So we set the empty space to 7 and then pass this updated board in a recursive call. Essentially, this is like saying "if I force this spot to have the number 7, can you find a solution?"
If the recursive call returns true, it means there is a solution with 7 in that spot and hence the board has a solution, so we return true. If the recursive call to solve() returns false, then we know that there is no solution to the board with 7 in this spot, so we reset this spot to 0 and then try 8 (and then 9 if needed).
The thing to remember is that there is only one board (bo) in all the recursive calls - in other words, all the function calls are operating on the same variable bo. It doesn't create a copy of the board every time you make a recursive call. Lookup 'Pass by reference' and shallow vs. deep copies if you want to learn more about why.

Recursive function for connect four possible moves generation in Python

I am programming a connect four AI for my school project. But first I want to simulate every possible moves on the 6(row)*7(column) before I write the minimax algorithm to work the perfect move for each stage of board.
Instead of using
for a in range(7):
place_player_disk()
complete_set.append
if check_win():
continue
for b in legal_move():
place_AI_disk()
complete_set.append
if check_win()
continue
.... #repeat the nested for loop 42 times
I want to use a neater way of doing it
state0=[['','','','','','',''],['','','','','','',''],['','','','','','',''],['','','','','','',''],['','','','','','',''],['','','','','','',''],['','','','','','','']]
complete_set=[[],[],[],[],[],[]...]
import copy
def playerplacetoken(perimeter,location):
count=0
for row in range(6):
if perimeter[row][location]=='X' or perimeter[row][location]=='Y':
count+=1
perimeter[5-count][location]='X'
def full(perimeter):
free = []
for column in range(7):
if perimeter[0][column] == '':
free.append(column)
return free
def PlacingCPUToken(perimeter,location):
count=0
for row in range (6):
if perimeter[row][location]=='X' or perimeter[row][location]=='Y':
count+=1
perimeter[5-count][location]='Y'
def CheckP(perimeter):
changerow=[0,1,1]
changecolumn=[1,0,1]
Pwin=False
for col in range(7):
for row in range (6):
for change in range (3):
try:
consecutivecount=0
for nochange in range(4):
if perimeter[row+(changerow[change]*(nochange))] [col+(changecolumn[change]*(nochange))]=='X':
consecutivecount+=1
if consecutivecount==4:
Pwin=True
except:
continue
return Pwin
def CheckC(perimeter):
changerow=[0,1,1]
changecolumn=[1,0,1]
Cwin=False
for col in range(7):
for row in range (6):
for change in range (3):
try:
consecutivecount=0
for nochange in range(4):
if perimeter[row+(changerow[change]*(nochange))][col+(changecolumn[change]*(nochange))]=='Y':
consecutivecount+=1
if consecutivecount==4:
Cwin=True
except:
continue
return Cwin
def recursive(state,move): #state: the state of board, first starts with an empty board and as the function loops, the state changes Move: no of moves taken by both the player and the computer
for a in full(state): #full returns a list of legal moves, which means columns that are not full
state1= copy.deepcopy(state)
playerplacetoken(state1, a)
complete_set[move].append(state1)
if CheckP(state1): #Check p returns boolean, checking if the player has won
continue
for b in full(state1):
state2= copy.deepcopy(state1)
PlacingCPUToken(state2, b)
complete_set[move+1].append(state2)
if CheckC(state2): #Check C checks if the computer wins and return a boolean
continue
while move<44:
move+=2
recursive(state2,move)
recursive(state0,0)
but this doesn't work properly (I mean it has no error but the results are not correct)
I dont really know how to use a recursive function.Please help!
You do a deep copy of the state to compute further moves.
You create a new complete_set for each recursive invocation.
You never return anything from the recursive step.
Because of this, there's no way for information computed in the nested steps to trickle up to the calling step.
UPDATE: the state is indeed updated by a recursive step: complete_set[...].append(...) does that, because complete_set is global.
Try to think about the type of the function you're trying to write.
E.g. it takes a state and an integer depth level. It returns a list of possible moves, which is empty if the depth it too big.
What you may actually want is a tree of moves, where each element of your list is a pair: (move, [...]). The list contains pairs of the same type: a move with a subtree of moves possible after it, etc. The leaves have an empty set of possible moves.
You might consider calculating the immediate utility function value right when you're building the nodes.
If you make the calculation lazy (using yield and generators), alpha-beta pruning will become easy to implement, too.

Why two while loops one after the other (not inside the other) in Python don't work?

I wrote the code below and I was expecting that, when the first loop ends and doesn't return False, the flow would follow to the second while loop. However, the flow skips the second while loop and simply returns True. Why is that? How can I fix this problem, making the flow after the first while loop go to the second while loop?
square = [[1,2,3,4],[4,3,1,4],[3,1,2,4],[2,4,4,3]]
# this is an auxiliary function
def getSum(lis):
sum = 0
for e in lis:
sum = sum + e
return sum
# here is where the problem is
def check_game(square):
standardSum = getSum(range(1, len(square)+1))
while square: #this is the first while loop
row = square.pop()
print row, 'row', 'sum of row=', getSum(row)
if standardSum != getSum(row):
return False
m = 0
while m < len(square): # the second while loop, which the flow skips
n = 0
col = []
while n < len(square):
col.append(square[n][m])
n = n + 1
print col, 'column'
if standardSum != getSum(col):
print standardSum, ' and sum of col =', getSum(col)
return False
m = m + 1
return True
The first loop only terminates when there are no more items left in square. After the first loop, len(square) will be 0, so the entry condition for the second loop m < len(square) will be False.
FYI your code is very (very very very) un-idiomatic Python -- it's written much more like C.
Here's a rewrite which is much more like Python is normally written.
square = [[1,2,3,4],[4,3,1,4],[3,1,2,4],[2,4,4,3]]
transpose = lambda i: zip(*i)
def is_magic(square):
n = len(square)
s = n*(n+1)/2
return all(sum(row) == s for row in square) and \
all(sum(col) == s for col in transpose(square))
You may wish to look into numpy, which is a Python module for handling matrices. With it:
def is_magic(square):
n = len(square)
s = n*(n+1)/2
return all(m.sum(0) == s) and all(m.sum(1) == s)
while square: will terminate when square is empty; it follows that len(square) == 0, and thus m < len(square) evaluates to false when m=0.
square.pop() returns a row from square and removes the row, therefore len(square) is zero in the second loop.
There is also a built-in function sum that does the same thing as your getSum function.
You know how many times you plan to iterate because you check a length and an increment variable. Use a for loop instead, as it will allow you to initialize the increment and adjust it each loop on the same line. This will avoid issues resulting in infinite loops in the future (even though thisn't the problem here, I consider it relevant to point out).
You can avoid your error by replacing your first while with this:
for row in square:
print row, 'row', 'sum of row=', getSum(row)
if standardSum != getSum(row):
return False

Categories