我有一个任务,我需要写一个递归的洪水填充算法,用递增的字符填充ASCII艺术中的空格。现在,我做了无止境的研究,并认为我理解这个算法的基本原理。然而,当我应用我所学的东西时,输出并没有产生我想要的东西。以下是该计划的大纲
*****
*DCB*
***A*
*DCB*
*****
下面是一个示例程序,因为原来的要大得多。
#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);
int main(int argc, char *argv[]){
// Make a new room
room newRoom;
// Set the rows and columns
newRoom.rows = 5;
newRoom.cols = 5;
// Allocate memory for the array
newRoom.array = malloc(newRoom.rows * sizeof(char*));
for(int i = 0; i < newRoom.rows; i++){
newRoom.array[i] = malloc(newRoom.cols * sizeof(char));
}
// Fill the first array with "*****"
for(int i = 0; i < newRoom.cols; i++){
newRoom.array[0][i] = '*';
}
// Fill the second array with "* *"
newRoom.array[1][0] = '*';
newRoom.array[1][1] = ' ';
newRoom.array[1][2] = ' ';
newRoom.array[1][3] = ' ';
newRoom.array[1][4] = '*';
// Fill the third array with "**A*"
newRoom.array[2][0] = '*';
newRoom.array[2][1] = '*';
newRoom.array[2][2] = '*';
newRoom.array[2][3] = 'A';
newRoom.array[2][4] = '*';
// Fill the fourth array with "* *"
newRoom.array[3][0] = '*';
newRoom.array[3][1] = ' ';
newRoom.array[3][2] = ' ';
newRoom.array[3][3] = ' ';
newRoom.array[3][4] = '*';
// Fill the fifth array with "*****"
for(int i = 0; i < newRoom.cols; i++){
newRoom.array[4][i] = '*';
}
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]);
// 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){
// If the current position is a wall, return
if(room.array[x][y] == '*'){
return;
}
// If the current position is already painted, return
if(room.array[x][y] == paint){
return;
}
if(x < 0 || x >= room.rows || y < 0 || y >= room.cols){
return;
}
// Paint the current position
room.array[x][y] = paint;
// Flood fill the left position
floodFill(room, x, y + 1, paint);
// Flood fill the right position
floodFill(room, x, y - 1, paint);
// Flood fill the top position
floodFill(room, x + 1, y, paint);
// Flood fill the bottom position
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");
}
}
输出
Before
*****
* *
***A*
* *
*****
A is at 2, 3
After
*****
* *
***A*
* *
*****
我认为问题的一部分是,在上面的版本中,当第一次调用洪水填充时,它会检查当前位置是否等于油漆。在这种情况下,它是,然后立即返回,什么也不做。但是,如果我更改这一行:
从
floodFill(newRoom, a[0], a[1], 'A');
到
floodFill(newRoom, a[1], a[0], 'A');
输出
*****
* *
***A*
* *
*****
A is at 2, 3
After
*****
* *
***A*
*AAA*
*****
正如你所看到的,它有点填满了下半部分,但没有填满顶部。我认为这里发生的事情是,由于A在试图上升时已经在那里,所以它退出时,当前位置已经是A。现在我不知道该怎么办,因为我一直被卡住。如果我尝试改变基本情况,我将得到无限递归调用,否则它将什么都不做。此外,我不确定floodFill函数中是否需要两个char参数(char oldPaint,char newPaint)来处理字符的递增。非常感谢您的帮助!
存在以下问题:
>
算法立即停止,因为它发现在位置 x
, y
处,绘画
字符('A')已经存在。为了解决这个问题,我会写一个包装函数(floodFillStart
),它首先用空格替换“A”,然后调用 floodFill
。
在访问矩阵之前,应检查x
和y
坐标是否超出范围。因此,if
语句应该首先出现。
缺少填充下一个字符的逻辑。
一旦字符发生变化,检查room. array[x][y]==油漆
就不够好:算法会遇到一个具有前面值的字符(洪水来自哪里)。这可以读取room.array[x][y] ! = ' '
,因此同时执行墙检查。
void floodFill(room room, int x, int y, char paint){
// First this
if(x < 0 || x >= room.rows || y < 0 || y >= room.cols){
return;
}
// If the current position is not a free spot...
if(room.array[x][y] != ' '){
return;
}
room.array[x][y] = paint;
// Increment the character to paint with
if (paint < 'Z') {
paint++;
}
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 floodFillStart(room room, int x, int y){
// Temporarily clear the starting spot
if (room.array[x][y] == 'A') {
room.array[x][y] = ' ';
}
floodFill(room, x, y, 'A');
}
在主程序调用中:
floodFillStart(room, x, y);
问题是,在开始时,初始单元格已经包含一个<code>A</code>字符,因此函数立即返回。一种方法是在第一次从main
调用floodFill
之前清除初始单元格,如下所示:
// Flood fill the room
newRoom.array[a[0]][a[1]] = ' ';
floodFill(newRoom, a[0], a[1], 'A');
这将产生以下输出:
Before
*****
* *
***A*
* *
*****
A is at 2, 3
After
*****
*AAA*
***A*
*AAA*
*****