Calculating the distance of items from non-empty edges in a matrix - c

I have a matrix of 0 and 1
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 1 1 0 1 1 1 0 0
0 0 0 1 1 1 1 0 0 0
0 0 0 1 1 1 1 1 1 1
0 0 1 1 1 1 1 0 0 0
0 0 0 0 1 1 0 1 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 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0
I want to calculate the shortest distance of each item from the non-empty edges. You can assume it as pixels of black and white (or empty). We want to calculate the distance of each black pixel from the edge of the black body (through a straight line; horizontal, vertical or diagonal).
The distance is calculated geometrically: the distance of Ai,j and Ai+1,j+1 is sqrt(2).
With the following code in C, I started to calculate the distance of each item from its horizontal and vertical edges (in four directions). Now I want to consider diagonal distance too (at any angle, not just 45°).
The straightforward approach is to calculate the distance of each item from each edge. However, as the matrix gets larger, the loops become painfully slow.
Since we have the distance from horizontal and vertical edges for each item, I look for a hack to find the shortest distance to the edge by examining neighbour items in fewer checks.
#include <stdlib.h>
#include <stdio.h>
int min(int a, int b, int c, int d)
{
int e = a < b ? a : b;
int f = c < d ? c : d;
int r = e < f ? e : f;
return r;
}
int main()
{
int width = 50;
int height = 50;
int points[width][height];
int distances[width][height][5]; // 0 left 1 right 2 bottom 3 top 4 min
// some random data
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
points[x][y] = rand() % 2;
}
}
// scanning in four direction to check if the previous neighbour exists
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (points[x][y] > 0)
{
if (x > 0)
{
distances[x][y][0] = distances[x - 1][y][0] > 0 ? distances[x - 1][y][0] + 1 : 1;
}
else
{
distances[x][y][0] = 1;
}
}
}
for (int x = width - 1; x >= 0; x--)
{
if (points[x][y] > 0)
{
if (x < width - 1)
{
distances[x][y][1] = distances[x + 1][y][1] > 0 ? distances[x + 1][y][1] + 1 : 1;
}
else
{
distances[x][y][1] = 1;
}
}
}
}
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (points[x][y] > 0)
{
if (y > 0)
{
distances[x][y][2] = distances[x][y - 1][2] > 0 ? distances[x][y - 1][2] + 1 : 1;
}
else
{
distances[x][y][2] = 1;
}
}
}
for (int y = height - 1; y >= 0; y--)
{
if (points[x][y] > 0)
{
if (y < height - 1)
{
distances[x][y][3] = distances[x][y + 1][3] > 0 ? distances[x][y + 1][3] + 1 : 1;
}
else
{
distances[x][y][3] = 1;
}
}
}
}
// finding the minimum of four distances
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (points[x][y] > 0)
{
distances[x][y][4] = min(distances[x][y][0], distances[x][y][1], distances[x][y][2], distances[x][y][3]);
printf("%d %d %d %d %d %d %d \n", x, y, distances[x][y][0], distances[x][y][1], distances[x][y][2], distances[x][y][3], distances[x][y][4]);
}
}
}
return 0;
}

