Python, and The Game of Life Rules - python

Okay, so i finally get this to print, and actually do something, but the rules are not applying right? I've tried messing with the rules, but can't seem to get them to print out right, here's the snip of my rules:
nCount = 0
for i in range(x-1,x+2):
for j in range(y-1,y+2):
if not(i == x and j == y):
nCount += int(mat[i][j])
if(nCount < 2 or nCount > 3):
return 0
elif(nCount == 2 or nCount == 3):
return 1
else:
return mat[i][j]
I've tested with a regular 5x5 with 3 1's in the middle to act as an oscillator but instead of oscillating it fills the 5x5 edges with zeros like a square box then stops
Here is the rest of my coding:
import time
import os
def buildMatrix(fname):
fp = open(fname, "r")
row = fp.readlines()
matrix = []
for i in range(0, len(row), 1):
token = row[i].split(" ")
token[-1] = token[-1].replace('\n', ' ')
matrix.append(token)
fp.close()
return matrix
def getRows(mat):
return len(mat)
def getCols(mat):
return len(mat[0])
def printGen(mat): #this is what i use for printing
os.system('clear')
for i in range(0, len(mat), 1):
for j in range(0, len(mat[0]), 1):
if(mat[i][j] == 1):
print("#", sep=" ", end=" ")
else:
print(" ", sep=" ", end=" ")
print()
def nextGen(cur, nxt): #use this to update to the next matrix
for i in range(0, len(cur)-1, 1):
for j in range(0, len(cur[0])-1, 1):
nxt[i][j] = neighbors(i, j, cur)
return nxt
def neighbors(x, y, mat):
nCount = 0
for i in range(x-1,x+2):
for j in range(y-1,y+2):
if not(i == x and j == y):
nCount += int(mat[i][j])
if(nCount < 2 or nCount > 3):
return 0
elif(nCount == 2 or nCount ==3):
return 1
else:
return mat[i][j]
This isnt all my code, as im still importing all this to another repo and running it from that repo, but the other part i have done

elif(nCount == 2,3):
This doesn't do what you want. This builds a 2-element tuple whose first element is the value of nCount == 2, and whose second element is 3, then converts this tuple to a boolean to decide which way to go. If you wanted to check whether nCount was equal to either 2 or 3, you could use
elif nCount in (2, 3):
but it's redundant, since nCount must be one of those for control flow to reach the elif. Of course, this isn't correct for implementing the rules of Life; what you want is
elif nCount == 3:
A cell keeps its current live/dead status if surrounded by 2 other live cells. There have to be exactly 3 live cells around it for it to be alive in the next generation regardless of its current life status.

It looks like your code isn't making a copy first, so the results of a birth or death are effecting themselves. Try with a copy:
import numpy
# this function does all the work
def play_life(a):
xmax, ymax = a.shape
b = a.copy() # copy current life grid
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 # living cells with <2 or >3 neighbors die
elif n == 3:
b[x, y] = 1 # dead cells with 3 neighbors ar born
return(b)
life = numpy.zeros((5, 5), dtype=numpy.byte)
# place starting conditions here
life[2, 1:4] = 1 # middle three in middle row to 1
# now let's play
print(life)
for i in range(3):
life = play_life(life)
print(life)
I also used numpy for speed. Note that the case for a live cell with 2 or 3 neighbors is taken care of when the copy is made. Here are the results of this test case:
[[0 0 0 0 0]
[0 0 0 0 0]
[0 1 1 1 0]
[0 0 0 0 0]
[0 0 0 0 0]]
[[0 0 0 0 0]
[0 0 1 0 0]
[0 0 1 0 0]
[0 0 1 0 0]
[0 0 0 0 0]]
[[0 0 0 0 0]
[0 0 0 0 0]
[0 1 1 1 0]
[0 0 0 0 0]
[0 0 0 0 0]]
[[0 0 0 0 0]
[0 0 1 0 0]
[0 0 1 0 0]
[0 0 1 0 0]
[0 0 0 0 0]]
Now, if you don't have numpy, then you can use a "2D" array like this:
# this function does all the work
def play_life(a):
xmax = len(a)
ymax = len(a[0])
b = [[cell for cell in row] for row in life]
for x in range(xmax):
for y in range(ymax):
n = 0
for i in range(max(x - 1, 0), min(x + 2, xmax)):
for j in range(max(y - 1, 0), min(y + 2, ymax)):
n += a[i][j]
n -= a[x][y]
if a[x][y]:
if n < 2 or n > 3:
b[x][y] = 0 # living cells with <2 or >3 neighbors die
elif n == 3:
b[x][y] = 1 # dead cells with 3 neighbors ar born
return(b)
# this function just prints the board
def show_life(a):
print('\n'.join([' '.join([str(cell) for cell in row]) for row in life]) + '\n')
# create board
x_size, y_size = (5, 5)
life = [[0 for y in range(y_size)] for x in range(x_size)]
# place starting conditions here
for x in range(1, 4): life[x][2] = 1 # middle three in middle row to 1
# now let's play
show_life(life)
for i in range(3):
life = play_life(life)
show_life(life)
That outputs the following for the test case:
0 0 0 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 1 1 1 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 1 1 1 0
0 0 0 0 0
0 0 0 0 0

