Generate paths on n*n grid - algorithm

I have n*n grid, where for example n=10. I have to fill it with black and white elements. Every black element has to have one, two or three black neighbors. It is not allowed to contain black elements with four or zero neighbors.
How should I build this kind of grid ?
Edit:
To be more specific, it is two-dimensional array built for example with two for loops:
n = 10
array = [][];
for ( x = 0; x < n; x++ ) {
for ( y = 0; y < n; y++ ) {
array[x][y] = rand(black/white)
}
}
This pseudo code builds somethind like:
And what I expect is:

Obviously, you're trying to generate "black path" shapes on a write grid.
So let's just do it.
Start with a white grid.
Randomly position some turtles on it.
Then, while your grid doesn't meet a proper white/black cell ratio, do the following
Move each turtle one cell in a random direction and paint it black unless doing so break the "no more than three black neighbors" rule.

Maybe this python code could be of some use. Its basic idea is to do some sort of breadth first traversal of the grid, ensuring that the blackened pixels respect the constraint that they have no more than 3 black neighbours. The graph corresponding to the blackened part of the grid is a tree, as your desired result seemed to be.
import Queue
import Image
import numpy as np
import random
#size of the problem
size = 50
#grid initialization
grid = np.zeros((size,size),dtype=np.uint8)
#start at the center
initpos = (size/2,size/2)
#create the propagation queue
qu = Queue.Queue()
#queue the starting point
qu.put((initpos,initpos))
#the starting point is queued
grid[initpos] = 1
#get the neighbouring grid cells from a position
def get_neighbours(pos):
n1 = (pos[0]+1,pos[1] )
n2 = (pos[0] ,pos[1]+1)
n3 = (pos[0]-1,pos[1] )
n4 = (pos[0] ,pos[1]-1)
return [neigh for neigh in [n1,n2,n3,n4]
if neigh[0] > -1 and \
neigh[0]<size and \
neigh[1] > -1 and \
neigh[1]<size \
]
while(not qu.empty()):
#pop a new element from the queue
#pos is its position in the grid
#parent is the position of the cell which propagated this one
(pos,parent) = qu.get()
#get the neighbouring cells
neighbours = get_neighbours(pos)
#legend for grid values
#0 -> nothing
#1 -> stacked
#2 -> black
#3 -> white
#if any neighbouring cell is black, we could join two branches
has_black = False
for neigh in neighbours:
if neigh != parent and grid[neigh] == 2:
has_black = True
break
if has_black:
#blackening this cell means joining branches, abort
grid[pos] = 3
else:
#this cell does not join branches, blacken it
grid[pos] = 2
#select all valid neighbours for propagation
propag_candidates = [n for n in neighbours if n != parent and grid[n] == 0]
#shuffle to avoid deterministic patterns
random.shuffle(propag_candidates)
#propagate the first two neighbours
for neigh in propag_candidates[:2]:
#queue the neighbour
qu.put((neigh,pos))
#mark it as queued
grid[neigh] = 1
#render image
np.putmask(grid,grid!=2,255)
np.putmask(grid,grid<255,0)
im = Image.fromarray(grid)
im.save('data.png')
Here is a result setting size = 50
and another one setting size = 1000
You can also play with the root of the tree.

With the size that you show here, you could easily go for a bit of a brute force implementation.
Write a function that checks if you meet the requirements, simply by iterating through all cells and counting neighbors.
After that, do something like this:
Start out with a white grid.
Then repeatedly:
pick a random cell
If the cell is white:
make it black
call the grid checking routine.
if the grid became invalid:
color it gray to make sure you don't try this one again
do this until you think it took long enough, or there are no more white cells.
then make all gray cells white.
If your grid is large (thousands of pixels), you should probably look for a more efficient algorithm, but for a 10x10 grid this will be calculated in a flash.

Related

moving an L-shaped piece on a grid

