Create a "path" (for a maze) in a two-dimensional array - any algorihtm ideas? - arrays

I have a 2-dimensional array which I want to use to create a maze.
Each value can be 0 or 1 where 0 means there is a wall and 1 means there is a room. And now I need an algorithm to create a "path" within that array.
For example the blank array looks like this:
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 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
An example of a "path" would be:
0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0
0 0 0 0 1 0 1 0
0 0 0 1 1 1 1 0
0 0 0 1 0 1 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
It basically comes down to this:
1) Everything is 0
2) I have a random start point which will be a 1
3) From that point I need to make random adjacent values 1. BUT: There should never be a square of 4 or more adjacent fields being a 1 AND: I don't want a linear path, I want it to be a maze
(Not all the array has to be used for the maze. Infact it would be cool if I could say I want a certain amount (say 20 or 50) of rooms within that array)
Are there any good algorithms or ideas I could use for this (especially #3 of my list)?

A recursive backtracking procedure can do this.
algorithm gen-maze(pos):
set pos to 1
build a list of neighboring positions
randomly shuffle this list
for each neighbor n of pos in random order:
if n is 0 and setting it to 1 doesn't create a square:
gen-maze(n)
Start this algorithm from a random position.
For an explanation, read the Wikipedia article about depth-first search and be sure to watch the animation.

Related

Find smallest enclosed area of a grid

There is a grid, the edges of which are always wall.
The internal area of the grid is also divided by walls into several sub-areas, like this
1 = Wall,
0 = Empty.
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 0 0 1 0 0 0 0 0 0 0 0 0 1
1 0 0 0 1 0 0 0 0 0 0 0 0 0 1
1 0 0 0 1 0 0 0 0 0 0 0 0 0 1
1 1 1 1 1 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1 1 1 0 0 0 1
1 0 0 0 0 0 0 0 1 0 1 1 1 1 1
1 0 0 0 0 0 0 0 1 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
I need to find the smallest empty sub-area.
How do i do it?
Telescope's suggestion is correct. Here's a slightly more detailed illustration of how you might approach this.
Given an M x N grid, you will loop over the (M - 2)(N - 2) subgrid ignoring the outer walls. When looking at a given grid cell:
if the grid cell is 0, you have not seen this area yet; begin a flood fill here that counts the number of adjacent 0s and changes them to 2 to mark them as having been seen already in some enclosed area, to avoid having to re-flood this area again later
if a grid cell is 1, it's an interior wall and should be skipped
if the grid cell is 2, you have seen this area already and can skip it
At the end, you'll have counted the area of each distinct enclosed section and can choose the biggest, smallest, or whichever you need to know.
This algorithm will visit each cell at most a few times (worst case is a 1 surrounded by 0s which the flood fill will bump into up to four times, and the wall will be checked once during the subgrid scan). Therefore, the time complexity is O(MN). The algorithm uses the grid itself to keep track of what it has done so far, so no extra memory is used; if the grid must not be modified in place, an extra O(MN) memory can be allocated for a working copy.

Why does summing the rows in this matrix give me 0?

I created an array A by first using the command A = [1:10]'.
Then I created a 10x10 matrix, only containing 0's. I then overwrote this matrix with my A, resulting in this new matrix:
A =
1 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0 0 0
6 0 0 0 0 0 0 0 0 0
7 0 0 0 0 0 0 0 0 0
8 0 0 0 0 0 0 0 0 0
9 0 0 0 0 0 0 0 0 0
10 0 0 0 0 0 0 0 0 0
Now the problem is, when I run the command sum((A(1,1)):(A(1,end))), I keep getting 0 when I should be getting 1, as it is the sum of the first row. I tried running the same command on other matrices and they give me the correct answer, so why isn't it working here?
The term
(A(1,1)):(A(1,end))
creates and empty array, as A(1,1) = 1 and A(1,end) = 0 which makes it impossible for colon : to create a vector, so the sum over it is zero. But its not what you want anyway, I guess.
What you supposedly want is
sum(A(1,:))
or in respect to whole matrix, by specifying the dimension of the sum, e.g.
sum(A,2)
ans =
1
2
3
4
5
6
7
8
9
10
Edit
If you want to start from a different column index you can do the following:
sum( A(rowIndex,firstColumnIndex:lastColumnIndex) )
while end can be used as macro variable for the last index of the corresponding column or row.

Array block splitting in MATLAB

Say we have a vector containing zeros interspersed blocks of ones of varying length, such as:
0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0
I would like to transform this into a 2D array as follows. Each row contains zeros only and one of the blocks. I.e. the number of rows of the 2D array would be the number of blocks at the end. The above array would transform to:
0 0 0 1 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 1 1 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 1 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 1 1 1 0 0 0
I.e the first block ends up in the first row, the second block in the second row etc.
Question
This exercise is rather trivial using loops. My question is if there is a neat way using MATLAB matrix operations, MATLAB functions and array indexing to do this?
Off the top of my head you could use bwlabel (from the Image Processing Toolbox) to assign each cluster of 1's a unique value. You could then use bsxfun to check equality between the labeled version and the unique labels which will automatically expand it out into a matrix.
a = [0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0];
b = bwlabel(a);
out = bsxfun(#eq, (1:max(b))', b);
Without the image processing toolbox you could do effectively the same thing with:
C = cumsum(~a);
out = bsxfun(#eq, unique(C(logical(a))).', C);
I tried this one
N = 100; % set array size
A = randi(2,N,1)-1; % generate random array filled with 0 and 1
d = diff([0;A]); % if 1 : starting point of block
% if -1 : end point of block
ir = find(A); % Find A==1 which will be row index
ic = cumsum(d(ir)>0); % Set col index
% assemble array
% if you want output as full array
A_new = accumarray([ir,ic],ones(size(ir)),[length(A),ic(end)]);
% if you want output as sparse array
A_new = sparse(ir,ic,ones(size(ir)),length(A),ic(end),length(ir));
% display routine
figure;spy(A,'r');hold on;spy([zeros(size(A)),A_new]);
Turns out it is faster than #Suever 's solution (Compared tic toc time with size 10000, 1000 trial). Also, if you use sparse instead of accumarray, then it is much faster
Suever_time = 7~8 sec
Accumarray = 2~3 sec
Sparse = 0.2~0.3 sec
However, his one is much shorter and neat!

matlab matrix from array

I have large array. Now I need a matrix with 8 elements in every row. My array looks like this:
A= Columns 1 through 18
0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0
Columns 19 through 36
0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0
and so on. How I can get [nx8] matrix? For example:
B=[0 0 0 0 0 0 0 0
0 0 1 1 0 1 1 1
0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0]
I've tried reshape, but it didn't work correctly. I get one 1 where shouldn't be.
B=reshape(A,[],8)
You almost have it. The problem is that Matlab fills the matrix column-wise, whereas you seem to want it filled row-rise. So create an 8-row matrix and then transpose:
reshape(A,8,[]).'
What about vec2mat
vec2mat
vec2mat(A,8)

How can i rotate a shape in a matrix by 90 degrees in C?

I have to write rotate function for tetris game. I have bricks in a txt file in a 10x10
dimensioned matrix and i need catch the brick location (L-shape) and rotate it 90ᵒ in clockwise.
input:
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 1 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 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
and output must be like this:
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 1 1 1 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 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
i could rotate whole matrix by 90 degrees but it was not like output. how can i just rotate L-shape? or how can i make output like this? thanks.
EDIT; here's the question: In this homework you are going to write rotate function of a tetris game. You have your bricks in a txt file in a 10x10
dimensioned matrix. You will catch the brick location and rotate it 90ᵒ in clockwise. For simplicity only two kinds of
bricks are going to be rotate by your algorithm. They are “L” character and the inverse of “L”. From the input file
you can take 4 different combinations of this two bricks. Your algorithm must rotate the brick in clockwise and
write the result matrix In an output file in the same location of your executable file.
The input file name is “input.txt” and the output file name is “output.txt”. Your program can rotate the brick in the
output file which it produced before, if it is given as an input.
The sample input and output files are in the attachment.
If you are looking for an algorithm. Then, I think you should first look at the pivot element. About which the rotation takes place. It seems that (4,4) element in the input is the pivot. Ofcourse, this depends on the shape. For a 90 degree clockwise rotation, just regenerate the shape about the pivot. And you will get the output.

Resources