Related

Finding the nearest element in a 2D Numpy array

I have a two-dimensional numpy array like:
[[0 0 0 0 0 0 0 0 1 1]
[0 0 0 1 0 1 0 0 0 1]
[1 0 1 0 0 0 1 0 0 1]
[1 0 0 0 0 0 0 0 1 0]
[0 1 0 0 0 1 0 1 1 0]
[0 0 0 1 1 0 0 0 0 0]
[0 1 1 1 1 1 0 0 0 0]
[1 0 0 0 1 0 1 0 0 0]
[0 0 0 0 0 0 0 1 0 0]
[0 1 0 0 0 0 0 0 0 0]]
We can think of it as a map that is viewed from above.
I'll pick a random cell, let's say line 3 column 4 (start counting at 0). If the cell contains a 1, there is no problem. If the cell is a 0, I need to find the index of the nearest 1.
Here, line 3 column 4 is a 0, I want a way to find the nearest 1 which is line 4 column 5.
If two cells containing 1 are at the same distance, I don't care which one I get.
Borders are not inter-connected, i.e. the nearest 1 for the cell line 7 column 9 is not the 1 line 7 column 0
Of course it is a simplified example of my problem, my actual np arrays do not contain zeros and ones but rather Nones and floats
This is a simple "path-finding" problem. Prepare an empty queue of coordinates and push a starting position to the queue. Then, pop the first element from the queue and check location and if it's 1 return the coordinates, otherwise push all neighbours to the queue and repeat.
ADJACENT = [(0, 1), (1, 0), (0, -1), (-1, 0)]
def find(data: np.array, start: tuple):
queue = deque()
deque.append(start)
while queue:
pos = queue.popleft()
if data[pos[0], pos[1]]:
return position
else:
for dxy in ADJACENT:
(x, y) = (pos[0] + dxy[0], pos[1], dxy[1])
if x >= 0 and x < data.size[0] and y >= and y < data.size[1]:
queue.append((x,y))
return None

Python: Writing a matrix with different values depending of how far is from a point (i,j)

Help me out with this code! As Input I have N: matrix size. i: point's row. j: point's column. P: point's magnitude. Each time I move away point (i,j) the magnitude will decrease -1. So if my input is N = 7, i = 3, j = 3, P = 3, my output would look like this:
0 0 0 0 0 0 0
0 1 1 1 1 1 0
0 1 2 2 2 1 0
0 1 2 3 2 1 0
0 1 2 2 2 1 0
0 1 1 1 1 1 0
0 0 0 0 0 0 0
I can't figure out how to write the correct value in each position :( help me out! Here's the code that I tried -->
Not a beautiful or efficient solution, but gets the work done:
N, i, j, P = 7, 3, 3, 3
M = [[0] * N for i in range(N)]
for row in range(N):
for col in range(N):
M[row][col] = P - max(abs(row - i), abs(col - j))

Maze Recursive Division algorithm

