Petetunze
Petetunze

Reputation: 35

Recursive Flood Fill in C with ASCII: How do I get the letters to spread out instead of one by one?

This is a continuation of this question: Recursive Flood Fill algorithm in C using ASCII art and incrementing characters to fill the space

In the previous question, I asked about how to get the Flood Fill algorithm to properly. The algorithm works and fills the space properly but now I have a question regarding on the visuals and how letters are printed onto the room.

Below is a sample of the program with a more complicated room pattern.

#include <stdio.h>
#include <stdlib.h>

typedef struct room{

    char **array;
    int rows;
    int cols;
} room;

void printRoom(room room);
int *findA(room room);
void floodFill(room room, int x, int y, char paint);
room buildRoom();

int main(int argc, char *argv[]){

    // Make a new room
    room newRoom = buildRoom();

    printf("Before\n");
    printRoom(newRoom);

    // Find the A
    int *a = findA(newRoom);

    // Print the A
    printf("A is at %d, %d\n", a[0], a[1]);

    // Set current position to ' '
    newRoom.array[a[0]][a[1]] = ' ';

    // Flood fill the room
    floodFill(newRoom, a[0], a[1], 'A');

    // Print the room
    printf("\nAfter\n");
    printRoom(newRoom);
    
    return 0;
}

int *findA(room room){

    int *location = malloc(2 * sizeof(int));

    for(int i = 0; i < room.rows; i++){
        for(int j = 0; j < room.cols; j++){
            if(room.array[i][j] == 'A'){
                location[0] = i;
                location[1] = j;
            }
        }
    }

    return location;
}

void floodFill(room room, int x, int y, char paint){

    /* Base cases */
    if(x < 0 || x >= room.rows || y < 0 || y >= room.cols) return;
    if(room.array[x][y] != ' ') return;

    // Paint the current position
    room.array[x][y] = paint;

    if(paint < 'Z') paint++;

    /* Recursive calls */
    floodFill(room, x, y - 1, paint);
    floodFill(room, x, y + 1, paint);
    floodFill(room, x - 1, y, paint);
    floodFill(room, x + 1, y, paint);
}

void printRoom(room room){

    for(int i = 0; i < room.rows; i++){
        for(int j = 0; j < room.cols; j++){
            printf("%c", room.array[i][j]);
        }
        printf("\n");
    }
}

room buildRoom(){

    room newRoom;
    int row = 12;
    int col = 14;

    newRoom.rows = row;
    newRoom.cols = col;

    /* Allocate memory for the array */
    newRoom.array = malloc(row * sizeof(char*));
    for(int i = 0; i < row; i++){
        newRoom.array[i] = malloc(col * sizeof(char));
    }

    char *row1 =     "**************";
    char *row2 =     "*  A         *";
    char *row3 =     "* **** ***** *";
    char *row4 =     "* *    *   * *";
    char *row5 =     "* * **** *** *";
    char *row6 =     "* * *  * *   *";
    char *row7 =     "*      * * ***";
    char *row8 =     "* **** * * * *";
    char *row9 =     "* *    * * ***";
    char *row10 =    "*** ****** * *";
    char *row11 =    "* *        * *";
    char *row12 =    "**************";

    int i;

    /* Make room.newArray[0][] = row1 */
    for(i = 0; i < col; i++){
        newRoom.array[0][i] = row1[i];
    }

    /* Make room.newArray[1][] = row2 */
    for(i = 0; i < col; i++){
        newRoom.array[1][i] = row2[i];
    }

    /* Make room.newArray[2][] = row3 */
    for(i = 0; i < col; i++){
        newRoom.array[2][i] = row3[i];
    }

    /* Make room.newArray[3][] = row4 */
    for(i = 0; i < col; i++){
        newRoom.array[3][i] = row4[i];
    }

    /* Make room.newArray[4][] = row5 */
    for(i = 0; i < col; i++){
        newRoom.array[4][i] = row5[i];
    }

    /* Make room.newArray[5][] = row6 */
    for(i = 0; i < col; i++){
        newRoom.array[5][i] = row6[i];
    }

    /* Make room.newArray[6][] = row7 */
    for(i = 0; i < col; i++){
        newRoom.array[6][i] = row7[i];
    }

    /* Make room.newArray[7][] = row8 */
    for(i = 0; i < col; i++){
        newRoom.array[7][i] = row8[i];
    }

    /* Make room.newArray[8][] = row9 */
    for(i = 0; i < col; i++){
        newRoom.array[8][i] = row9[i];
    }

    /* Make room.newArray[9][] = row10 */
    for(i = 0; i < col; i++){
        newRoom.array[9][i] = row10[i];
    }

    /* Make room.newArray[10][] = row11 */
    for(i = 0; i < col; i++){
        newRoom.array[10][i] = row11[i];
    }

    /* Make room.newArray[11][] = row12 */
    for(i = 0; i < col; i++){
        newRoom.array[11][i] = row12[i];
    }
    
    return newRoom;
}

Output

Before
**************
*  A         *
* **** ***** *
* *    *   * *
* * **** *** *
* * *  * *   *
*      * * ***
* **** * * * *
* *    * * ***
*** ****** * *
* *        * *
**************
A is at 1, 3

After
**************
*CBAZZZZZZZZZ*
*D****Z*****Z*
*E*ZZZZ*   *Z*
*F*Z**** ***Z*
*G*Z*ON* *ZZZ*
*HIJKLM* *Z***
*I****N* *Z* *
*J*RQPO* *Z***
***S******Z* *
* *TUVWXYZZ* *
**************

While the room is filled with no errors, I want the letters to print in a specific way. Below is an example of how I want it to print.

Preferred output

**************
*CBABCDEFGHIJ*
*D****E*****K*
*E*IHGF*   *L*
*F*J**** ***M*
*G*K*MN* *PON*
*HIJKLM* *Q***
*I****N* *R* *
*J*RQPO* *S***
***S******T* *
* *TUVWXWVU* *
**************

In the preferred output above, it seems that the letters spread out from the 'A'. For example, the 'A' is surrounded by Bs, the Bs are surrounded by Cs and so on. In original output, the program goes simply goes in "one" direction where a 'Z' is next to the 'A'. The original program uses DSF but I have seen that a BSF approach can be possible with the Flood Fill algorithm and it seems that BSF is might create the pattern that I need but not sure how to implement it into the program. I could be totally wrong about it so any insight or help is greatly appreciated.

Upvotes: 1

Views: 373

Answers (1)

Dialecticus
Dialecticus

Reputation: 16769

The most visually appealing way is to introduce a queue. Put the starting cell in the queue. Then follow the algorithm:

  • If there are no items in the queue then stop.
  • Take first cell from the queue.
  • Change the visual appearance of the matrix.
  • Put free (non-visited) neighboring cells at the end of the queue.
  • Repeat.

You have to change the state of the cell when you visit the cell. You can use the same matrix for this, or you can use new temporary matrix. If you use the same matrix then in the end you have to reset the visiting state of all the cells. If you use a temporary matrix then just discard it.

There are several different algorithms explained in Wikipedia article.

If you want to change visual appearance in a way that cells that are equally distant from the start are filled at the same time then your visiting flag must be more than a bool. It must be a distance from start. In that case you Change visual appearance when you run out of one generation of cells, and encouter in the queue a second generation. OR you have two queues. This could be simpler. When you pop from first queue you push to second queue. When first queue becomes empty change second queue to be the first.

Upvotes: 1

Related Questions