cells not "dying" in may logocal loop. New cells geretion is normal, i think..
so cells not die
all calculations are into one numpy array, i dont have "second/old/new etc" arrays
sory for my bad English
def updateCells(grid: np.ndarray):
for i in range(GRID_WIDTH):
for j in range(GRID_HEIGHT):
#neighbours list contains 0, 1
neighbours = getNeighbours(i, j, grid)
#sum of alive neighbours
count = sum(neighbours)
if grid[i][j] == 1:
if count < 2:
grid[i][j] = 0
continue
if count == 2 or count == 3:
grid[i][j] = 1
continue
if count > 3:
grid[i][j] = 0
continue
if grid[i][j] == 0:
if count == 3:
grid[i][j] = 1
continue
function for getting neighbours of one cell:
def getNeighbours(i, j, arr):
ax_0_y = np.size(arr, 1)
ax_1_x = np.size(arr, 0)
n = []
ofssets = [-1, 0, 1]
for x in ofssets:
for y in ofssets:
if x == 0 and y == 0: continue
if y+j < 0 or y+j == ax_0_y: continue
if x+i < 0 or x+i == ax_1_x: continue
n.append(arr[x+i][y+j])
return n
main loop:
def main():
grid = np.zeros((GRID_WIDTH, GRID_HEIGHT), dtype=numpy.short)
....
drawGrid(display) #drawing cells line separators
randomise(grid) #random gereation alive cells
while True:
for i in pg.event.get():
if i.type == pg.QUIT:
quit()
updateCells(grid)
drawCells(display, grid) #drawing squares
pg.display.update()
fpsClock.tick(UPDATE_TIME)
if __name__ == "__main__":
main()
You can’t update the grid as you go, because then cells you get to later in the scan will have some neighbors from the current generation and some from the new one and will get the wrong neighbor count.
You have to do the whole grid as if it all updates at the same time, which means either having a second grid to build the new generation in or creating a list of changes to make to the grid at the end of the scan.
Some of the cells might not die due to you changing the field before the checks, like mentioned in the previous answer. You also seem to have quiet a bit of unneccessary code, like
if count == 2 or count == 3:
grid[i][j] = 1
continue
For example.
If there is no dying cells at all, i would like you to show us the code that calls your function.
Related
I'm currently learning BackTracking algorithms with Python and the first question everyone typically starts with is NQueens. NQueens is where you take a board of size N x N and you have to determine where to place N queens, in such an order they are not attacked by any other queen.
Example:
N = 5
['Q', 0, 0, 0, 0]
[0, 0, 'Q', 0, 0]
[0, 0, 0, 0, 'Q']
[0, 'Q', 0, 0, 0]
[0, 0, 0, 'Q', 0]
Currently, my algorithm returns ALL Possible Solutions. How do I produce ONE outcome. For instance, when N = 8, there are 92 optimal outcomes, how do I just return One Outcome instead of printing 92 separate Outcomes.
#This is our main recursive function that will determine optimal outcome
def NQueens(row,Current,N):
#this tells us when to stop
if row == N:
print("\n")
return printBoard(Current)
for choice in range(0,N):
if isValid(row,choice,Current,N):
#Place Queen in appropriate spot
Current[row][choice] = "Q"
#Go to next row
NQueens(row+1,Current,N)
Current[row][choice] = 0
return "All Solutions Found"
#This function determines whether we can put a Queen in a certain orientation on the board
def isValid(row,col,Current,N):
#check whether current state of game has queen in row/column
for i in range(0,N):
#checks column/row and sees whether a queen exists already
if Current[row][i] == "Q" or Current[i][col] == "Q":
return False
# Check upper diagonal on right side
i = row-1
j = col + 1
#Do while row is greater than 0 and column is less than N
while i >= 0 and j < N:
if Current[i][j] == "Q":
return False
i -= 1
j += 1
# Check upper diagonal on left side
#Do while row is greater than 0 and column is greater than N
i = row-1
j = col - 1
while i >= 0 and j >= 0:
if Current[i][j] == "Q":
return False
i -= 1
j -= 1
#If we pass the diagonal/row/column tests, we can then determine this is a valid move
return True
###############################################################################################################
#These functions deal with board creation and printing them in a proper format
def generateBoard(N):
#generate board based on User Input N in Main()
Board = [[0 for i in range(0,N)] for j in range(0,N)]
return Board
def printBoard(arr):
#Loop through each row to print an organized board
for row in arr:
print(row)
def main():
#ask number from user
print("What sized board would you like?"
" Please input a number higher that 3: ")
#user input used to determine size of board
N = int(input())
#generate Board that will be used
Board = generateBoard(N)
#this is the current status of the board
printBoard(Board)
print("\n")
#Runs Algorithm
print(NQueens(0,Board,N))
if __name__ == "__main__":
main()
NQueens needs to communicate to its caller that a solution has been found; a simple return True will do if that's the case. I made the following changes to your code (your previous lines are commented):
def NQueens(row,Current,N):
#this tells us when to stop
if row == N:
print("\n")
#return printBoard(Current)
return True # found a solution, say so
for choice in range(0,N):
if isValid(row,choice,Current,N):
#Place Queen in appropriate spot
Current[row][choice] = "Q"
#Go to next row
# NQueens(row+1,Current,N)
if NQueens(row+1,Current,N): # recursive call found a solution, let's stop
return True
Current[row][choice] = 0
#return "All Solutions Found"
And in main():
# ...
#Runs Algorithm
#print(NQueens(0,Board,N))
if NQueens(0,Board,N):
printBoard(Board) # found a solution, print it
I have fixed your code to have well-perfoming:
I merge this code https://www.geeksforgeeks.org/n-queen-problem-backtracking-3/ and yours to get it.
count = 1
def printOut(arrayMap):
global count
print('{}: -'.format(count))
count += 1
for i in range(0, len(arrayMap)):
print(arrayMap[i])
# This is our main recursive function that will determine optimal outcome
def NQueens(currentRow, arrayMap, matrixSize):
# this tells us when to stop
if currentRow == matrixSize:
print()
printOut(arrayMap)
return True # found a solution, say so
res = False
for col in range(0, matrixSize):
if isValid(currentRow, col, arrayMap, matrixSize):
# Place Queen in appropriate spot
arrayMap[currentRow][col] = 0
# Go to next row
# NQueens(row+1,Current,N)
res = NQueens(currentRow + 1, arrayMap, matrixSize) or res # recursive call found a solution, let's stop
arrayMap[currentRow][col] = 1
# return "All Solutions Found"
return res
# This function determines whether we can put a Queen in a certain orientation on the board
def isValid(row, col, arrayMap, matrixSize):
# check whether current state of game has queen in row/column
for i in range(0, matrixSize):
# checks column/row and sees whether a queen exists already
if arrayMap[row][i] == 0 or arrayMap[i][col] == 0:
return False
# Check upper diagonal on right side
i = row - 1
j = col + 1
# Do while row is greater than 0 and column is less than N
while i >= 0 and j < matrixSize:
if arrayMap[i][j] == 0:
return False
i -= 1
j += 1
# Check upper diagonal on left side
# Do while row is greater than 0 and column is greater than N
i = row - 1
j = col - 1
while i >= 0 and j >= 0:
if arrayMap[i][j] == 0:
return False
i -= 1
j -= 1
# If we pass the diagonal/row/column tests, we can then determine this is a valid move
return True
###############################################################################################################
if __name__ == "__main__":
# ask number from user
print("What sized board would you like?")
N = int(input('Choose your size: '))
# generate Board that will be used
Board = [[1 for i in range(0, N)] for j in range(0, N)]
count = 0
NQueens(0, Board, N)
So I am an absolute beginner in python and tried my hand at implementing Conway's game of life.
I am not using any libraries at all, my grid is just a 50x50 matrix of 1s and 0s.
The next_gen output I get is not matching the expected output but I couldn't figure out why, any help would be appreciated.
Here's my code:
def alive_neighbours(grid, r, c):
count = 0
if grid[r-1][c-1] == 1:
count += 1
if grid[r-1][c] == 1:
count += 1
if grid[r-1][c+1] == 1:
count += 1
if grid[r][c-1] == 1:
count += 1
if grid[r][c+1] == 1:
count += 1
if grid[r+1][c-1] == 1:
count += 1
if grid[r+1][c] == 1:
count += 1
if grid[r+1][c+1] == 1:
count += 1
return count
grid = [[0 for i in range(50)] for j in range(50)]
grid[25][25] = 1
grid[26][26] = 1
grid[27][24] = 1
grid[27][25] = 1
grid[27][26] = 1
grid[49][49] = 1
def next_gen(grid):
new_grid = grid[:]
for r in range(1, 49):
for c in range(1, 49):
neighbour = alive_neighbours(grid, r, c)
if (r == 0 or c == 0) or (r == 49 or c == 49):
pass # I am yet to define edge case
else:
if grid[r][c] == 1 and (neighbour > 3 or neighbour < 2):
new_grid[r][c] = 0
continue
elif grid[r][c] == 1 and (neighbour == 2 or 3):
continue
elif grid[r][c] == 0 and neighbour == 3:
new_grid[r][c] = 1
continue
else:
continue
grid = new_grid[:]
def printf(grid):
for r in range(50):
for c in range(50):
if grid[r][c] == 1:
print("*", end=" ")
else:
print(" ", end=" ")
print("")
x = 0
while x != '-1':
x = (input("x: "))
printf(grid)
next_gen(grid)
I also tried rewriting my next_gen function, but using that there is absolutely no change in the matrix
next_gen:
def next_gen(grid):
new_grid = grid[:]
for r in range(1, 49):
for c in range(1, 49):
neighbour = alive_neighbours(grid, r, c)
if (r == 0 or c == 0) or (r == 49 or c == 49):
pass
else:
if grid[r][c] == 1 and neighbour == 2 or 3:
continue
if grid[r][c] == 0 and neighbour == 3:
new_grid[r][c] = 1
continue
if grid[r][c] == 1:
new_grid[r][c] = 0
continue
grid = new_grid[:]
As bruno said in his answer there are a few issues in your code, He already told about your issue with grid and how allocating to it in the function actually points the local scope version to the new grid and not the global scope one. He also covers how to resolve this.
The other issue you will have is that you have undertood that just doing new_grid = grid will mean that new_grid and grid point at the same list. So to prevent this you have correctly done new_grid = grid[:] as this will create a new list in memory and copy the data from the grid list. However thats a shallow copy, so you will create a new list object but copy all the list references inside your list. we can demonstrate this by doing a shallow copy of a list and then changing a value in the new list.
grid_size = 2
grid = [[0 for i in range(grid_size)] for j in range(grid_size)]
new_grid = grid[:]
new_grid[1][1] = "R"
print("grid:", grid)
print("newg:", new_grid)
#output#
grid: [[0, 0], [0, 'R']]
newg: [[0, 0], [0, 'R']]
So you can see that changing the inner list in one will change the inner list in the other. so you need to do a deep copy of the list so that your not changing the original grid as you go. Since conways states are based on the original grid state and squares changing shouldnt impact the others. I think your already aware of this concept.
I also made a change to the alive neighbours to simplyfy it. Below is a quick draft adaptation. when you run it you should see your glider heading off to the bottom right corner
from copy import deepcopy
def alive_neighbours(grid, r, c):
differences = (0, -1, +1)
cells_in_square = [(r + a, c + b) for a in differences for b in differences]
total = 0
for x,y in cells_in_square[1:]:
try:
if x >=0 and y>=0:
total += grid[x][y]
except IndexError as ie:
pass #ignore index errors as at the edge of the grid
return total
def next_gen(grid):
new_grid = deepcopy(grid)
for r in range(len(grid)):
for c in range(len(grid)):
neighbour = alive_neighbours(grid, r, c)
if grid[r][c] == 1 and (neighbour > 3 or neighbour < 2):
new_grid[r][c] = 0
elif grid[r][c] == 0 and neighbour == 3:
new_grid[r][c] = 1
return new_grid
def printf(grid):
for r in grid:
for c in r:
if c == 1:
print("*", end=" ")
else:
print(" ", end=" ")
print("")
grid_size = 50
grid = [[0 for i in range(grid_size)] for j in range(grid_size)]
grid[25][25] = 1
grid[26][26] = 1
grid[27][24] = 1
grid[27][25] = 1
grid[27][26] = 1
grid[49][49] = 1
while True:
x = (input("press enter to see next grid: "))
if x:
break
printf(grid)
grid = next_gen(grid)
UPDATE
other then the glider you started with the below is a nice start for a cool exploder
grid_size = 50
grid = [[0 for i in range(grid_size)] for j in range(grid_size)]
grid[25][25] = 1
grid[26][24] = 1
grid[26][25] = 1
grid[26][26] = 1
grid[27][24] = 1
grid[27][26] = 1
grid[28][25] = 1
There are actually quite a few issues with your code, but the first and main problem is with your updated grid never being returned to the caller.
Here:
def next_gen(grid):
new_grid = grid[:]
# ...
# code modifying new_grid
# ...
grid = new_grid[:]
within the function, grid is a local name. Rebinding this name at the end of the function only affects the local name, it doesn't do anything to the global one. you should read this reference article for more in-depth explanations.
What you want is to return the grid to the caller instead:
def next_gen(grid):
new_grid = grid[:]
# ...
# code modifying new_grid
# ...
# return the new grid to the caller
return new_grid
x = 0
while x != '-1':
x = (input("x: "))
printf(grid)
# replace previous grid with the new one
grid = next_gen(grid)
For some other issues, this:
if grid[r][c] == 1 and neighbour == 2 or 3:
doesn't do what you think it does.
The neighbour == 2 or 3 part is actually executed as (neighbour == 2) or 3. Now the or operator returns either the first of it's operands that is not false, or the last of it's operand. Note that "that is not false" means "that does not have a false value in a boolean context" (all Python objects have a "truth" value, and for numbers, all numbers are true expect for zeros). So in the end, if the neighbours is different from 2, the value of neighbour == 2 or 3is3, whatever the value ofneighbour`:
>>> foo
1
>>> foo == 1 or 3
True
>>> foo == 2 or 3
3
>>>
And since 3 is true, the expression will have a true value even if neighbours is actually 1 or 4 or 5 or etc...
TL;DR: you want either:
`neighbour == 2 or neighbour == 3`
or more simply:
`neighbour in (2, 3)`
I am doing the standard Conway's Game of Life program using Python. I am having an issue when trying to count neighbors as I iterate through the array. I created print statements that print the succession of the if statement, as well as the value of count for each statement.
Here is my code: ( I have the questions inside the # throughout the code)
import random
numrows = 10
numcols = 10
def rnd():
rn = random.randint(0,1)
return rn
def initial():
grid = []
count = 0
for x in range(numrows):
grid.append([])
for y in range(numcols):
rand=random.randrange(1,3)
if(rand == 1):
grid[x].append('O')
else:
grid[x].append('-')
for x in grid:
print(*x, sep=' ',end="\n") #this prints the random 2d array
print("")
print("")
answer = 'y'
newgrid = []
count = 0
while(answer == 'y'): # I believe I am going through, checking neighbors
# and moving onto the next index inside these for
#loops below
for r in range(0,numrows):
grid.append([])
for c in range(0,numcols):
if(r-1 > -1 and c-1 > -1): #I use this to check out of bound
if(newgrid[r-1][c-1] == 'O'):#if top left location is O
count = count + 1 #should get count += 1
else:
count = count
print("top left check complete")
print(count)
if(r-1 > -1):
if(newgrid[r-1][c] == 'O'):
count = count + 1
else:
count = count
print("top mid check complete")
print(count)
if(r-1 > -1 and c+1 < numcols):
if(newgrid[r-1][c+1] == 'O'):
count = count + 1
else:
count = count
print("top right check complete")
print(count)
if(c-1 > -1 and r-1 > -1):
if(newgrid[r][c-1] == 'O'):
count = count + 1
else:
count = count
print("mid left check complete")
print(count)
if(r-1 > -1 and c+1 < numcols):
if(newgrid[r][c+1] == 'O'):
count = count + 1
else:
count = count
print("mid right check complete")
print(count)
if(r+1 < numrows and c-1 > -1):
if(newgrid[r+1][c-1] == 'O'):
count = count + 1
else:
count = count
print("bot left check complete")
print(count)
if(r+1 < numrows and c-1 > -1):
if(newgrid[r+1][c] == 'O'):
count = count + 1
else:
count = count
print("bot mid check complete")
print(count)
if(r+1 < numrows and c+1 < numcols):
if(newgrid[r+1][c+1] == 'O'):
count = count + 1
else:
count = count
print("bot right check complete")
print(count)
# I am not sure about the formatting of the code below, how do I know that
# the newgrid[r][c] location is changing? should it be according to the for-
# loop above? Or should it get it's own? If so, how could I construct it as
# to not interfere with the other loops and items of them?
if(newgrid[r][c] == '-' and count == 3):
newgrid[r][c] ='O'
elif(newgrid[r][c] == 'O' and count < 2):
newgrid[r][c] = '-'
elif(newgrid[r][c] == 'O' and (count == 2 or count == 3)):
newgrid[r][c] = 'O'
elif(newgrid[r][c] == 'O' and count > 3):
newgrid[r][c] = '-'
# I'm also confused how to go about printing out the 'new' grid after each
# element has been evaluated and changed. I do however know that after the
# new grid prints, that I need to assign it to the old grid, so that it can
# be the 'new' default grid. How do I do this?
for z in newgrid:
print(*z, sep=' ',end="\n")
answer = input("Continue? y or n( lower case only): ")
newgrid = grid
if(answer != 'y'):
print(" Hope you had a great life! Goodbye!")
initial()
Here is the current output and error message:
>>> initial()
- O - - O - - O - -
- O - - O - - - O O
- O - - O - O O - O
O - - O - - O O O O
O - O O - - - O O -
O - O - O - O - O -
O - O O O O - - O -
- - - - O O O - - O
O O - O - - O - - -
- - O O O - O - - -
top left check complete
0
top mid check complete
0
top right check complete
0
mid left check complete
0
mid right check complete
0
bot left check complete
0
bot mid check complete
0
Traceback (most recent call last):
File "<pyshell#68>", line 1, in <module>
initial()
File "C:\Users\Ted\Desktop\combined.py", line 86, in initial
if(newgrid[r+1][c+1] == 'O'):
IndexError: list index out of range
As I iterate through the random array to see what the neighbors are, it seems to be fine up until it moves over to [0][1] while checking the bot right neighbor.
Also, the mid right neighbor should + 1 to count as it is alive. However, even with succession of the if statement, count remains 0?
Question 1: How can I possibly know that my if conditions witll suffice for every instance of [r][c] for all sides of the array?
Question 2: Is my current method of checking out of bounds the best for my situation? Is there a way to make a "check all for out of bounds" before I even check the value?
I am at my wit's end at this point. Thanks in advance for the time taken to help answer my questions
You are getting that index error because your newgrid only contains a single empty row. And your testing for neighbours in newgrid instead of in grid (as Blckknght mentions in the comments). I've made a few repairs, but there's a lot more that can be done to improve this code. It looks like it's working now, but it's hard to tell when you're working with random Life forms. :) I suggest giving your program some way of using known Life patterns like blinkers and gliders to see that they behave correctly.
The simplest way to ensure that newgrid is valid is to copy it from grid. If we just do newgrid = grid that simply makes newgrid another name for the grid object. To copy a list of lists properly we need to make copies of each of the internal lists. My new code does that with the copy_grid function.
I've fixed a couple of minor bugs that you had in the if tests in the section that counts neighbours, and I've simplified the logic that updates a cell from its neighbour count. I've also condensed the code that makes a random grid, and I've added a simple function that can read a Life pattern from a string and build a grid from it. This lets us test the code with a Glider. I've also added a function that makes an empty grid. The program doesn't currently use that function although I used it during my tests, and I guess it's a useful example. :)
import random
# Set a seed so that we get the same random numbers each time we run the program
# This makes it easier to test the program during development
random.seed(42)
numrows = 10
numcols = 10
glider = '''\
----------
--O-------
---O------
-OOO------
----------
----------
----------
----------
----------
----------
'''
# Make an empty grid
def empty_grid():
return [['-' for y in range(numcols)]
for x in range(numrows)]
# Make a random grid
def random_grid():
return [[random.choice('O-') for y in range(numcols)]
for x in range(numrows)]
# Make a grid from a pattern string
def pattern_grid(pattern):
return [list(row) for row in pattern.splitlines()]
# Copy a grid, properly!
def copy_grid(grid):
return [row[:] for row in grid]
# Print a grid
def show_grid(grid):
for row in grid:
print(*row)
print()
def run(grid):
show_grid(grid)
# Copy the grid to newgrid.
newgrid = copy_grid(grid)
while True:
for r in range(numrows):
for c in range(numcols):
# Count the neighbours, making sure that they are in bounds
count = 0
# Above this row
if(r-1 > -1 and c-1 > -1):
if(grid[r-1][c-1] == 'O'):
count += 1
if(r-1 > -1):
if(grid[r-1][c] == 'O'):
count += 1
if(r-1 > -1 and c+1 < numcols):
if(grid[r-1][c+1] == 'O'):
count += 1
# On this row
if(c-1 > -1):
if(grid[r][c-1] == 'O'):
count += 1
if(c+1 < numcols):
if(grid[r][c+1] == 'O'):
count += 1
# Below this row
if(r+1 < numrows and c-1 > -1):
if(grid[r+1][c-1] == 'O'):
count += 1
if(r+1 < numrows):
if(grid[r+1][c] == 'O'):
count += 1
if(r+1 < numrows and c+1 < numcols):
if(grid[r+1][c+1] == 'O'):
count += 1
# Update the cell in the new grid
if grid[r][c] == '-':
if count == 3:
newgrid[r][c] ='O'
else:
if count < 2 or count> 3:
newgrid[r][c] = '-'
# Copy the newgrid to grid
grid = copy_grid(newgrid)
show_grid(grid)
answer = input("Continue? [Y/n]: ")
if not answer in 'yY':
print(" Hope you had a great life! Goodbye!")
break
#grid = random_grid()
grid = pattern_grid(glider)
run(grid)
This code does work correctly, but there is still plenty of room for improvement. For example, here's an improved version of run() that condenses the neighbour counting section by using a couple of loops.
def run(grid):
show_grid(grid)
# Copy the grid to newgrid.
newgrid = copy_grid(grid)
while True:
for r in range(numrows):
for c in range(numcols):
# Count the neighbours, making sure that they are in bounds
# This includes the cell itself in the count
count = 0
for y in range(max(0, r - 1), min(r + 2, numrows)):
for x in range(max(0, c - 1), min(c + 2, numcols)):
count += grid[y][x] == 'O'
# Update the cell in the new grid
if grid[r][c] == '-':
if count == 3:
newgrid[r][c] ='O'
else:
# Remember, this count includes the cell itself
if count < 3 or count > 4:
newgrid[r][c] = '-'
# Copy the newgrid to grid
grid = copy_grid(newgrid)
show_grid(grid)
answer = input("Continue? [Y/n]: ")
if not answer in 'yY':
print(" Hope you had a great life! Goodbye!")
break
To count the neighbors, just follow this simple rule. You will have the row and col of the current cell. Using that form two arrays, one for rows and another for columns. Below would be your logic.
You can find the detailed implementation with a demo video here.
this.neibhours = function() {
var rows = [row-1, row, row+1];
var cols = [col-1, col, col+1];
neibhourCells = [];
for(var i=0; i < rows.length; i++) {
for(var j=0; j < cols.length; j++) {
if(!(col === cols[j] && row === rows[i])) {
var cell = new Cell(rows[i], cols[j])
if(cell.isOnGrid()) {
neibhourCells.push(cell);
}
}
}
}
return neibhourCells;
}
I took a liking to Conway's Game of Life and began to try and write it in python. At this moment I have yet to write any code for the borders of the program so I am just asking for help with what I have right now. I seem to have trouble when initialization a "blinker" formation. Instead of oscillating like it should, it seems to turn itself into a cube.
#File: gameoflife.py
#Description: This is a basic "life" simulation that follows three distinct rules:
#1.Any live cell with fewer than two live neighbours dies
#2.Any live cell with two or three live neighbours lives
#3.Any live cell with more than three live neighbours dies
#4.Any dead cell with exactly three live neighbours becomes a live cell
#A neighbor is deemed as any cell directly horizantal/vertical/diagonal
#meaning there are 9 neighbors to a cell at any time
from graphics import *
import random
from time import sleep
def initial(D,M,win):
#Creates the white board background
for i in range (11):
m = [] # rectangle list
for j in range (11):
rec = Rectangle(Point(6 + 4 * i, 6 + 4 * j), Point(10 + 4 * i, 10 + 4 * j))
D[i][j] = 0
rec.setFill("white")
rec.draw(win)
m.append(rec)
M.append(m)
def check(x,y,D):
#Checks all 9 adjacent neihbors to see if "alive" and checks this number
#means the cell should stay alive(1), die(0), or if already dead come
#back alive(2)
counter = 0
if D[x+1][y] == 1:
counter += 1
if D[x-1][y] == 1:
counter += 1
if D[x][y+1] == 1:
counter += 1
if D[x][y-1] == 1:
counter +=1
if D[x+1][y+1] == 1:
counter+=1
if D[x+1][y-1] == 1:
counter+= 1
if D[x-1][y-1] == 1:
counter += 1
if D[x-1][y+1] == 1:
counter +=1
if counter<2 or counter>3:
return 0
if counter == 2:
return 1
if counter == 3:
return 2
def main():
win = GraphWin("Game of Life", 700, 600)
win. setCoords(0, 0, 70, 60)
#Initialize two dimesion arrays.
#D records color of grids, M records rectangles
D = []
M = []
C = []
#initialize the grids to create all "white"
for i in range(11):
d = []
c = []
for j in range(11):
d.append(0)
c.append(0)
D.append(d)
C.append(c)
initial(D,M,win)
#Initialzes three "alive" units
D[5][5],D[4][5] ,D[6][5]= 1,1,1
C[5][5],C[4][5] ,C[6][5]= 1,1,1
M[5][5].setFill("Black")
M[4][5].setFill("Black")
M[6][5].setFill("Black")
#Contiually checking
while True:
#Purposfully not checking the "Borders" of the array
for i in range (len(D)-1):
for j in range(len(D[i])-1):
#If the cell is alive
if D[i][j] == 1:
#If the cell should die
if check(i,j,D) == 0:
sleep(1)
#Sets a temporary list to white
C[i][j] = 0
#Fills the cell white
M[i][j].setFill("White")
#if the cell is dead
if D[i][j] == 0:
#If the cell should be revived
if check(i,j,D) == 2:
sleep(1)
#Sets a temporary list to black
C[i][j] = 1
#Fills the cell black
M[i][j].setFill("Black")
#Sets the main list = to the temporary list
D = C
main()
You will need to swap D and C, and not just assign C to D. As it stands now, D and C will be referring to the same list after the first iteration.
Here is a simple algorithm to do Conway's Game of Life in python using a numpy array of arbitrary 2D size:
import numpy
# this function does all the work
def play_life(a):
xmax, ymax = a.shape
b = a.copy() # copy grid & Rule 2
for x in range(xmax):
for y in range(ymax):
n = numpy.sum(a[max(x - 1, 0):min(x + 2, xmax), max(y - 1, 0):min(y + 2, ymax)]) - a[x, y]
if a[x, y]:
if n < 2 or n > 3:
b[x, y] = 0 # Rule 1 and 3
elif n == 3:
b[x, y] = 1 # Rule 4
return(b)
# replace (5, 5) with the desired dimensions
life = numpy.zeros((5, 5), dtype=numpy.byte)
# place starting conditions here
life[2, 1:4] = 1 # a simple "spinner"
# now let's play
print(life)
for i in range(3):
life = play_life(life)
print(life)
This is not very efficient, but will certainly get the job done. Replace print(life) with whatever graphical calls you prefer.
This question already has answers here:
Why does foo.append(bar) affect all elements in a list of lists?
(3 answers)
Closed 4 years ago.
I seem to have a problem with my maze generating program made in Python. I'm trying to randomly create a path that branches out at select points, with the points getting stored as it goes along. When the maze gets to a dead end, it will sort back through the visited points by testing the top value than popping that and going to the next one, until it gets to a spot where it isn't a dead end. However, when I try to append items to the list I'm using to save the spaces I've been to, something strange happens, I've never seen it before actually. Here's the code, and the best way to see it is to run it a through times until it goes all the way through. I haven't really found a way to counter the dead end problem, so if anyone could help me with that also, that would be great.
import random
width = 8
def check(x,y):
"""Figures out the directions that Gen can move while"""
if x-1 == -1:
maze[x][y][3] = 0
if x+1 == 8:
maze[x][y][1] = 0
if y+1 == 8:
maze[x][y][2] = 0
if y-1 == -1:
maze[x][y][0] = 0
if x + 1 in range(0,8) and visited[x+1][y] == False:
maze[x][y][1] = 2
if x - 1 in range(0,8) and visited[x-1][y] == False:
maze[x][y][3] = 2
if y + 1 in range(0,8) and visited[x][y+1] == False:
maze[x][y][2] = 2
if y - 1 in range(0,8) and visited[x][y-1] == False:
maze[x][y][0] = 2
def Gen(x,y):
visited[x][y] = True
past.append(current)
dirs = []
check(x,y)
print current
if maze[x][y][0] == 2:
dirs.append(0)
if maze[x][y][1] == 2:
dirs.append(1)
if maze[x][y][2] == 2:
dirs.append(2)
if maze[x][y][3] == 2:
dirs.append(3)
pos = random.choice(dirs)
print dirs
maze[x][y][pos] = 1
if pos == 0:
current[1] -= 1
if pos == 1:
current[0] += 1
if pos == 2:
current[1] += 1
if pos == 3:
current[0] -= 1
if maze[x][y][0] == 4:
maze[x][y][0] = 1
if maze[x][y][1] == 4:
maze[x][y][1] = 1
if maze[x][y][2] == 4:
maze[x][y][2] = 1
if maze[x][y][3] == 4:
maze[x][y][3] = 1
print maze[x][y]
print past, '\n'
#Build the initial values for the maze to be replaced later
maze = []
current = [0,0]
visited = []
past = []
#Generate empty 2d list with a value for each of the xy coordinates
for i in range(0,width):
maze.append([])
for q in range(0, width):
maze[i].append([])
for n in range(0, 4):
maze[i][q].append(4)
#Makes a list of falses for all the non visited places
for x in range(0, width):
visited.append([])
for y in range(0, width):
visited[x].append(False)
#Generates the walls
#for q in range(0, width):
# for i in range(0, width):
# check(q, i)
current = [0,0]
while current != [7,7]:
Gen(current[0], current[1])
print maze
As you can see, it starts at 0,0 and then figures out the possible paths to take. It randomly selects from those and sets the value for that side of the room in 0,0 to 1, which means a passage. 2 means wall and 0 means out of bounds. 4 is just a placeholder as all values should be filled by the time the maze is completely generated.
If anyone could help me, that would be great and very appreciated. Thanks in advance.
I believe the current list is simply copied multiple times into past. So you have multiple copies of the same list.
To fix: in the line past.append(current) (two lines below def Gen(x,y):), change it to past.append(current[:]).
The notation list[:] creates a copy of the list. Technically, you are creating a slice of the whole list.
By the way, a better solution would be to not use a global current variable :)
Yeah this is correct while List Comprehension in Python you need to append by strip other wise it will replace multiple times