I am currently making a random maze generator in Python that stores its values in a 2 dimensional array. This will be used in the future as a pathfinding algorithm tester for me.
I attemped to make this using the Recursive Division Algorithm, as it seemed the most intuitive to me.
I do not have experience with Python.
To allow for the most amount of combinations possible, I gave the user the option to choose the height and width, using
def dimensions():
height = int(input("Desired height: "))
width = int(input("Desired width: "))
res = (height, width)
return res
As per the algorithm rules, I create an empty array surrounded with walls, and with a start and end point, given by:
def create_array(height, width):
maze = np.zeros((height, width), dtype = int)
for i in range(height):
maze[i][0] = 1
maze[i][width - 1] = 1
for i in range(width):
maze[0][i] = 1
maze[height - 1][i] = 1
return maze
def set_start_end(start, height = 0, width = 0):
if start == True:
elems = [0,1]
random.shuffle(elems)
else:
elems = [[height - 1, width - 2], [height - 2, width - 1]]
elems = random.choice(elems)
res = (elems[0], elems[1])
return res
Both the start and end point are chosen from the upper-left, and lower-right corner, once again, to allow for more possible combinations.
Following this, I created 3 auxiliary functions:
def choose_orientation(height, width):
if width > height:
return VERTICAL
elif width < height:
return HORIZONTAL
else:
return random.choice((VERTICAL, HORIZONTAL))
def set_wall(length):
coor = int(length/2)
if (coor % 2 != 0):
coor += random.choice([-1, 1])
return coor
def set_door(length):
coor = random.randrange(1, length - 1)
if (coor % 2 == 0):
coor += random.choice([-1, 1])
return coor
The first is pretty staightforward, it chooses the direction in which the wall will be created, based on the current height and width of the room.
The following two functions make sure that walls will only be created in even cells, and doors the oposite.
My main recursive loop is the following:
def divide(maze, x, y, height, width, resolution):
h = height
w = width
if w <= resolution or h <= resolution:
return
orientation = choose_orientation(h, w)
w_coor = 0
w_length = 0
d_coor = 0
if orientation == HORIZONTAL:
w_coor = set_wall(w)
d_coor = set_door(w)
w_length = w
for i in range(w_length):
maze[x + w_coor][i] = 1
maze[w_coor][d_coor] = 0
for elem in [[y, w_coor - y + 1], [w_coor, y + h - w_coor - 1]]:
divide(maze, x, elem[0], elem[1], w, resolution)
else:
w_coor = set_wall(h)
d_coor = set_door(h)
w_length = h
for i in range(w_length):
maze[i][y + w_coor] = 1
maze[d_coor][w_coor] = 0
for elem in [[x, w_coor - x + 1], [w_coor, x + w - w_coor - 1]]:
divide(maze, elem[0], y, h, elem[1], resolution)
And yet, the result somehow always resembles the following:
[[1 5 1 1 1 1 1 1 1 1]
[1 0 0 0 1 0 0 0 1 1]
[1 1 1 0 1 0 0 0 1 1]
[1 0 0 0 1 0 0 0 1 1]
[1 0 1 1 1 1 1 1 1 1]
[1 0 0 0 0 0 0 0 1 1]
[1 0 0 0 0 0 0 0 0 1]
[1 0 0 0 0 0 0 0 0 1]
[1 1 1 1 1 1 0 0 0 1]
[1 1 1 1 1 1 1 1 5 1]]
I haven't been able to spot the problem, and don't know what else to do
As per #Stef's answer, I have switched the arguments given to set_wall and set_door, giving me a slightly better result
[[1 1 1 1 1 1 1 1 1 1]
[5 0 1 0 1 0 1 0 1 1]
[1 0 1 0 1 0 1 0 1 1]
[1 0 0 0 0 0 1 0 1 1]
[1 1 1 0 1 1 1 0 1 1]
[1 0 0 0 0 0 1 0 1 1]
[1 1 1 1 0 0 0 0 0 1]
[1 0 0 0 0 0 0 0 0 1]
[1 0 0 0 0 0 0 0 0 5]
[1 1 1 1 1 1 1 1 1 1]]

changing the boolean values of an array according to a formula for the indices