If I understood correctly, given an arbitrary body as the ameba-like shown below, you would like to find the shortest distance from its containing points (for instance, the black point in the figure below) to the edges of the black body. This is the distance shown in blue. And you would like to hopefully take advantage of the orthogonal distances already calculated (black straight lines in the figure) to find it quickly.
Since the shape is arbitrary and not many assumptions can be made about it, the only thing I could think of is to confine the search for the shortest distance to the bounding square shown below in green. The value of the green square side is two times the shortest orthogonal distance found in your algorithm (from the black point to the green point).
Another possible approach would be to get instead a 1/8, 1/4 or so of the size of this green square and if no edges are found, keep increasing it until you find one with a few edges. It is guaranteed that at least the last green square will have at least one edge point, which is the orthogonal distance itself.
Playing with some strategy to grow the green square, maybe you can get a satisfactory performance heuristically.
This solution is easier said than done when it comes to put it in code, but I'm not quite sure I got the problem correctly so I stopped here.
One issue I found is that the term "black body" is not well defined, and the matrix shown in the question does not have any sparse points so it's not random at all as the posted code generates. Does the black body allow holes in it? Even the word "edge" is confusing to me because my English is not very good and the term reminds me of the term used in graph theory which is actually a line segment.
I tried the code and its output seems correct and clear. Just noticed some rubbish is coming out from the not initialized distances variable. Easier to get this if you reduce the size of points array to 10x10 or so.
EDIT:
Here is a possible implementation of the first method. The function that calculates the shortest distance to the edge, taking into account a bounding square, is the get_min_dist_to_edge function. All edges are added to a list to reduce unnecessary checks. To get the first point of the list inside the bounding square, there is no way other than iterating the list from the beginning. In a use case with too many edges, this list can get too large. A hash table containing the elements of the list mapped to its y coordinate would allow to find the first element inside the square much faster, at the expense of some memory.
#include "ameba.h"
#include <sys/queue.h>
#include <search.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
struct point_entry_t {
int x;
int y;
LIST_ENTRY(point_entry_t) entries;
};
LIST_HEAD(slisthead, point_entry_t)
edges_list_head = LIST_HEAD_INITIALIZER(edges_list_head);
void add_point_to_edges_list(int x, int y)
{
static int list_initialized = 0;
if (list_initialized == 0) {
LIST_INIT(&edges_list_head);
list_initialized = 1;
}
struct point_entry_t *entry = malloc(sizeof(*entry));
if (entry) {
entry->x = x;
entry->y = y;
LIST_INSERT_HEAD(&edges_list_head, entry, entries);
}
}
void clear_list(void)
{
while (!LIST_EMPTY(&edges_list_head)) {
struct point_entry_t *n1 = LIST_FIRST(&edges_list_head);
LIST_REMOVE(n1, entries);
free(n1);
}
}
int min(int a, int b, int c, int d)
{
int e = a < b ? a : b;
int f = c < d ? c : d;
int r = e < f ? e : f;
return r;
}
int calc_distances(unsigned char points[80][80], int distances[80][80][5])
{
int width = 80;
int height = 80;
// scanning in four direction to check if the previous neighbour exists
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (points[x][y] > 0)
{
if (x > 0)
{
distances[x][y][0] = distances[x - 1][y][0] > 0 ? distances[x - 1][y][0] + 1 : 1;
}
else
{
distances[x][y][0] = 1;
}
}
}
for (int x = width - 1; x >= 0; x--)
{
if (points[x][y] > 0)
{
if (x < width - 1)
{
distances[x][y][1] = distances[x + 1][y][1] > 0 ? distances[x + 1][y][1] + 1 : 1;
}
else
{
distances[x][y][1] = 1;
}
}
}
}
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (points[x][y] > 0)
{
if (y > 0)
{
distances[x][y][2] = distances[x][y - 1][2] > 0 ? distances[x][y - 1][2] + 1 : 1;
}
else
{
distances[x][y][2] = 1;
}
}
}
for (int y = height - 1; y >= 0; y--)
{
if (points[x][y] > 0)
{
if (y < height - 1)
{
distances[x][y][3] = distances[x][y + 1][3] > 0 ? distances[x][y + 1][3] + 1 : 1;
}
else
{
distances[x][y][3] = 1;
}
}
}
}
// finding the minimum of four distances
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (points[x][y] > 0)
{
distances[x][y][4] = min(distances[x][y][0], distances[x][y][1], distances[x][y][2], distances[x][y][3]);
if (distances[x][y][4] == 1)
add_point_to_edges_list(x, y);
}
}
}
}
void print_edges_and_points(int point_x, int point_y,
int min_dist_edge_x, int min_dist_edge_y,
int distances[80][80][5])
{
for (size_t y = 0; y < 80; y++) {
for (size_t x = 0; x < 80; x++) {
if ( x == min_dist_edge_x
&& y == min_dist_edge_y) {
printf("E");
} else if (distances[x][y][4] == 1) {
printf(".");
} else if ( x == point_x
&& y == point_y) {
printf("P");
} else {
printf(" ");
}
}
printf("\n");
}
}
static inline void get_boundaries(int x, int y, int distances[80][80][5],
int *boundary_start_x, int *boundary_finish_x,
int *boundary_start_y, int *boundary_finish_y)
{
*boundary_start_x = x - distances[x][y][4];
*boundary_start_y = y - distances[x][y][4];
*boundary_finish_x = x + distances[x][y][4];
*boundary_finish_y = y + distances[x][y][4];
if (*boundary_start_x < 0) *boundary_start_x = 0;
if (*boundary_start_y < 0) *boundary_start_y = 0;
if (*boundary_finish_x > 80) *boundary_finish_x = 80;
if (*boundary_finish_y > 80) *boundary_finish_y = 80;
}
float get_min_dist_to_edge(int x, int y, int distances[80][80][5],
int *edge_x, int *edge_y)
{
uint32_t min_sq_dist = INT_MAX;
int boundary_start_x; int boundary_finish_x;
int boundary_start_y; int boundary_finish_y;
get_boundaries(x, y, distances,
&boundary_start_x, &boundary_finish_x,
&boundary_start_y, &boundary_finish_y);
if (!LIST_EMPTY(&edges_list_head)) {
struct point_entry_t *entry = NULL;
LIST_FOREACH(entry, &edges_list_head, entries) {
if ( entry->y > boundary_finish_y
|| entry->x < boundary_start_x
|| entry->x > boundary_finish_x) {
continue;
} else if (entry->y < boundary_start_y) {
return sqrt(min_sq_dist);
}
int sq_dist = pow(abs(x - entry->x), 2) +
pow(abs(y - entry->y), 2);
if (sq_dist < min_sq_dist) {
*edge_x = entry->x;
*edge_y = entry->y;
min_sq_dist = sq_dist;
}
}
}
return -1;
}
int main(int nargs, char *argv[])
{
if (nargs != 3) {
printf("\tusage: %s <x> <y>\n", argv[0]);
return 0;
}
unsigned char (*points)[80] = (unsigned char (*)[80])ameba_bin;
int distances[80][80][5] = {0,}; // 0 left 1 right 2 bottom 3 top 4 min
int x = atoi(argv[1]);
int y = atoi(argv[2]);
int min_dist_edge_x = 0;
int min_dist_edge_y = 0;
calc_distances(points, distances);
float min_dist_edge = 0;
if ((min_dist_edge = get_min_dist_to_edge(x, y, distances, &min_dist_edge_x,
&min_dist_edge_y)) > 0) {
print_edges_and_points(x, y, min_dist_edge_x, min_dist_edge_y, distances);
printf("ortho distances for P (%d, %d): < %d, > %d, ^ %d, v %d\n", x, y,
distances[x][y][0], distances[x][y][1],
distances[x][y][2], distances[x][y][3]);
printf("min distance from P (%d, %d) to nearest edge point E (%d, %d) = %.02f\n", x, y,
min_dist_edge_x, min_dist_edge_y, min_dist_edge);
}
clear_list();
return 0;
}
Here is an output example:
$ gcc main.c -lm && ./a.out 35 40
.....
.... .....
.. ..
.. ..
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
E .
........ . .
. ... . .
.. ..... .
. .
. .
. .
. P .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
. .
.. .
. .
.. .
... .
... .
........... .
.... .
.. .
... .
... ..
.... ...
......
ortho distances for P (35, 40): < 31, > 37, ^ 28, v 24
min distance from P (35, 40) to nearest edge point E (27, 33) = 10.63
ameba.h was created using xxd -i over the output of a web-based tool that converts images to an ASCII table.