i'm trying to code a small grid game, but i'm having trouble with coding piece movements.
I have a small 4x4 rgb pixels grid, initialized as np.zeros(4,4,3), full black. An update method to refresh objects position and free cells, a reset method, and a simple show function that uses cv2 to show the grid from a pixel matrix.
class Grid():
def __init__(self):
self.cells = np.zeros((SIZE, SIZE, 3), dtype=np.uint8)
self.free_cells = []
def update(self, c, l):
self.reset() #clear cells and free cells list
self.cells[c.x][c.y] = COIN_COL #set coin position
for i in range(len(l.coords)): #set L posiion
self.cells[l.coords[i][0]][l.coords[i][1]] = L_COL
for i in range(len(self.cells)): #calculate free cells
for j in range(len(self.cells)):
if np.amax(self.cells[i][j]) == 0:
self.free_cells.append((i, j))
def reset(self):
self.cells = np.zeros((SIZE, SIZE, 3), dtype=np.uint8)
self.free_cells = []
def show(self):
img = Image.fromarray(self.cells, "RGB")
img = img.resize((200,200))
cv2.imshow('img', np.array(img))
cv2.waitKey(0)
on the grid there are 2 pieces, an L-shaped one 3x2, and a coin 1x1.
they both have colors and coordinates
SIZE = 4
COIN_COL = (255,255,255)
L_COL = (0,0,255)
C_COORDS = np.array((0,0), dtype=np.uint8) #coin starting position
L_COORDS = np.array(((1,1),(2,1),(3,1),(3,2)), dtype=np.uint8) #L starting position
class Coin():
def __init__(self, coords):
self.x = coords[0]
self.y = coords[1]
class LShape():
def __init__(self, coords):
self.coords = coords
each piece can rotate, translate and move whenever he wants as long as it stays inside the grid, and does not overlap with other pieces.
moving the coin is straightforward: check empty cells, choose one, update coin coordinates, update grid.
Moving the L, doesn't look that simple. How can i check every possible legal move of such a piece? (there could be more than 1 coin on the grid). i started by calculating the empty cells, so that i have a layout of the free space, and i'm trying to come up with an algorithm to highlight legal moves by first removing isolated free cells (1x1), than removing isolated couples (2x1), and so on, but i got stuck halfway through.
I was also thinking about making a list of every possible position on an empty grid, and removing positions from the list if they require an occupied cell, but that doesn't seems elegant nor optimal.
Any idea on how to approach the problem?

How do I programmatically create a grid of pixels given only the pixels neighbors

I'm trying to figure out an algorithm for building a grid, based on number of pixels and surrounding pixels. For instance let's say I have 200 random pixels. I have pixel a, and I can get references to each pixel surrounding it. This holds true for all the pixels. In essence each pixel is s puzzle piece, and each piece has a reference to all its neighbors. How do Programmatically creat the grid of pixels ( the finished puzzle ) given that information
Assuming your
Input is a list of pixels and each pixel has the attributes top, left, bottom and right (references to the surrounding pixels) and your
Output will be an 2D Array grid of pixels,
you can do as follows:
def pixel_graph_to_grid(pixels):
if len(pixels) == 0:
return [[]]
# (1) Finding the top left pixel.
p = pixels[0]
while p.top:
p = p.top
while p.left:
p = p.left
# (2) Go row-wise through the image.
grid = []
first_of_row = p
while True:
p = first_of_row
row = [p]
while p.right:
p = p.right
row.append(p)
grid.append(row)
if first_of_row.bottom:
first_of_row = first_of_row.bottom
else:
break
You can also do some counting similar to (1) to know how much memory you have to allocate for the grid.
This algorithm has linear runtime and requires constant extra space, so it should be optimal.

Ordering coordinates from top left to bottom right