I want to create a 64 components array showing all the squares in which the two rooks of an empty chessboard could move from their current position. So far I am doing it with for and while loops.
I first create a function just to better visualize the board:
import numpy as np
def from_array_to_matrix(v):
m=np.zeros((8,8)).astype('int')
for row in range(8):
for column in range(8):
m[row,column]=v[row*8+column]
return m
and here I show how I actually build the array:
# positions of the two rooks
a=np.zeros(64).astype('int')
a[15] = 1
a[25] = 1
print from_array_to_matrix(a)
# attack_a will be all the squares where they could move in the empty board
attack_a=np.zeros(64).astype('int')
for piece in np.where(a)[0]:
j=0
square=piece+j*8
while square<64:
attack_a[square]=1
j+=1
square=piece+j*8
j=0
square=piece-j*8
while square>=0:
attack_a[square]=1
j+=1
square=piece-j*8
j=0
square=piece+j
while square<8*(1+piece//8):
attack_a[square]=1
j+=1
square=piece+j
j=0
square=piece-j
while square>=8*(piece//8):
attack_a[square]=1
j+=1
square=piece-j
print attack_a
print from_array_to_matrix(attack_a)
I have been advised to avoid for and while loops whenever it is possible to use other ways, because they tend to be time consuming. Is there any way to achieve the same result without iterating the process with for and while loops ?
Perhaps using the fact that the indices to which I want to assign the value 1 can be determined by a function.
There are a couple of different ways to do this. The simplest thing is of course to work with matrices.
But you can vectorize operations on the raveled array as well. For example, say you had a rook at position 0 <= n < 64 in the linear array. To set the row to one, use integer division:
array[8 * (n // 8):8 * (n // 8 + 1)] = True
To set the column, use modulo:
array[n % 8::8] = True
You can convert to a matrix using reshape:
matrix = array.reshape(8, 8)
And back using ravel:
array = martix.ravel()
Or reshape:
array = matrix.reshape(-1)
Setting ones in a matrix is even simpler, given a specific row 0 <= m < 8 and column 0 <= n < 8:
matrix[m, :] = matrix[:, n] = True
Now the only question is how to vectorize multiple indices simultaneously. As it happens, you can use a fancy index in one axis. I.e, the expression above can be used with an m and n containing multiple elements:
m, n = np.nonzero(matrix)
matrix[m, :] = matrix[:, n] = True
You could even play games and do this with the array, also using fancy indexing:
n = np.nonzero(array)[0]
r = np.linspace(8 * (n // 8), 8 * (n // 8 + 1), 8, False).T.ravel()
c = np.linspace(n % 8, n % 8 + 64, 8, False)
array[r] = array[c] = True
Using linspace allows you to generate multiple sequences of the same size simultaneously. Each sequence is a column, so we transpose before raveling, although this is not required.
Use reshaping to convert 1-D array to 8x8 2-D matrix and then numpy advance indexing to select rows and columns to set to 1:
import numpy as np
def from_array_to_matrix(v):
return v.reshape(8,8)
# positions of the two rooks
a=np.zeros(64).astype('int')
a[15] = 1
a[25] = 1
a = from_array_to_matrix(a)
# attack_a will be all the squares where they could move in the empty board
attack_a=np.zeros(64).astype('int')
attack_a = from_array_to_matrix(attack_a)
#these two lines replace your for and while loops
attack_a[np.where(a)[0],:] = 1
attack_a[:,np.where(a)[1]] = 1
output:
a:
[[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 1]
[0 0 0 0 0 0 0 0]
[0 1 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]]
attack_a:
[[0 1 0 0 0 0 0 1]
[1 1 1 1 1 1 1 1]
[0 1 0 0 0 0 0 1]
[1 1 1 1 1 1 1 1]
[0 1 0 0 0 0 0 1]
[0 1 0 0 0 0 0 1]
[0 1 0 0 0 0 0 1]
[0 1 0 0 0 0 0 1]]

Find all the blocks

I am very new to python and coding. I have this homework that I have to do:
You will receive on the first line the rows of the matrix (n) and on the next n lines you will get each row of the matrix as a string (zeros and ones separated by a single space). You have to calculate how many blocks you have (connected ones horizontally or diagonally) Here are examples:
Input:
5
1 1 0 0 0
1 1 0 0 0
0 0 0 0 0
0 0 0 1 1
0 0 0 1 1
Output:
2
Input:
6
1 1 0 1 0 1
0 1 1 1 1 1
0 1 0 0 0 0
0 1 1 0 0 0
0 1 1 1 1 0
0 0 0 1 1 0
Output:
1
Input:
4
0 1 0 1 1 0
1 0 1 1 0 1
1 0 0 0 0 0
0 0 0 1 0 0
Output:
5
the code I came up with for now is :
n = int(input())
blocks = 0
matrix = [[int(i) for i in input().split()] for j in range(n)]
#loop or something to find the blocks in the matrix
print(blocks)
Any help will be greatly appreciated.
def valid(y,x):
if y>=0 and x>=0 and y<N and x<horizontal_len:
return True
def find_blocks(y,x):
Q.append(y)
Q.append(x)
#search around 4 directions (up, right, left, down)
dy = [0,1,0,-1]
dx = [1,0,-1,0]
# if nothing is in Q then terminate counting block
while Q:
y = Q.pop(0)
x = Q.pop(0)
for dir in range(len(dy)):
next_y = y + dy[dir]
next_x = x + dx[dir]
#if around component is valid range(inside the matrix) and it is 1(not 0) then include it as a part of block
if valid(next_y,next_x) and matrix[next_y][next_x] == 1:
Q.append(next_y)
Q.append(next_x)
matrix[next_y][next_x] = -1
N = int(input())
matrix = []
for rows in range(N):
row = list(map(int, input().split()))
matrix.append(row)
#row length
horizontal_len = len(matrix[0])
blocks = 0
#search from matrix[0][0] to matrix[N][horizontal_len]
for start_y in range(N):
for start_x in range(horizontal_len):
#if a number is 1 then start calculating
if matrix[start_y][start_x] == 1:
#make 1s to -1 for not to calculate again
matrix[start_y][start_x] = -1
Q=[]
#start function
find_blocks(start_y, start_x)
blocks +=1
print(blocks)
I used BFS algorithm to solve this question. The quotations are may not enough to understand the logic.
If you have questions about this solution, let me know!

Categories

Resources