This problem is called "Euclidean Distance Transform". It can be solved exactly in O(NM) time. Here you can find a nice paper discussing the algorithm.
http://fab.cba.mit.edu/classes/S62.12/docs/Meijster_distance.pdf
It works also for other norms like Manhattan or Chessboard distance.

Related

Game of Life problem with board update function in C

I need help with my Game of Life implementation in C. Other posts on Stackoverflow lead me to believe that my problem was to do with dangling pointers, but after modifying my program to use a global 2D array for the game grid instead of passing it to functions which return new 2D arrays, I realized that it was a problem with my update function.
I have tried hard-coding a number of simple patterns, including gliders and oscillators, and the grid doesn't update correctly. The patterns do update the same way every time the program is run, so I don't think it's a problem of uninitialized memory causing problems. I also know that there are no cells which contain values greater than 1. Therefore, the problem must lie in my mechanisms for updating the grid.
Can someone help me find the problem? I can't find anything wrong with my code and I believe I have programmed the rules correctly.
Here are my neighbors and update functions, along with the relevant variable and constant declarations.
#define MAX_Y 10 /* height */
#define MAX_X 30 /* width */
int grid[MAX_Y][MAX_X];
int neighbors(int x, int y) {
int dx, dy, dstx, dsty;
int n = 0;
for (dy = -1; dy <= 1; ++dy) {
for (dx = -1; dx <= 1; ++dx) {
dsty = y + dy;
dstx = x + dx;
if (dsty >= 0 && dsty < MAX_Y && dstx >= 0 && dstx < MAX_X)
n += !!grid[dsty][dstx]; /* use !! so that non-zero values eval to 1 */
}
}
/* (n > 0) ? printf("Point (%d,%d) has %d neighbors!\n", x, y, n) : 0; */
return n;
}
void update(void) {
int new[MAX_Y][MAX_X];
memset(new, 0, sizeof(int) * MAX_Y * MAX_X);
int i, j, n;
for (i = 0; i < MAX_Y; ++i) {
for (j = 0; j < MAX_X; ++j) {
n = neighbors(i, j);
/* alive, 2 or 3 neighbors -> alive!
* dead, 3 neighbors -> alive!
* anything else -> dead :(
*/
if (grid[i][j] && (n == 2 || n == 3))
new[i][j] = 1;
else if (!grid[i][j] && n == 3)
new[i][j] = 1;
else
new[i][j] = 0;
}
}
memcpy(grid, new, sizeof grid);
}
In your neighbors function, you need to think carefully about the loop iteration where dx and dy are both zero. Conway's Game of Life does not consider a cell to be neighbor of itself, so you need to avoid counting it.
You're also confusing yourself by using the letters i and j. You're allowing j to go all the way up to MAX_X, but then you are using j as the y coordinate when you call neighbors, so that will cause overflows and incorrect calculations. (Starting with the easier case of a 10x10 grid would sometimes save you from bugs like this.)
You should adjust the neighbors() function to omit the cell itself.
Here is a modified version:
#define MAX_Y 10 /* height */
#define MAX_X 30 /* width */
unsigned char grid[MAX_Y][MAX_X];
int neighbors(int x, int y) {
int n = -!!grid[y][x];
for (int dy = -1; dy <= 1; ++dy) {
for (int dx = -1; dx <= 1; ++dx) {
int dsty = y + dy;
int dstx = x + dx;
if (dsty >= 0 && dsty < MAX_Y && dstx >= 0 && dstx < MAX_X && grid[dsty][dstx])
n++;
}
}
return n;
}
void update(void) {
int new[MAX_Y][MAX_X] = { 0 };
for (int y = 0; y < MAX_Y; ++y) {
for (int x = 0; x < MAX_X; ++x) {
int n = neighbors(y, x);
/* alive, 2 or 3 neighbors -> alive!
* dead, 3 neighbors -> alive!
* anything else -> dead :(
*/
new[y][x] = (grid[y][x] && n == 2) || n == 3;
}
}
memcpy(grid, new, sizeof grid);
}
The neighbors() function can be simplified with fewer tests:
int neighbors(int x, int y) {
int n = -(grid[y][x] != 0);
int x1 = x - (x > 0);
int x2 = x + (x < MAX_X - 1);
int y1 = y - (y > 0);
int y2 = y + (y < MAX_Y - 1);
for (y = y1; y <= y2; y++) {
for (x = x1; x <= x2; x++) {
n += grid[y][x] != 0;
}
}
return n;
}