How can I go about trying to order the points of an irregular array from top left to bottom right, such as in the image below?
Methods I've considered are:
calculate the distance of each point from the top left of the image (Pythagoras's theorem) but apply some kind of weighting to the Y coordinate in an attempt to prioritise points on the same 'row' e.g. distance = SQRT((x * x) + (weighting * (y * y)))
sort the points into logical rows, then sort each row.
Part of the difficulty is that I do not know how many rows and columns will be present in the image coupled with the irregularity of the array of points. Any advice would be greatly appreciated.
Even though the question is a bit older, I recently had a similar problem when calibrating a camera.
The algorithm is quite simple and based on this paper:
Find the top left point: min(x+y)
Find the top right point: max(x-y)
Create a straight line from the points.
Calculate the distance of all points to the line
If it is smaller than the radius of the circle (or a threshold): point is in the top line.
Otherwise: point is in the rest of the block.
Sort points of the top line by x value and save.
Repeat until there are no points left.
My python implementation looks like this:
#detect the keypoints
detector = cv2.SimpleBlobDetector_create(params)
keypoints = detector.detect(img)
img_with_keypoints = cv2.drawKeypoints(img, keypoints, np.array([]), (0, 0, 255),
cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
points = []
keypoints_to_search = keypoints[:]
while len(keypoints_to_search) > 0:
a = sorted(keypoints_to_search, key=lambda p: (p.pt[0]) + (p.pt[1]))[0] # find upper left point
b = sorted(keypoints_to_search, key=lambda p: (p.pt[0]) - (p.pt[1]))[-1] # find upper right point
cv2.line(img_with_keypoints, (int(a.pt[0]), int(a.pt[1])), (int(b.pt[0]), int(b.pt[1])), (255, 0, 0), 1)
# convert opencv keypoint to numpy 3d point
a = np.array([a.pt[0], a.pt[1], 0])
b = np.array([b.pt[0], b.pt[1], 0])
row_points = []
remaining_points = []
for k in keypoints_to_search:
p = np.array([k.pt[0], k.pt[1], 0])
d = k.size # diameter of the keypoint (might be a theshold)
dist = np.linalg.norm(np.cross(np.subtract(p, a), np.subtract(b, a))) / np.linalg.norm(b) # distance between keypoint and line a->b
if d/2 > dist:
row_points.append(k)
else:
remaining_points.append(k)
points.extend(sorted(row_points, key=lambda h: h.pt[0]))
keypoints_to_search = remaining_points
Jumping on this old thread because I just dealt with the same thing: sorting a sloppily aligned grid of placed objects by left-to-right, top to bottom location. The drawing at the top in the original post sums it up perfectly, except that this solution supports rows with varying numbers of nodes.
S. Vogt's script above was super helpful (and the script below is entirely based on his/hers), but my conditions are narrower. Vogt's solution accommodates a grid that may be tilted from the horizontal axis. I assume no tilting, so I don't need to compare distances from a potentially tilted top line, but rather from a single point's y value.
Javascript below:
interface Node {x: number; y: number; width:number; height:number;}
const sortedNodes = (nodeArray:Node[]) => {
let sortedNodes:Node[] = []; // this is the return value
let availableNodes = [...nodeArray]; // make copy of input array
while(availableNodes.length > 0){
// find y value of topmost node in availableNodes. (Change this to a reduce if you want.)
let minY = Number.MAX_SAFE_INTEGER;
for (const node of availableNodes){
minY = Math.min(minY, node.y)
}
// find nodes in top row: assume a node is in the top row when its distance from minY
// is less than its height
const topRow:Node[] = [];
const otherRows:Node[] = [];
for (const node of availableNodes){
if (Math.abs(minY - node.y) <= node.height){
topRow.push(node);
} else {
otherRows.push(node);
}
}
topRow.sort((a,b) => a.x - b.x); // we have the top row: sort it by x
sortedNodes = [...sortedNodes,...topRow] // append nodes in row to sorted nodes
availableNodes = [...otherRows] // update available nodes to exclude handled rows
}
return sortedNodes;
};
The above assumes that all node heights are the same. If you have some nodes that are much taller than others, get the value of the minimum node height of all nodes and use it instead of the iterated "node.height" value. I.e., you would change this line of the script above to use the minimum height of all nodes rather that the iterated one.
if (Math.abs(minY - node.y) <= node.height)
I propose the following idea:
1. count the points (p)
2. for each point, round it's x and y coordinates down to some number, like
x = int(x/n)*n, y = int(y/m)*m for some n,m
3. If m,n are too big, the number of counts will drop. Determine m, n iteratively so that the number of points p will just be preserved.
Starting values could be in alignment with max(x) - min(x). For searching employ a binary search. X and Y scaling would be independent of each other.
In natural words this would pin the individual points to grid points by stretching or shrinking the grid distances, until all points have at most one common coordinate (X or Y) but no 2 points overlap. You could call that classifying as well.

Distinguish a simply connected figures?

So I have a binary matrix in Matlab.
It is basically a blob (pixels of value 1) surrounded by a neutral background (value 0).
I want to figure out whether this blob is simply connected or not.
Figure below is a straightforward example.
How can this be achieved?
Notably I understand that every path in a pixelated image can be created by choosing from 4 adjacent elements (up, down, left, right) or 8 adjacent elements etc - it doesn't matter in this case.
Code
%// Assuming bw1 is the input binary matrix
[L,num] = bwlabel( ~bw1 );
counts = sum(bsxfun(#eq,L(:),1:num));
[~,ind] = max(counts);
bw2 = ~(L==ind);
%// Output decision
[L,num] = bwlabel( bw1 );
if ~nnz(bw1~=bw2) && num==1
disp('Yes it is a simply connected blob.')
else
disp('Nope, not a simply connected blob.')
end

Largest rectangular sub matrix with the same number

I am trying to come up with a dynamic programming algorithm that finds the largest sub matrix within a matrix that consists of the same number:
example:
{5 5 8}
{5 5 7}
{3 4 1}
Answer : 4 elements due to the matrix
5 5
5 5
This is a question I already answered here (and here, modified version). In both cases the algorithm was applied to binary case (zeros and ones), but the modification for arbitrary numbers is quite easy (but sorry, I keep the images for the binary version of the problem). You can do this very efficiently by two pass linear O(n) time algorithm - n being number of elements. However, this is not a dynamic programming - I think using dynamic programming here would be clumsy and inefficient in the end, because of the difficulties with problem decomposition, as the OP mentioned - unless its a homework - but in that case you can try to impress by this algorithm :-) as there's obviously no faster solution than O(n).
Algorithm (pictures depict binary case):
Say you want to find largest rectangle of free (white) elements.
Here follows the two pass linear O(n) time algorithm (n being number of elemets):
1) in a first pass, go by columns, from bottom to top, and for each element, denote the number of consecutive elements available up to this one:
repeat, until:
Pictures depict the binary case. In case of arbitrary numbers you hold 2 matrices - first with the original numbers and second with the auxiliary numbers that are filled in the image above. You have to check the original matrix and if you find a number different from the previous one, you just start the numbering (in the auxiliary matrix) again from 1.
2) in a second pass you go by rows, holding data structure of potential rectangles, i.e. the rectangles containing current position somewhere at the top edge. See the following picture (current position is red, 3 potential rectangles - purple - height 1, green - height 2 and yellow - height 3):
For each rectangle we keep its height k and its left edge. In other words we keep track of the sums of consecutive numbers that were >= k (i.e. potential rectangles of height k). This data structure can be represented by an array with double linked list linking occupied items, and the array size would be limited by the matrix height.
Pseudocode of 2nd pass (non-binary version with arbitrary numbers):
var m[] // original matrix
var aux[] // auxiliary matrix filled in the 1st pass
var rect[] // array of potential rectangles, indexed by their height
// the occupied items are also linked in double linked list,
// ordered by height
foreach row = 1..N // go by rows
foreach col = 1..M
if (col > 1 AND m[row, col] != m[row, col - 1]) // new number
close_potential_rectangles_higher_than(0); // close all rectangles
height = aux[row, col] // maximal height possible at current position
if (!rect[height]) { // rectangle with height does not exist
create rect[height] // open new rectangle
if (rect[height].next) // rectangle with nearest higher height
// if it exists, start from its left edge
rect[height].left_col = rect[height].next.left_col
else
rect[height].left_col = col;
}
close_potential_rectangles_higher_than(height)
end for // end row
close_potential_rectangles_higher_than(0);
// end of row -> close all rect., supposing col is M+1 now!
end for // end matrix
The function for closing rectangles:
function close_potential_rectangles_higher_than(height)
close_r = rectangle with highest height (last item in dll)
while (close_r.height > height) { // higher? close it
area = close_r.height * (col - close_r.left_col)
if (area > max_area) { // we have maximal rectangle!
max_area = area
max_topleft = [row, close_r.left_col]
max_bottomright = [row + height - 1, col - 1]
}
close_r = close_r.prev
// remove the rectangle close_r from the double linked list
}
end function
This way you can also get all maximum rectangles. So in the end you get:
And what the complexity will be? You see that the function close_potential_rectangles_higher_than is O(1) per closed rectangle. Because for each field we create 1 potential rectangle at the maximum, the total number of potential rectangles ever present in particular row is never higher than the length of the row. Therefore, complexity of this function is O(1) amortized!
So the whole complexity is O(n) where n is number of matrix elements.
A dynamic solution:
Define a new matrix A wich will store in A[i,j] two values: the width and the height of the largest submatrix with the left upper corner at i,j, fill this matrix starting from the bottom right corner, by rows bottom to top. You'll find four cases:
case 1: none of the right or bottom neighbour elements in the original matrix are equal to the current one, i.e: M[i,j] != M[i+1,j] and M[i,j] != M[i,j+1] being M the original matrix, in this case, the value of A[i,j] is 1x1
case 2: the neighbour element to the right is equal to the current one but the bottom one is different, the value of A[i,j].width is A[i+1,j].width+1 and A[i,j].height=1
case 3: the neighbour element to the bottom is equal but the right one is different, A[i,j].width=1, A[i,j].height=A[i,j+1].height+1
case 4: both neighbours are equal: A[i,j].width = min(A[i+1,j].width+1,A[i,j+1].width) and A[i,j].height = min(A[i,j+1]+1,A[i+1,j])
the size of the largest matrix that has the upper left corner at i,j is A[i,j].width*A[i,j].height so you can update the max value found while calculating the A[i,j]
the bottom row and the rightmost column elements are treated as if their neighbours to the bottom and to the right respectively are different
in your example, the resulting matrix A would be:
{2:2 1:2 1:1}
{2:1 1:1 1:1}
{1:1 1:1 1:1}
being w:h width:height
Modification to the above answer:
Define a new matrix A wich will store in A[i,j] two values: the width and the height of the largest submatrix with the left upper corner at i,j, fill this matrix starting from the bottom right corner, by rows bottom to top. You'll find four cases:
case 1: none of the right or bottom neighbour elements in the original matrix are equal to the current one, i.e: M[i,j] != M[i+1,j] and M[i,j] != M[i,j+1] being M the original matrix, in this case, the value of A[i,j] is 1x1
case 2: the neighbour element to the right is equal to the current one but the bottom one is different, the value of A[i,j].width is A[i+1,j].width+1 and A[i,j].height=1
case 3: the neighbour element to the bottom is equal but the right one is different, A[i,j].width=1, A[i,j].height=A[i,j+1].height+1
case 4: both neighbours are equal:
Three rectangles are considered:
1. A[i,j].width=A[i,j+1].width+1; A[i,j].height=1;
A[i,j].height=A[i+1,j].height+1; a[i,j].width=1;
A[i,j].width = min(A[i+1,j].width+1,A[i,j+1].width) and A[i,j].height = min(A[i,j+1]+1,A[i+1,j])
The one with the max area in the above three cases will be considered to represent the rectangle at this position.
The size of the largest matrix that has the upper left corner at i,j is A[i,j].width*A[i,j].height so you can update the max value found while calculating the A[i,j]
the bottom row and the rightmost column elements are treated as if their neighbours to the bottom and to the right respectively are different.
This question is a duplicate. I have tried to flag it as a duplicate. Here is a Python solution, which also returns the position and shape of the largest rectangular submatrix:
#!/usr/bin/env python3
import numpy
s = '''5 5 8
5 5 7
3 4 1'''
nrows = 3
ncols = 3
skip_not = 5
area_max = (0, [])
a = numpy.fromstring(s, dtype=int, sep=' ').reshape(nrows, ncols)
w = numpy.zeros(dtype=int, shape=a.shape)
h = numpy.zeros(dtype=int, shape=a.shape)
for r in range(nrows):
for c in range(ncols):
if not a[r][c] == skip_not:
continue
if r == 0:
h[r][c] = 1
else:
h[r][c] = h[r-1][c]+1
if c == 0:
w[r][c] = 1
else:
w[r][c] = w[r][c-1]+1
minw = w[r][c]
for dh in range(h[r][c]):
minw = min(minw, w[r-dh][c])
area = (dh+1)*minw
if area > area_max[0]:
area_max = (area, [(r, c, dh+1, minw)])
print('area', area_max[0])
for t in area_max[1]:
print('coord and shape', t)
Output:
area 4
coord and shape (1, 1, 2, 2)

Resources