简体   繁体   English

洪水填充算法迷宫

[英]Flood fill algorithm maze

I ma trying to make my program read a maze like this:我试图让我的程序阅读这样的迷宫:

    #.#######
    #.......#
    ####.####
    #....#..#
    #.####.##

and print out the reachable zones and non-reachable zones in the maze, which should look like this:并打印出迷宫中的可达区域和非可达区域,如下所示:

    #+#######
    #+++++++#
    ####+####
    #++++#--#
    #+####-##

Walls are represented with "#", and passable cells are represented with ".".墙用“#”表示,可通过的单元用“.”表示。

The "+" that replaces the cells means that those cells are reachable from the top entry point of the maze.替换单元格的“+”表示可以从迷宫的顶部入口点到达这些单元格。 The "-" symbol are the cells that can't be reached if you enter the top of the maze. “-”符号是进入迷宫顶部无法到达的单元格。

For example, in the above maze, all the cells are reachable except for the cells in the bottom right-hand corner.例如,在上面的迷宫中,除了右下角的单元格之外,所有单元格都是可到达的。 This is because those cells cannot be reached from the entry point at the top of the maze.这是因为无法从迷宫顶部的入口点到达这些细胞。

I am trying to use some recursion to flood fill the maze, and determine the reachable zones, but I am having trouble with that.我正在尝试使用一些递归来填充迷宫,并确定可到达的区域,但我遇到了麻烦。

This is what I have so far:这是我到目前为止:

    int
    flood_fill(m_t * maze, int row, int col) {

        int direction;

        direction = flood_fill(maze, row+1, col); /* down */
        if (!direction) {
            direction = flood_fill(maze, row, col+1); /* right */
        }

        if (!direction) {
            direction = flood_fill(maze, row-1, col); /* up */
        }

        if (!direction) {
            direction = flood_fill(maze, row, col-1); /* left */
        }

        if (direction) {
            maze->M[row][col].type = path;
        }

        return direction;
    }

I know that my flood_fill function is not doing the right thing, and I'm having difficulty getting it right.我知道我的 flood_fill 函数没有做正确的事情,而且我很难做到正确。 Can anyone help me please me get my flood filling part of the code right, so I can call the function elsewhere in the code and determine which cells can be reached.任何人都可以帮助我,请我正确填写代码的洪水填充部分,以便我可以在代码的其他地方调用该函数并确定可以访问哪些单元格。

try this尝试这个

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

#define MAX_HEIGHT 100
#define MAX_WIDTH  100
#define wall '#'
#define path_cell '.'

typedef struct {
    char type;
    int reachable;
    int visited;
} mazecells_t;

typedef struct {
    int height;
    int width;
    mazecells_t M[MAX_HEIGHT][MAX_WIDTH];
} m_t;

void readmaze(m_t *maze);
void print(m_t *m);
void print_reachable(m_t *m);

int main(void) {
    m_t MAZE;

    readmaze(&MAZE);
    print(&MAZE);
    puts("");
    print_reachable(&MAZE);

    return 0;
}

void readmaze(m_t *maze) {
    int row=0, col=0;
    char ch;
    FILE *fp = stdin;//fopen("map.txt", "r");
    while(EOF != fscanf(fp, "%c", &ch)){
        if(ch == wall || ch == path_cell){
            maze->M[row][col].type = ch;
            maze->M[row][col].reachable = 0;
            maze->M[row][col].visited = 0;
            ++col;
        } else if(ch == '\n'){
            maze->width = col;
            col = 0;
            ++row;
        }
    }
    if(col != 0)
        ++row;
    //fclose(fp);
    maze->height = row;
}

void print(m_t *m){
    for(int r = 0; r < m->height; ++r){
        for(int c = 0; c < m->width; ++c){
            putchar(m->M[r][c].type);
        }
        putchar('\n');
    }
}

typedef enum dir {
    UP, RIGHT, DOWN, LEFT, FORWARD
} DIR;

typedef struct pos {
    int r, c;
    DIR dir;
} Pos;

typedef struct node {
    Pos pos;
    struct node *next;
} Node;

typedef struct queque {
    Node *head, *tail;
} Queque;

Queque *new_queque(void){
    Queque *q = malloc(sizeof(*q));
    q->head = q->tail = NULL;
    return q;
}

void enque(Queque *q, Pos pos){
    Node *node = malloc(sizeof(*node));
    node->pos = pos;
    node->next = NULL;
    if(q->head == NULL){
        q->head = q->tail = node;
    } else {
        q->tail = q->tail->next = node;
    }
}

Pos deque(Queque *q){
    Pos pos = q->head->pos;
    Node *temp = q->head;
    if((q->head = q->head->next)==NULL)
        q->tail = NULL;
    free(temp);
    return pos;
}

bool isEmpty_que(Queque *q){
    return q->head == NULL;
}

Pos dxdy(DIR curr, DIR next){
    Pos d = { 0, 0, 0};
    switch(curr){
    case UP:
        switch(next){
        case LEFT:
            d.c -= 1;
            break;
        case FORWARD:
            d.r -= 1;
            break;
        case RIGHT:
            d.c += 1;
            break;
        }
        break;
    case RIGHT:
        switch(next){
        case LEFT:
            d.r -= 1;
            break;
        case FORWARD:
            d.c += 1;
            break;
        case RIGHT:
            d.r += 1;
            break;
        }
        break;
    case DOWN:
        switch(next){
        case LEFT:
            d.c += 1;
            break;
        case FORWARD:
            d.r += 1;
            break;
        case RIGHT:
            d.c -= 1;
            break;
        }
        break;
    case LEFT:
        switch(next){
        case LEFT:
            d.r += 1;
            break;
        case FORWARD:
            d.c -= 1;
            break;
        case RIGHT:
            d.r -= 1;
            break;
        }
        break;
    }
    return d;
}