Finding distance in a matrix in C

I have a matrix of numbers and want to find the distance of each item from its farthest non-zero neighbour (in four directions). I came up with this idea
#include <stdlib.h>
#include <stdio.h>
int min(int a, int b, int c, int d)
{
int e = a < b ? a : b;
int f = c < d ? c : d;
int r = e < f ? e : f;
return r;
}
int main()
{
int width = 50;
int height = 50;
int points[width][height];
int distances[width][height][5]; // 0 left 1 right 2 bottom 3 top 4 min
// adding some random values, zero and non-zero
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
points[x][y] = rand() % 100;
}
}
// scanning in four direction to check if the previous neighbour exists
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (points[x][y] > 0)
{
distances[x][y][0] = distances[x - 1][y][0] > 0 ? distances[x - 1][y][0] + 1 : 1;
}
}
for (int x = width - 1; x >= 0; x--)
{
if (points[x][y] > 0)
{
distances[x][y][1] = distances[x + 1][y][1] > 0 ? distances[x + 1][y][1] + 1 : 1;
}
}
}
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (points[x][y] > 0)
{
distances[x][y][2] = distances[x][y - 1][2] > 0 ? distances[x][y - 1][2] + 1 : 1;
}
}
for (int y = height - 1; y >= 0; y--)
{
if (points[x][y] > 0)
{
distances[x][y][3] = distances[x][y + 1][3] > 0 ? distances[x][y + 1][3] + 1 : 1;
}
}
}
// finding the minimum of four distances
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (points[x][y] > 0)
{
distances[x][y][4] = min(distances[x][y][0], distances[x][y][1], distances[x][y][2], distances[x][y][3]);
printf("%d %d %d %d %d %d %d \n", x, y, distances[x][y][0], distances[x][y][1], distances[x][y][2], distances[x][y][3], distances[x][y][4]);
}
}
}
return 0;
}
but it doesn't work as expected. Most likely, I have made a stupid mistake and have a blind eye for that to see.
At line 34:
if (points[x][y] > 0)
{
distances[x][y][0] = distances[x - 1][y][0] > 0 ? distances[x - 1][y][0] + 1 : 1;
}
when x is zero, you are referencing up to 250 (50 * 5) words before the address of distances, which is an invalid thing to do.

