How can I recursively divide the grid in my maze? - python

I am trying to create a maze generator using recursive division. I use this link:
Maze generation - recursive division (how it works?) as my guide as to how to approach the problem.
Here is my code so far:
import random
# Maze: 0 - N : 4 x 4 Grid
# Grid: 0 - (2n + 1) : 9 x 9 Array
# TODO: Now, Find a way to save the previous walls and not just only one at a time
rows = 9
cols = 9
start = 2
end = 7
# -------------------------------------------------------------------------------------
# Lists for all even / odd numbers in given range
evens = [n for n in range(start, end+1) if n % 2 == 0]
odds = [m for m in range(start, end+1) if m % 2 != 0]
# Generate random even/odd integer value for walls/ passages respectively
# Walls: Not sure if 2 variables are necessary-----------------------------------------
wallX = random.choice(evens)
wallY = random.choice(evens)
# Passages
passageX = random.choice(odds)
passageY = random.choice(odds)
#--------------------------------------------------------------------------------------
# Random direction: True = Horizontal Slice, False = Vertical Slice
randomDirection = random.choice([True, False])
arr = [['0' for i in range(cols)] for j in range(rows)]
def displayBoard(arr):
print()
for i in range(len(arr)):
for j in range(len(arr[i])):
# Print just the edges
if i == 0 or i == 8 or j == 0 or j == 8:
print('*', end = ' ')
# Print wall
elif arr[i][j] == 1:
print('.', end = ' ')
else:
print (' ', end = ' ')
print()
# Function choose direction to slice
def chooseDir(arr):
for i in range(len(arr)):
for j in range(len(arr[i])):
# Horizontal Direction Slice
if randomDirection:
arr[wallX][j] = 1
arr[wallX][passageY] = 2
print(arr[i][j], end = ' ')
# Vertical Slice
else:
arr[i][wallY] = 1
arr[passageX][wallY] = 2
print(arr[i][j], end = ' ')
print()
displayBoard(arr)
print()
mazeX = 0
mazeY = 0
# Write the recursive division function:
def divide():
chooseDir(arr)
print()
divide()
What this produces is a grid that is randomly sliced at an even index (creating walls) and creates passages at odd indices.
Output: 1 = wall, 2 = passage made
0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 2 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0
* * * * * * * * *
* . *
* . *
* *
* . *
* . *
* . *
* . *
* * * * * * * * *
My issue is that I don't know how to write my recursive function. Do I call division on the two new cells created when a wall is made and continuously divide the "sub cells".
Or I know that a 4 x 4 cell grid will provide an array of 9 x 9 and I will have 16 cells total.
Then I can call division until a certain condition is met, increment to the next cell until all 16 were visited.
In both cases, I am not sure how to represent the new walls/cells created so that I can write the division function. Up until now, I've been using the grid coordinates.

You asked "Do I call division on the two new cells created when a wall is made and continuously divide the "sub cells"". Yes, that is the essence of recursion. Take a big problem and make smaller problem(s). Repeat with the smaller problems. Eventually, the problems are small enough to easily solve. Then put all the small problems back together to solve the original problem.
For the maze, the first wall split the maze into two smaller mazes. Use the same algorithm to split each of them and there are not 4 smaller mazes. Repeat until the sub-mazes are too small to split any more.
Your code that splits the maze should go in a function. If the sub-maze is big enough to split, the function splits the sub-maze and then calls itself on the two smaller sub-mazes.

Related

