I'm creating a chess game inside of Python (pygame) and in my validating moves function, I access a list of all possible moves.
However, as I'm removing from that list, I index it backwards. However, when I implement that change, the amount of repetitions undergone by the for loop encompassing the index changes from 20 to 1.
Here's the full function code:
def valid_move_2():
global white_to_move
possible_moves = generate_possible_moves()
print(range(len(possible_moves)))
for i in range(len(possible_moves)-1, -1, -1):
print("possible moves range")
print(str(possible_moves[i][0]))
move(possible_moves[i][0], possible_moves[i][1], possible_moves[i][2], possible_moves[i][3])
white_to_move = not white_to_move
check_check()
if check_check():
possible_moves.remove(possible_moves[i])
white_to_move = not white_to_move
undo_move()
if len(possible_moves) == 0:
if check_check():
checkmate = True
else:
stalement = True
else:
checkmate = False
stalemate = False
return possible_moves
To be specific:
print(range(len(possible_moves)))
This line returns 20.
However this line:
print("possible moves range")
only returns once, meaning the for loop repeats only once.
Where have I gone wrong?
THE ISSUE
The issue lies with this function, where my program gets stuck:
def square_under_attack(posx, posy):
print("SQUARE UNDER ATTACK FUNCTION CALLED")
global white_to_move
white_to_move = not white_to_move
enemy_moves = generate_possible_moves()
white_to_move = not white_to_move
x=0
for opponent_move in enemy_moves:
print(x)
if opponent_move[3] == posx and opponent_move[4] == posy: # if the opponent can move to the square being tested
print("returned true")
return True
x+=1
print("returned false")
return False
In this function, it gets stuck in the for loop. The x value was for troubleshooting to find out how many times the loop is iterated before not returning anything.
x is printed to have a value of 2 without either of the other 2 print functions being called at all.
What's wrong?
print(range(len(possible_moves)))
This shouldn't return 20.
It should return something like
range(0,20)
If so then it's problem of your for loop not range.
possible_moves.remove(possible_moves[i])
This line in particular is problematic.
If you are trying to remove i th element in possible_moves, use del
del possible_moves[i]
Also there are some dangerous bits in your code, one is global variable. Try to find another way to do that without using a global variable.
Another is your loop is iterated by initial length of possible_moves, and in the loop you are possibly removing something from possible_moves. This may cause index error. Easy fix would be to create a new list to keep track of what is deleted and what is not deleted.
If this doesn't solve error then there must be some issues in called method/functions
Try refactoring it with recursion since I think your iteration is very unorderly and possibly has repeated codes all over your code base.
If possible, use list comprehension instead of iteration to make things more concise.
If you want to do something like "Do until list L is empty" then use following pattern
while L:
do_something()
For your problem, chess, I would design it like this:
First define a function for each chess pieces that returns a set of grids they can go on next turn.
For check and checkmate I would look for a union of all the sets which represents all their possible next moves.
I think you are trying to implement your program by trying out every single enemy moves and then undoing it which is incredibly inefficient approach
You should make all the methods very concise and atomic. You shouldn't make them convoluted and do many implicit things under the hood. Keep them simple and logically concise as much as possible
Related
I'm so confused by backtracking because when the recursive call returns, won't you replace the solution found by replacing the grid back to zero. So even if you find the solution would it not be erased because after calling the solve function you are canceling what you did by replacing the value back to zero. I get the fact that you are backtracking but on the final recursive call that contains all the correct values are you not just replacing everything to 0?
# grid = ..... # defined as a global value,
# a list of 9 lists, 9-long each
def solve():
global grid
for y in range (0, 9):
for x in range (0, 9):
if grid[y][x] == 0:
for n in range(1,10):
if possible(y, x, n):
grid[y][x] = n
solve()
grid[y][x] = 0
return
# edit: missed this final line:
print (np.matrix(grid))
This was the code on Computerphile video by Prof. Thorsten Altenkirch.
This is weird code, but should work with some adaptations:
def solve():
global grid
for y in range(0, 9):
for x in range(0, 9):
if grid[y][x] == 0:
for n in range(1,10):
if possible(y, x, n):
grid[y][x] = n
if solve():
return True # return without reset
grid[y][x] = 0
return False # exhausted all options
return True # this is the deepest and last call with no more zeroes
Here is part of my code:
vlist = PossibleValueAtPosition(row,col) # find possible value at location (row, col)
for v in vlist: # try each possible value
puzzle[row][col] = v
if SolvePuzzle(n+1)==True: # n=81 means all filled then end loop
return True # if get a solution, you return True
puzzle[row][col] = 0 # if above return true, this line will never run
return False # return False for each fail attemp
Main program should like this
if SolvePuzzle(0)==True:
print(puzzle)
else:
print('No solution!')
It's not the final recursive call that contains all the correct values, but (each of) the deepest. Yes, this code enumerates all the solutions to the puzzle with the given board grid, not just the first solution.
For each (y,x) place, if it's empty, we try to place there each of the numbers from 1 through 9 in turn. If the placement was possible on the board as it is so far, we recurse with the changed grid board.
At the deepest level of recursion there were no empty (y,x) places on the board. Therefore we slide through to the print statement. (It could also be replaced by yield True for example, to turn it into a generator. On each next value we'd get from that generator, we'd have a complete solution -- in the changed grid. And when the generator would get exhausted, the grid would be again in its original state.)
When all the numbers from 1 through 9 have been tried, the current invocation has run its course. But the one above it in the recursion chain is waiting to continue its work trying to fill its (y,x) position. We must let it work on the same board it had before it invoked this invocation of solve(). And the only change on the board this invocation did was to change its (y,x) position's value from 0 to 1 through 9. So we must change it back to 0.
This means that the code could be restructured a little bit too, as
def solve():
global grid
for y in range (0, 9):
for x in range (0, 9): # for the first
if grid[y][x] == 0: # empty slot found:
for n in range(1,10): # try 1..9
if possible(y, x, n):
grid[y][x] = n
solve() # and recurse
# (move it here)
grid[y][x] = 0 # restore
return # and return
# no empty slots were found:
# we're at the deepest level of recursion and
# there are no more slots to fill:
yield True # was: print (np.matrix(grid))
Each invocation works only on one (y,x) location, the first empty position that it found by searching anew from the start on the changed board. This search is done by the first two nested loops on y and on x. That is a bit redundant; we know all the positions before this (y,x) are already filled. The code would be better restructured to pass the starting position (y,x) as a parameter to solve.
The paradigm of recursive backtracking is beautiful. Prolog is full of mystique, Haskell will dazzle you with cryptic monads talk (monads are actually just interpretable nestable data), but all it takes here are some nested loops, recursively created!
The paradigm is beautiful, but this code, not so much. A code's visual structure should reflect its true computational structure, but this code gives you an impression that the y-x- loops are the nested loops at work to create the backtracking structure, and they are not (they just implement a one-off linear search for the next empty space in the top-down left-to-right order).
That role is fulfilled by the n in range(1,10) loops. The y-x- loops should be stopped and exited explicitly when the empty space is found, to truly reflect in the code structure what is going on computationally, to make it apparent that the n in range(1,10) loop is not nested inside the y-x- loops, but comes in play after they finish their job.
Another problem is that it just assumes the validity of the numbers given to us in the grid before the very first call to solve(). That validity is never actually checked, only the validity of the numbers which we are placing in the empty cells is checked.
(note: previous versions of this answer were based on an erroneous reading of the code. there were some valid parts in them too. you can find them on the revisions list here).
have tried to use the return feature so when I call the Function it will use the last generated generation of solutions, but instead, it just uses the randomly generated ones that I used for the first generation and doesn't use the newest, this is an attempt of the Genetic algorithm in python on countdown to find a solution using "*,/,+,-" as operators and six numbers that are generated.
Forgive me if this was an overly simple mistake but I couldn't find anything online as to why it wouldn't use the latest Generation/return properly.
Mutate, SecondGen and CurrentPopFitness are both lists of lists, ([[]]) Mutate is ran through a cross over algorithm and mutation is done to it and appended to SecondGen, the Fitness scores are then calculated and appended to CurrentPopFitness along with the solution that gave that fitness, the 50 best solutions are then appended to SecondGen and Mutate is set to equal it which it does as I checked via the print at the end, however when it goes onto the next call of the function Mutate is back to being what it was at the start of the program.
Mutate is made to be 50 long just before the function ends.
I have checked that the second generation at the end is different from what it was for the first generation, However, Mutate (which the contents of the second generation are in at the end) still ends up being the first generation I generated outside of the function; when calling it for the 2nd time and every time after.
Target = random.randint(101,1000)
track2 = 0
Mutate = [[5/6*24-4+3+2][2/5+100*50-7-8]....]
def OffspringMutation(SecondGen,Mutate):
print(len(Mutate))
for x in range(50):
if track2 >= 1:
SecondGen = SecondGen + 1*[[]]
SecondGen[track2].append(CurrentPopFitness[x][1])
SecondGen[track2].append(CurrentPopFitness[x][2])
SecondGen[track2].append(CurrentPopFitness[x][3])
SecondGen[track2].append(CurrentPopFitness[x][4])
SecondGen[track2].append(CurrentPopFitness[x][5])
SecondGen[track2].append(CurrentPopFitness[x][6])
SecondGen[track2].append(CurrentPopFitness[x][7])
SecondGen[track2].append(CurrentPopFitness[x][8])
SecondGen[track2].append(CurrentPopFitness[x][9])
SecondGen[track2].append(CurrentPopFitness[x][10])
SecondGen[track2].append(CurrentPopFitness[x][11])
track2 += 1
Mutate = SecondGen
return(Mutate)
TruFal = True
while TruFal != False:
stop = input("Type X to stop the Genetic Algorithm, otherwise press enter")
if stop == "X":
TruFal = False
OffspringMutation(SecondGen,Mutate)
The expected result is for len(Mutate) to be roughly 60 long at the start (i made it roughly 60 long). Then on the second call of the function(the second generation) len(Mutate) should be 50 long and the contents different from what they were set to at the start.
You're not recording the return value of OffspringMutation. Although you pass the reference to Mutate to the function, this reference is stored in the local variable of the same name you gave it. Therefore any actions to its contents will change the original eg: append, slicing, delete, etc. But by doing Mutate = SecondGen you are not editing the contents of the reference, you are telling the local variable to point to a different reference, unaffecting the original. By this logic something like Mutate[:] = SecondGen (slicing) will change the original, but this is bad practice for a function.
Target = random.randint(101,1000)
track2 = 0
Mutate = [[5/6*24-4+3+2][2/5+100*50-7-8]....]
def OffspringMutation(SecondGen,Mutate):
print(len(Mutate))
for x in range(50):
if track2 >= 1:
SecondGen = SecondGen + 1*[[]]
SecondGen[track2].append(CurrentPopFitness[x][1])
SecondGen[track2].append(CurrentPopFitness[x][2])
SecondGen[track2].append(CurrentPopFitness[x][3])
SecondGen[track2].append(CurrentPopFitness[x][4])
SecondGen[track2].append(CurrentPopFitness[x][5])
SecondGen[track2].append(CurrentPopFitness[x][6])
SecondGen[track2].append(CurrentPopFitness[x][7])
SecondGen[track2].append(CurrentPopFitness[x][8])
SecondGen[track2].append(CurrentPopFitness[x][9])
SecondGen[track2].append(CurrentPopFitness[x][10])
SecondGen[track2].append(CurrentPopFitness[x][11])
track2 += 1
Mutate = SecondGen
return Mutate
TruFal = True
while TruFal != False:
stop = input("Type X to stop the Genetic Algorithm, otherwise press enter")
if stop == "X":
TruFal = False
Mutate = OffspringMutation(SecondGen,Mutate)
also a cleaner method with the same logic as the last loop would be:
while True:
stop = input("Type X to stop the Genetic Algorithm, otherwise press enter")
Mutate = OffspringMutation(SecondGen,Mutate)
if stop == "X":
break
I need to Check that every number in numberList is positive and implement the below
function using recursion. I'm stuck. Just learning recursion and I'm completely lost as I am very new to programming. Help!
def isEveryNumberPositiveIn(numberList):
foundCounterexampleYet = False
for number in numberList:
if(number <= 0):
foundCounterexampleYet = True
return not(foundCounterexampleYet)
Your function is not recursive because it never calls itself; a recursive version would look like
def all_positive(lst):
if lst:
return lst[0] > 0 and all_positive(lst[1:])
# ^
# this is the recursive bit -
# the function calls itself
else:
return True
# this keeps the function from looping forever -
# when it runs out of list items, it stops calling itself
This is a bad example to choose for a recursive function because (a) there is a simple non-recursive solution and (b) passing it a large list (ie over 1000 items) will overflow the call stack and crash your program. Instead, try:
def all_positive(lst):
return all(i > 0 for i in lst)
Your indentation is incorrect, but your thinking is correct, though the algorithm is not recursive. You could make it a bit more efficient though, by jumping out of the loop when a negative number is detected:
def isEveryNumberPositiveIn(numberList):
foundCounterexampleYet = False
for number in numberList:
if number <= 0:
foundCounterexampleYet = True
break
return not foundCounterexampleYet
then for example:
a = [1,-2,3,4,45]
print(isEveryNumberPositiveIn(a))
returns False
By the way, those parentheses forif and not are unnecessary.
With this sort of recursive problem, here is how you should think about it:
There should be a "basis case", which answers the question trivially.
There should be a part that does something that brings you closer to a solution.
In this case, the "basis case" will be an empty list. If the list is empty, then return True.
The part that brings you closer to a solution: shorten the list. Once the list get shortened all the way to a zero-length (empty) list, you have reached the basis case.
In pseudocode:
define function all_positive(lst)
# basis case
if lst is zero-length:
return True
if the first item in the list is not positive:
return False
# the actual recursive call
return all_positive(lst[with_first_value_removed]
Try to convert the above pseudocode into Python code and get it working. When you are ready to peek at my answer, it's below.
def all_positive(lst):
"""
Recursive function to find out if all members of lst are positive.
Because it is recursive, it must only be used with short lists.
"""
# basis case
if len(lst) == 0:
return True
if lst[0] <= 0:
return False
# recursive call
return all_positive(lst[1:])
There's several ways you can write this. One way would be to use lst.pop() to remove one element from the list. You could combine that with the if statement and it would be kind of elegant. Then the list would already be shortened and you could just do the recursive call with the list.
if lst.pop() <= 0:
return False
return all_positive(lst)
There is one problem though: this destroys the list! Unless the caller knows that it destroys the list, and the caller makes a copy of the list, this is destructive. It's just plain dangerous. It's safer to do it the way I wrote it above, where you use "list slicing" to make a copy of the list that leaves off the first item.
Usually in a language like Python, we want the safer program, so we make copies of things rather than destructively changing them ("mutating" them, as we say).
Here's one more version of all_positive() that makes a single copy of the list and then destroys that copy as it works. It relies on a helper function; the helper is destructive. We don't expect the user to call the helper function directly so it has a name that starts with an underscore.
def _all_positive_helper(lst):
"""
Recursive function that returns True if all values in a list are positive.
Don't call this directly as it destroys its argument; call all_positive() instead.
"""
if len(lst) == 0:
return True
if lst.pop() <= 0:
return False
return _all_positive_helper(lst)
def all_positive(lst):
"""
Return True if all members of lst are positive; False otherwise.
"""
# use "list slicing" to make a copy of the list
lst_copy = lst[:]
# the copy will be destroyed by the helper but we don't care!
return _all_positive_helper(lst_copy)
It's actually possible in Python to use a default argument to implement the above all in one function.
def all_positive(lst, _lst_copy=None):
"""
Return True if all members of lst are positive; False otherwise.
"""
if _lst_copy is None:
return all_positive(lst, lst[:])
if len(_lst_copy) == 0:
return True
if _lst_copy.pop() <= 0:
return False
return all_positive(lst, _lst_copy)
Recursion doesn't really help you with this. A better use for recursion would be, for example, visiting every node in a binary tree.
I am trying to write a program for Conway's Game of Life, and I came across some really weird problems, so I'm going step by step and trying to debug it. There is some weird stuff going on.
If you are not familiar with Conway's game of Life, the rules for determining the next stage is simply:
Any live cell with fewer than two live neighbours dies, as if caused
by under-population.
Any live cell with two or three live neighbours lives on to the next
generation.
Any live cell with more than three live neighbours dies, as if by
overcrowding.
Any dead cell with exactly three live neighbours becomes a live cell,
as if by reproduction.
I'm keeping a list called squareList that has N_ROWS rows and N_COL columns. I reference each element as squareList[i][j].
My get_next(squareList) function returns another list that counts the number of 'neighbors' in each square, and returns another list with the next stage.
Now, onto my problem. Here is a test case that highlights that a function is changing values it is not supposed to:
squareList = init_list(NUM_ROWS, NUM_COL) #sets all values in squareList to zero.
#here, NUM_ROWS = 12 and NUM_COL = 18
squareList[11][17] = 1
squareList[5][7] = 1
squareList[6][7] = 1
squareList[7][7] = 1
squareList[9][2] = 1
squareList[9][3] = 1
squareList[9][4] = 1
print_list(squareList) #prints squareList
nextList = get_next(squareList) #does NOT change squareList
print '\n--------------------------------------\n'
print_list(squareList) #prints squareList again
sys.exit()
What I get when I use my print_list function is:
As you can see, everything touched by the get_next function is set to zero. This shouldn't happen in my mind for two reasons:
It's not what should happen according to the Conway logic in my get_next function (and I really cannot find why it would not work)
My get_next function is setting a nextList variable, it's not supposed to do ANYTHING to squareList !! What am I missing??
Here's the code for my get_next function:
def get_next(squareList): #gets the next list for the game of life
nextList = squareList
for i in range(1,NUM_ROWS - 1):
for j in range(1,NUM_COL-1):
#num of neighbors:
counter = sum( [squareList[i+x][j+y] for x in range(-1,2) for y in range(-1,2) if not (x==y and x == 0)])
#logic for changing:
if squareList[i][j] == 1 and counter < 2: nextList[i][j] = 0
elif squareList[i][j] == 1 and counter > 3: nextList[i][j] = 0
elif squareList[i][j] == 0 and counter == 3: nextList[i][j] = 1
return nextList
My original thought is that it's changing a global variable, but it's not the case. First, python needs to declare global variables it uses within the function, and second, I tried changing the names of the lists, and got the same results.
EDIT: reply to lanzz suggestion:
The first thing you do in your get_next function is to make nextList a reference to the same list that squareList points to. Assignment does not imply copying — nextList = squareList makes both names point to the same actual structure in memory, so any change to nextList will affect squareList as well.
You should use copy.deepcopy to obtain an actual copy of your squareList list.
I'm trying to halt the for loop below once values (x,y) or (z,2) have been returned so that the value i doesn't keep increasing, and simply halts when the if or elif condition is first
def maxPalindrome(theList):
# students need to put some logic here
maxcomplist = theList[:]
maxcomplist.reverse()
control = len(theList) - 1
# exit if maxPalindrome is True
for i in range(control):
if maxcomplist[:] == theList[:]:
x = 0
y = len(theList)
return (x, y)
break
elif maxcomplist[i:control] == theList[i:control]:
successList = theList[i:control]
z = i
w = len(theList) - z - 1
return (z, w)
How can I accomplish this?
As I wrote in a comment already: that function isn't a recursive one at all.
Recursion means, that a function calls itself to complete it's purpose. This call can be indirect, meaning that the function uses helper function that will call the first function again.
But your code doesn't cover both cases.
A recursive function always have a certain architecture:
the first thing after being called should be to test, if the primitive case (or one primitive case among options) has been reached. if so, it returns.
If not it will compute whatever is needed and pass this results to itself again,
untill the primitive case is reached, and the nested function calls will finish in one after the other.
One well-known usage of recursion is the quicksort algorithm:
def quicksort(alist):
if len(alist) < 2:
return alist # primitive case: a list of size one is ordered
pivotelement = alist.pop()
# compute the 2 lists for the next recursive call
left = [element for element in alist if element < pivotelement]#left = smaller than pivotelemet
right = [element for element in alist if element >= pivotelement]#left = greater than pivotelemet
# call function recursively
return quicksort(left) + [pivotelement] + quicksort(right)
So the "stop" must be the return of a primitive case. This is vital for recursion. You cannot just break out somehow.
I don't understand the question - if I get it right, that what you want already happens. If you return, the function stops running.
Some comments in addition to this answer:
As well, I cannot see where the function is called recursively, nor what
exit if maxPalindrome is True
means. (Is this a comment, maybe?)
Besides, the maxcomplist[:]==theList[:] does not make much sense to me, and seem to be a waste of time and memory, and to have this comparison in each iteration loop doesn't make it faster as well.