Blurring a .BMP with box BLUR in C

To resume. the code I ve written below doesn t get me a blur image. But a black IMAGE instead ( except for the pixel edges).
For testing i ve just tried the interior PIXELS, without edges RGBTRIPLE pixels because I wanted to see if I was making well so far.
Could anybody tell me whats wrong with my code, please?
is muy BUFFER RGB newImage correct done?? if image[height][width].rgbtRed it means that newImage[height][width].rgbtRed will exist?? thanks in advance
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
//create a buffer to allocate new pixels.
RGBTRIPLE newImage[height][width];
// iterate through each row
for (int i = 0 ; i < height ; i++)
{
// iterate through each column passing through every RGBTRIPLE
for ( int j = 0; j < width ; j++)
{
int redSum = 0;
int greenSum = 0;
int blueSum = 0;
//counter for pixels being add in every avg.
//int count = 0;
// take the average amount of RGB of every pixel in a range of 3x3 pixels
// avg for left top corner
/*if ( r == 0 && l == 0) {
}
// avg left bottom corner
else if ( r == height - 1 && l == 0 ){
}
// avg right top corner
else if ( r == 0 && l == width - 1){
}
// avg left bottom corner
else if ( r == height - 1 && l == width - 1){
}
// avg top side
else if ( r == 0 && l > 0 && l != width - 1) {
}
// avg right side
else if ( l == width - 1 && r > 0 && r != height - 1) {
}
// avg bottom side
else if ( r == height - 1 && l > 0 && l != width - 1) {
}
// avg left side
else if ( l == 0 && r > 0 && r != height - 1){
}*/
for ( int iy = -1 ; iy >= 1 ; iy++)
{
for ( int jx = -1 ; jx >= 1 ; jx++)
{
redSum = redSum + image[i + iy][j + jx].rgbtRed;
greenSum = greenSum + image[i + iy][j + jx].rgbtGreen;
blueSum = blueSum + image[i + iy][j + jx].rgbtBlue;
//count++;
}
}
int avgRed = redSum / 9;
int avgGreen = greenSum / 9;
int avgBlue = blueSum / 9;
newImage[i][j].rgbtRed = avgRed;
newImage[i][j].rgbtGreen = avgGreen;
newImage[i][j].rgbtBlue = avgBlue;
}
}
for ( int y = 1 ; y < height - 1; y++)
{
for ( int x = 1; x < width - 1; x++)
{
image[y][x].rgbtRed = newImage[y][x].rgbtRed;
image[y][x].rgbtGreen = newImage[y][x].rgbtGreen;
image[y][x].rgbtBlue = newImage[y][x].rgbtBlue;
}
}
return;
}
A major mistake not already mentioned in a comment is that redSum, greenSum and blueSum are initialized to 0 only once, while they must be set to zero before each pixel is processed, so better move the definitions right before the for ( int py = 0 ; py >= 2 ; py++) loop.
It's hardly believable how the many eyes (including mine) who looked at the code could overlook the main, simple error - the inner loops (in their original as well as in the edited version) are never executed:
for ( int iy = -1 ; iy >= 1 ; iy++)
{
for ( int jx = -1 ; jx >= 1 ; jx++)
Of course, the iy >= 1 condition is false from the start; you surely meant iy <= 1 and jx <= 1.

Shuffling or Randomizing an Array in C

I'm just getting started on a project and am having some trouble. The idea is to make an 8x8 array that randomly generates an array with ten blocks, one random starting point, and the top right corner being an 'exit'. Then the program will find the quickest path and the output will be the randomly generated array as well as the directions to the exit (i.e., Up, Up, Right, Right, Up, Left)
Obviously there are many steps that I have to take afterwards to get the array to do what I want, but I was wondering if anyone could help me figure out how to set one up so it looks something along the lines of (E=exit, X=block, Z=starting point)
0 0 0 0 X 0 0 E
0 0 X 0 0 0 0 0
0 0 0 0 0 0 X 0
0 X 0 0 X 0 0 0
0 0 0 0 0 0 0 X
X 0 0 X 0 Z 0 0
0 0 0 0 0 0 0 0
0 0 X 0 0 0 X 0
So far I have this program. It fortunately places the ten random -1s as well as the random starting point (I have it as '7' for now, but I will change it eventually), but I can't seem to guarantee that the upper right corner is not going to be one of the -1's that I need and then replaced by the 99 leaving the array with only nine -1's instead of the required ten.
#include <stdio.h>
#include <stdlib.h>
#define ROW 8
#define COLUMN 8
#define NUM 10
#define start 1
int main () {
int x, y;
int array[ROW][COLUMN];
for (x = 0; x < ROW; x++) {
for (y = 0; y < COLUMN; y++) {
array[x][y] = 0;
}
}
srand (time (NULL));
for (x = 0; x < NUM; x++) {
int t = rand () % ROW;
y = rand () % COLUMN;
if (array[t][y] != -1) {
array[t][y] = -1;
} else {
x--;
}
}
for (x = 0; x < start; x++)
{
int t = rand () % ROW;
y = rand () % COLUMN;
if (array[t][y] != 7) {
array[t][y] = 7;
} else { x--;
}
}
for (x = 0; x < ROW; x++) {
for (y = 0; y < COLUMN; y++) {
array[0][7] = 99;
printf ("%d ", array[x][y]);
}
printf ("\n");
}
return 0; }
any help would be greatly appreciated-I am a terrible programmer.
If I understand your question, then I would begin by initializing the array contents to zero (instead of -1) and I would also define the number of elements I want to randomly set to -1.
#include <stdio.h>
#include <stdlib.h>
#define ROW 8
#define COLUMN 8
#define NUM 10
int main (int argc, char *argv[]) {
int x, y;
int array[ROW][COLUMN];
for (x = 0; x < ROW; x++) {
for (y = 0; y < COLUMN; y++) {
array[x][y] = 0;
}
}
Then we can set NUM elements randomly to -1 like
srand (time (NULL));
for (x = 0; x < NUM; x++) {
int t = rand () % ROW;
y = rand () % COLUMN;
if (array[t][y] != -1) {
array[t][y] = -1;
} else {
x--;
}
}
Finally, we can print the results with something like
for (x = 0; x < ROW; x++) {
for (y = 0; y < COLUMN; y++) {
printf ("%d ", array[x][y]);
}
printf ("\n");
}
return 0;
I would have a 3-D array and have the first two dimensions randomized from 0-7 and the third dimension be randomized 0 and 1. 0 being a block and 1 being starting pointing. Having a for-loop for how many you want of each. Then fill the rest of the array with "0"'s

Finding all adjacent elements in a 2D array

I am working on a project where at one point I am stuck.
My question is for example I have the following 2D array containing 3 different integers.
2 2 2 2 1
1 2 2 2 1
3 3 2 3 2
3 1 3 3 1
1 1 2 3 1
1 3 1 3 3
What I want is to find the longest adjacent elements chain of array of any number contained in the array.
Like in the above array the longest chain is of digit 2.
2 2 2 2
2 2 2
2
Can anyone just guide me as to what I have to do to achieve this goal?
Easier to draw than to explain...
2 2 2 2 1 => A A A A B => (A: 4, B: 1)
1 2 2 2 1 => C A A A B => (A: 3 + 4, B: 1 + 1, C: 1)
3 3 2 3 2 => D D A E F => (A: 1 + 7, B: 2, C: 1, D: 2, E: 1, F: 1)
3 1 3 3 1 => D G E E G => (A: 8, B: 2, C: 1, D: 2 + 1, E: 2 + 1, F: 1, G: 1)
1 1 2 3 1 => ...
1 3 1 3 3 => ...
update:
And now, with some real code:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define ROWS 6
#define COLS 5
unsigned char eles[ROWS][COLS] = { { 2, 2, 2, 2, 1 },
{ 1, 2, 2, 2, 1 },
{ 3, 3, 2, 3, 2 },
{ 3, 1, 3, 3, 1 },
{ 1, 1, 2, 3, 1 },
{ 1, 3, 1, 3, 3 } };
struct zone {
int acu;
int row, col;
int refs;
};
typedef struct zone zone;
zone *
new_zone(int row, int col) {
zone *z = (zone *)malloc(sizeof(zone));
z->col = col;
z->row = row;
z->refs = 1;
z->acu = 0;
}
void croak (const char *str) {
fprintf(stderr, "error: %s\n", str);
exit(1);
}
void
free_zone(zone *z) {
if (z->refs != 0) croak("free_zone: reference count is not cero");
free(z);
}
zone *
ref_zone(zone *z) {
z->refs++;
return z;
}
void
unref_zone(zone *z) {
z->refs--;
if (!z->refs) free_zone(z);
}
int
main() {
zone *last[COLS];
zone *current[COLS];
zone *best = new_zone(0, 0);
int i, j;
memset(last, 0, sizeof(last));
for (j = 0; j < ROWS; j++) {
for (i = 0; i < COLS; i++) {
unsigned int ele = eles[j][i];
zone *z;
/* printf("analyzing ele: %d at row %d, col: %d\n", ele, j, i); */
if (i && (ele == eles[j][i-1])) {
/* printf(" equal to left element\n"); */
z = ref_zone(current[i-1]);
if (j && (ele == eles[j-1][i])) {
zone *z1 = last[i];
/* printf(" equal to upper element\n"); */
if (z != z1) {
int k;
/* printf(" collapsing zone %p\n", z1); */
z->acu += z1->acu;
for (k = 0; k < COLS; k++) {
if (last[k] == z1) {
last[k] = ref_zone(z);
unref_zone(z1);
}
}
for (k = 0; k < i; k++) {
if (current[k] == z1) {
current[k] = ref_zone(z);
unref_zone(z1);
}
}
}
}
}
else if (j && (ele == eles[j-1][i])) {
/* printf(" equal to upper element\n"); */
z = ref_zone(last[i]);
}
else {
/* printf(" new element\n"); */
z = new_zone(j, i);
}
z->acu++;
current[i] = z;
/* printf(" element zone: %p\n", z); */
}
for (i = 0; i < COLS; i++) {
if (j) unref_zone(last[i]);
last[i] = current[i];
if (best->acu < current[i]->acu) {
unref_zone(best);
best = ref_zone(current[i]);
/* printf("best zone changed to %p at row; %d, col: %d, acu: %d\n", best, best->row, best->col, best->acu); */
}
}
}
printf("best zone is at row: %d, col: %d, ele: %d, size: %d\n", best->row, best->col, eles[best->row][best->col], best->acu);
}
Suppose your matrix is a graph, and the elements are vertices. Two vertices are connected if they are adjacent and have the same value. If you perform any search in that graph, be it Breadth-First Search or Depth-First Search, you'll get exactly what you want. HTH
You could treat this like a picture in a paint application. Perform a flood-fill on each element in your 2D array (unless its filled already by something else) and keep track how many pixels you filled in each step.
If your array is declared like
int elements[5][5];
Then introduce a second array which tells whether you filled an element already (if you like, use a different type like bool if thats's okay in your C program):
int pixelFilled[5][5];
memset( pixelFilled, 0, sizeof( pixelFilled ) );
Next, write a recursive function which performs a flood fill and returns the numbers of elements which were filled (I'm writing this from the top of my head, no guarantee whatsoever that this function works as it is):
int floodFill( int x, int y ) {
int filledPixels = 0;
if ( !pixelFilled[x][y] ) {
++filledPixels;
pixelFilled[x][y] = 1;
} else {
return 0;
}
if ( x < 4 && elements[x+1][y] == elements[x][y] )
filledPixels += floodFill( x + 1, y );
if ( x > 0 && elements[x-1][y] == elements[x][y] )
filledPixels += floodFill( x - 1, y );
if ( y < 4 && elements[x][y+1] == elements[x][y] )
filledPixels += floodFill( x, y + 1 );
if ( y > 0 && elements[x][y-1] == elements[x][y] )
filledPixels += floodFill( x, y - 1 );
return filledPixels;
}
Finally, iterate over your array and try to fill it completely. Keep track of the largest filled array:
int thisArea = 0;
int largestArea = 0;
int x, y;
for ( y = 0; y < 5; ++y ) {
for ( x = 0; x < 5; ++x ) {
thisArea = floodFill( x, y );
if (thisArea > largestArea ) {
largestArea = thisArea;
}
}
}
Now, largestArea should contain the size of the longest chain of adjacent elements.
define another 2d array of the same size, initialize all cells to 0
set maxval to 0
if helper array is full of 1's go to 5, otherwise find a cell with 0 and do:
3.1 change value of the cell to 1
3.2 set a counter to 1
3.3 check all adjacent cells, if they're 0 in the helper array and the same value as current cell in the input array then counter++ and go to 2.1 with new coordinates.
maxval = max(maxval,counter), go to 3
return maxval
steps 3.1-3.3 should be implemented as a recursive function which takes coordinate and both arrays as arguments and returns 1+the sum of the returned values from the recursive calls.
I love this kind of problems :-) so here it is my answer.
As said by Frerich Raabe, this can be solved with a floodFill function. For example, opencv library would provide such a function off the shelf.
Please forgive me if in the following code you'll find traces of C++, in case they should be simple to be replaced.
typedef struct Point {
int x;
int y;
} Point;
int areaOfBiggestContiguousRegion(int* mat,int nRows, int nCols) {
int maxArea = 0;
int currValue, queueSize, queueIndex;
int* aux;
Point queue[1000]; //Stores the points I need to label
Point newPoint, currentPoint;
int x,y,x2,y2;
//Code: allocate support array aux of same size of mat
//Code: fill aux of zeros
for (y = 0; y < nRows; y++)
for (x = 0; x < nCols; x++)
if (aux[y * nCols + x] == 0) {//I find a pixel not yet labeled, my seed for the next flood fill
queueIndex = 0; //Contains the index to the next element in the queue
queueSize = 0;
currValue = mat[y * nCols + x]; //The "color" of the current spot
aux[y * nCols + x] = 1;
newPoint.x = x;
newPoint.y = y;
queue[queueSize] = newPoint;
queueSize++;
while(queueIndex != queueSize) {
currPoint = queue[queueIndex];
queueIndex++;
//Look left, right, up, down
x2 = currPoint.x - 1;
y2 = currPoint.y;
//Some copy & paste, sorry I have been too long on C++ to remember correctly about C functions
if (x2 >= 0 && aux[y2 * nCols + x2] == 0 && mat[y2 * nCols + x2] == currValue) {
aux[y2 * nCols + x2] = 1;
newPoint.x = x2;
newPoint.y = y2;
queue[queueSize] = newPoint;
queueSize++;
}
x2 = currPoint.x + 1;
y2 = currPoint.y;
//Some copy & paste, sorry I have been too long on C++ to remember correctly about C functions
if (x2 < nCols && aux[y2 * nCols + x2] == 0 && mat[y2 * nCols + x2] == currValue) {
aux[y2 * nCols + x2] = 1;
newPoint.x = x2;
newPoint.y = y2;
queue[queueSize] = newPoint;
queueSize++;
}
x2 = currPoint.x;
y2 = currPoint.y - 1;
//Some copy & paste, sorry I have been too long on C++ to remember correctly about C functions
if (y2 >= 0 && aux[y2 * nCols + x2] == 0 && mat[y2 * nCols + x2] == currValue) {
aux[y2 * nCols + x2] = 1;
newPoint.x = x2;
newPoint.y = y2;
queue[queueSize] = newPoint;
queueSize++;
}
x2 = currPoint.x;
y2 = currPoint.y + 1;
//Some copy & paste, sorry I have been too long on C++ to remember correctly about C functions
if (y2 < nRows && aux[y2 * nCols + x2] == 0 && mat[y2 * nCols + x2] == currValue) {
aux[y2 * nCols + x2] = 1;
newPoint.x = x2;
newPoint.y = y2;
queue[queueSize] = newPoint;
queueSize++;
}
} //while
if (queueSize > maxArea)
maxArea = queueSize; //If necessary we could store other details like currentValue
}//if (aux...
return maxArea;
}
Note: In C++ using std containers and a constructor for Point it becomes much more compact

Resources