How to do a recursive procedure to represent a triangle in the upper half of the matrix in python [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed last year.
Improve this question
I did an Algorithm to print a triangle in the upper half of the matrix (without recursive function) but now i want to do it recursively can anyone Help?
Thanks
CLICK HERE TO SEE AN EXAMPLE
My python code:
def T(row,column):
print("Row: ",row)
print("Column", column)
if row != column and row%2 == 0:
print("Please enter valid number")
else:
matrix = []
start = 1
cteRow = row
cteColumn = column
for i in range(0,column):
matrix.append(list(range(start,row + 1)))
start = start + cteRow
row = row + cteColumn
print("The Matrix: \n")
for i in range(len(matrix)):
for j in range(len(matrix)):
print(matrix[i][j], end= " ")
print()
print()
length = len(matrix)
middle = int(length/2)
for i in range(length):
for j in range(length):
matrix[i][j] = 0
if (middle + i)<= length and (middle - i)>= 0:
matrix[i][middle] = 1
myRangeList=list(range(middle-i,middle+i+1))
for n in myRangeList:
matrix[i][n] = 1
print(matrix[i][j], end = " ")
print()
T(5,5)
To make it recursive, you have to come up with a method to convert the result of a smaller matrix into a larger one.
for example:
From T(3,5) --> T(4,7)
0 0 1 0 0 0 0 0 1 0 0 0
0 1 1 1 0 0 0 1 1 1 0 0
1 1 1 1 1 0 1 1 1 1 1 0
1 1 1 1 1 1 1
The transformation could be adding zeros on each side and a line of 1s at the bottom:
0 0 1 0 0 0 x x x x x 0 0 0 0 1 0 0 0
0 1 1 1 0 0 x x x x x 0 0 0 1 1 1 0 0
1 1 1 1 1 0 x x x x x 0 0 1 1 1 1 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1
This will be easy if the parameters provided fit the triangle size exactly: rows = (columns+1)/2. You can handle the disproportionate dimensions by padding the result from an appropriate size ratio with zeros so that the function only needs to handle proper proportions:
def R(rows,cols):
if not cols%2: # must have odd number of columns (pad trailing zero)
return [ row+[0] for row in R(rows,cols-1)]
height = (cols+1)//2
if rows>height: # too high, pad with lines of zeros
return R(height,cols)+[[0]*cols for _ in range(rows-height)]
if rows<height: # not high enough
return R(height,cols)[:rows] # truncate bottom
if cols == 1: # base case (1,1)
return [[1]]
result = R(rows-1,cols-2) # Smaller solution
result = [[0]+row+[0] for row in result] # pad with zeros
result += [[1]*cols] # add line of 1s
return result
The function only generates the matrix. User input and printing should always be separate from data manipulation (especially for recursion)
output:
for row in R(5,5): print(*row)
0 0 1 0 0
0 1 1 1 0
1 1 1 1 1
0 0 0 0 0
0 0 0 0 0
Note that this will work for any combination of row & column sizes but, if you always provide the function with a square matrix, only the "upper half" will contain the triangle because triangle height = (columns+1)/2. It would also be unnecessary to ask the user for both a number of rows and a number of columns if the two are required to be equal.
For only square matrices with an odd number of columns, the process can be separated in a recursive part and a padding function that uses it:
def R(cols):
if cols == 1: return [[1]] # base case (1,1)
result = R(cols-2) # Smaller solution
result = [[0]+row+[0] for row in result] # pad with zeros
result += [[1]*cols] # add line of 1s
return result
def T(n):
return R(n)+[[0]*n]*((n-1)//2) # square matrix with padding
for row in T(7): print(*row)
0 0 0 1 0 0 0
0 0 1 1 1 0 0
0 1 1 1 1 1 0
1 1 1 1 1 1 1
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0

How to use numpy/python to make a "chain reaction"?

I am trying to implement a "chain reaction". For example, for a 3x3 matrix all elements are initialized to zero, then one element (randomly) is assigned 1. A first iteration occurs and all the elements neighbouring 1 (up/down/left/right) gets changed from 0 -> 1. Now second iteration occurs and the process continues till all the elements in a(1) column become 1.
I have thought of using nested loops (for, for if, if elif..) but the code becomes kind of ugly (imo) and time consuming. I was wondering if this can be done with any other approach.
My Approach: Initialize with the help of np.zeros, then randomly assign any one element to 1.
import numpy as np
from random import randint, choice
import time
n = int(input("Enter number of modes(n):"))
start = time.time()
m1 = [i+1 for i in range(n)]
print(m1)
# initializing
m = []
ones = [1,1,1,1,1]
for i in range(n):
a = np.zeros(n)
m.append(a)
m1 = choice(m)
A = randint(0, len(m1)-1)
B = randint(0, len(ones)-1)
m1[A]=ones[B]
# game begins here:
print("----Initializing----")
print("1st iteration")
print(np.array(m))
One approach is to use np.argwhere() to get the indices of nonzero elements at each iteration. That way you don't need to go through the entire matrix at each iteration, but you will need to do some if-else checking to see if you're on a boundary.
import numpy as np
def flood_fill_naive(n):
A = np.zeros((n,n)) # Initialize an array of zeros.
snapshots = [] # Copies of the matrix after each change.
def fill_entry(i,j):
"""Set A[i,j] = 1 if (i,j) is a valid index pair for A."""
if 0 <= i < A.shape[0] and 0 <= j < A.shape[1]:
A[i,j] = 1
snapshots.append(A.copy())
# Fill in a single random entry to start.
i,j = np.random.randint(A.shape)
fill_entry(i,j)
# Do the reaction until all entries are 1.
while np.count_nonzero(A) != A.size:
# Find the indices of nonzero elements.
for i,j in np.argwhere(A):
# Set 0 -> 1 on neighbors, except at boundaries.
fill_entry(i-1,j) # Up
fill_entry(i,j-1) # Left
fill_entry(i,j+1) # Right
fill_entry(i+1,j) # Down
return snapshots
if __name__ == "__main__":
n = int(input("Enter integer size of matrix: "))
for snap in flood_fill_naive(n):
print(snap)
But notice that this approach does a lot of repeat work. For example, the initial 1 only updates its neighbors once, and then you can forget about it. So at each step, you really only need to remember the spaces that were just updated, since they are the only ones that potentially have neighbors that are 0.
0 0 0 0 0 0 0 1 0 0 0 1 x 1 0 1 x x x 1
0 0 1 0 0 0 1 x 1 0 1 x x x 1 x x x x x
0 0 0 0 0 --> 0 0 1 0 0 --> 0 1 x 1 0 --> 1 x x x 1 --> ...
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 x 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
So let's just try to keep track of the indices of the "current 1s" and "previous 1s" (marked as x's above). In fact, what we're doing here is a breadth-first search. See BFS and Flood Fill on Wikipedia.
def flood_fill_bfs(n):
A = np.zeros((n,n)) # Initialize an array of zeros.
snapshots = [] # Copies of the matrix after each change.
visit_queue = [] # List of indices to visit in the future.
visited = set() # Set of indices already visited.
def fill_entry(i,j):
"""If (i,j) has not been visited, visit it by setting A[i,j] = 1
and adding it to the visit queue.
"""
# Do nothing if this index has been visited.
if (i,j) in visited:
return
# If the index has not been visited but is valid,
if 0 <= i < A.shape[0] and 0 <= j < A.shape[1]:
A[i,j] = 1
visited.add((i,j))
visit_queue.append((i,j))
snapshots.append(A.copy())
# Fill in a single random entry to start.
i,j = np.random.randint(A.shape)
fill_entry(i,j)
# Fill in neighbors of 1's until all entries are 1.
while np.count_nonzero(A) != A.size:
i,j = visit_queue.pop(0)
# Set 0 -> 1 on neighbors, except at boundaries.
fill_entry(i-1,j) # Up
fill_entry(i,j-1) # Left
fill_entry(i,j+1) # Right
fill_entry(i+1,j) # Down
return snapshots
if __name__ == "__main__":
n = int(input("Enter integer size of matrix: "))
for snap in flood_fill_bfs(n):
print(snap)
You can guess which routine will be faster:
In [1]: %time _ = flood_fill_naive(100)
CPU times: user 6.21 s, sys: 258 ms, total: 6.47 s
Wall time: 6.49 s
In [2]: %time _ = flood_fill_bfs(100)
CPU times: user 709 ms, sys: 310 ms, total: 1.02 s
Wall time: 1.03 s

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!

Find all paths of length 2 in a graph

I've tried to create an algorithm for finding all paths of length 2, but it doesn't seem to work properly:
input_split = input().split(' ')
node_count = int(input_split[0])
input_count = int(input_split[1])
items = np.zeros((node_count, node_count), dtype=np.int32) # matrix of adjacency
for j in range(input_count):
split = input().split(' ')
x = int(split[0]) - 1 # convert 1 based coordinates to 0 based
y = int(split[1]) - 1
items[x][y] = 1
items[y][x] = 1
result = np.linalg.matrix_power(items, 2)
result_sum = int(np.sum(result) / 2) # reverse paths are counted only once
print(result_sum)
Sample input:
6 7
1 2
2 3
3 1
2 4
4 5
5 6
6 2
The result should be 11, but it prints 18.
You're on the right track when calculating the square of the adjacency matrix. After the exponentiation you would get result matrix that looks like this:
[[2 1 1 1 0 1]
[1 4 1 0 2 0]
[1 1 2 1 0 1]
[1 0 1 2 0 2]
[0 2 0 0 2 0]
[1 0 1 2 0 2]]
First you need to exclude all diagonal entries from this matrix, because those denote walks that are not paths, as their starting and ending node is the same. Note that for length 2 that is the only way how nodes can be repeating.
The other entries need to be counted only once, because of symmetry. So only look at the upper right triangle of the matrix.
One way to do it is:
result_sum = 0
for i in range(input_count - 1):
for j in range(i + 1, input_count - 1):
result_sum += result[i][j]
print(result_sum) # prints 11
More Pythonic way, one-liner using numpy.trace():
result_sum = (np.sum(result) - np.trace(result)) // 2
You are calculating walks, which would include walks 6-7-6 (which is not a P2)
this discussion might help:
https://math.stackexchange.com/questions/1890620/finding-path-lengths-by-the-power-of-adjacency-matrix-of-an-undirected-graph

Kadane's Algorithm for 2D array with known boundaries

I have implemented the Kadane's algorithm for a 2D array in Python 2 with known boundaries, but I'm using the implementation for an online contest and the time it takes is more than the time given.
So that made me think if there is maybe another algorithm similar to Kadane's that has a smaller complexity, or if my code can be optimized in a way. My implementation works for any array with dimensions N x M and a subarray with dimensions maxRows x maxCols.
maxSumSubarray.py
import numpy as np
# returns the maximum sum for the given vector using kadane's algorithm, with
# maxRows maximum members in the sum
def kadane1DwithBounds(maxRows):
global temp
m = s = sum(temp[i] for i in xrange(maxRows))
k = 0
for i in xrange(1, N - maxRows + 1):
s -= temp[k]
s += temp[maxRows + i - 1]
k += 1
m = max(m, s)
return m
# prints the maximum "area" given by the values of an NxM array inside a
# subarray with dimensions maxRows x maxCols. temp holds the latest vector to be
# given to kadane1DwithBounds()
def kadane2DwithBounds(maxRows, maxCols):
global temp
for i in xrange(N):
temp[i] = sum(table[i][j] for j in xrange(maxCols))
m = kadane1DwithBounds(maxRows)
k = 0
for j in xrange(1, M - maxCols + 1):
for i in xrange(N):
temp[i] -= table[i][k]
temp[i] += table[i][maxCols + j - 1]
k += 1
m = max(m, kadane1DwithBounds(maxRows))
print m
line = map(int, raw_input().split())
N = line[0]
M = line[1]
maxRows = line[2]
maxCols = line[3]
table = []
temp = np.empty(N, dtype = int)
for _ in xrange(N):
table.append(map(int, raw_input().split()))
kadane2DwithBounds(maxRows, maxCols)
test.txt
4 8 2 3
1 1 2 3 3 1 1 1
2 2 2 2 2 2 2 2
3 3 3 1 1 3 3 4
0 0 1 1 3 2 2 1
Run with
python maxSumSubarray.py < test.txt
it gives
16
which is correct and is the following rectangle:
2 2 2
3 3 4
I've tried with other dimensions too and I'm pretty sure it works fine. Only problem is time/complexity. Any help would be appreciated! Thanks for your time.

Categories

Resources