Pos next_pos(Pos pos, DIR dir){
    Pos dxy = dxdy(pos.dir, dir);
    switch(dir){
    case RIGHT:
        pos.dir = (pos.dir + 1) % 4;
        break;
    case LEFT:
        if((pos.dir = (pos.dir - 1)) < 0)
            pos.dir += 4;
        break;
    case FORWARD:
        break;
    }
    pos.r += dxy.r;
    pos.c += dxy.c;
    return pos;
}
static inline bool isValid(m_t *m, Pos pos){
    if(pos.r < 0 || pos.r >= m->height || pos.c < 0 || pos.c >= m->width || m->M[pos.r][pos.c].type == wall)
        return false;
    return true;
}
static inline bool isValidAndUnvisit(m_t *m, Pos pos){
    return isValid(m, pos) && !m->M[pos.r][pos.c].reachable;
}

void print_reachable(m_t *m){
    int i;
    for(i = 0; i < m->width; ++i)
        if(m->M[0][i].type == path_cell)
            break;
    Pos pos = { 0, i, DOWN};
    Queque *q = new_queque();
    enque(q, pos);
    while(!isEmpty_que(q)){
        pos = deque(q);
        if(!m->M[pos.r][pos.c].reachable){
            m->M[pos.r][pos.c].reachable = 1;

            Pos next = next_pos(pos, LEFT);
            if(isValidAndUnvisit(m, next))
                enque(q, next);
             next = next_pos(pos, FORWARD);
            if(isValidAndUnvisit(m, next))
                enque(q, next);
             next = next_pos(pos, RIGHT);
            if(isValidAndUnvisit(m, next))
                enque(q, next);
        }
    }
    free(q);
    for(int r = 0; r < m->height; ++r){
        for(int c = 0; c < m->width; ++c){
            if(m->M[r][c].reachable)
                putchar('+');
            else if(m->M[r][c].type == path_cell)
                putchar('-');
            else
                putchar(m->M[r][c].type);
        }
        putchar('\n');
    }
}

You need to check if the current position is a path, a visited path or a wall.您需要检查当前位置是路径、访问路径还是墙壁。

If it is a path, change it to reachable and visited and then call flood_fill in each direction.如果是路径,则将其更改为可到达和已访问,然后在每个方向上调用flood_fill

If it is a wall or a visited path then return without further calls to flood_fill .如果它是一堵墙或访问过的路径,则无需进一步调用flood_fill即可flood_fill

After flood_fill has returned, any position that is an unvisited path is unreachable.flood_fill返回后,任何未访问路径的位置都无法到达。

Edit:编辑:

The code for flood_fill could look something like this: flood_fill 的代码可能如下所示:

void
flood_fill(m_t * maze, int row, int col) {

    if (row < 0 || col < 0 || row >= MAX_HEIGHT || col >= MAX_WIDTH) {
        /* Out of bounds */
        return;
    }
    if (maze->M[row][col].type != path_cell) {
        /* Not a path cell */
        return;
    }
    if (maze->M[row][col].visited) {
        /* We have already processed this cell */
        return;
    }

    /* We have now established that the cell is a reachable path cell */
    maze->M[row][col].visited = 1;
    maze->M[row][col].reachable = 1;
    maze->M[row][col].type = '+';  /* Not sure if you want this line or if you exchange the symbol in the presentation */

    /* Check the surrounding cells */
    flood_fill(maze, row+1, col); /* down */
    flood_fill(maze, row, col+1); /* right */
    flood_fill(maze, row-1, col); /* up */
    flood_fill(maze, row, col-1); /* left */
}

First, you can find a very nice explanation for the maze recursion here .首先,您可以在此处找到对迷宫递归的非常好的解释。

In your case the function should look like this:在您的情况下,该函数应如下所示:

void
flood_fill(m_t * maze, int row, int col)
{
    // If row,col is outside maze
    if ( row < 0 || row >= maze->height || col < 0 || col >= maze->width) return;
    // If row,col is not open
    if (maze->M[row][col].type != '.') return;
    // Mark row,col as part of path.
    maze->M[row][col].type = '+';
    // Go Up
    flood_fill(maze, row, col - 1);
    // Go Right
    flood_fill(maze, row + 1, col);
    // Go Down
    flood_fill(maze, row, col + 1);
    // Go Left
    flood_fill(maze, row - 1, col);

    return;
}

Result after calling this function with your example matrix will be:使用示例矩阵调用此函数后的结果将是:

#+#######
#+++++++#
####+####
#++++#..#
#+####.##

After running this you can just go over the matrix again and mark every .运行此程序后,您可以再次查看矩阵并标记每个. cell with - and you're done.单元格-你就完成了。

Note: You don't need to change your matrix before calling this function.注意:在调用此函数之前,您不需要更改矩阵。 You only need to call this function with the index of the beginning of the maze when you find it.你只需要在找到迷宫开始的索引时调用这个函数。 In your example it will be flood_fill(maze,0,1) .在您的示例中,它将是flood_fill(maze,0,1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM