我们都知道Windows的画图里面有个油漆桶工具,可以把选中的封闭区域都填充成自定义的颜色,这就是填充算法的应用。我在这里用Ncurses写成了一个小的填充算法的程序,看下图:
程序控制
程序运行期间,输入区域编号就可以使用‘+’填充该区域。
算法思想
这个算法还是广度搜索算法,只是遇到边界的时候(选定区域的边界)就不继续进行向外探索。
小工具代码
#include <ncurses.h>
#include <unistd.h>
#include <string.h>
typedef struct point
{
int y;
int x;
}Point;
// 改变一个点的字符为ch
void change_point(int y , int x, int ch);
// 改变整个区块的字符为ch,除了区块号所在位置
void change_part(int part_num, int ch);
void init_point(Point *p, int y, int x);
char map[18][38] = {
"--------------------------------------",
"| | | | |",
"| | | | |",
"| | | 5 | |",
"| | 2 | | |",
"| ------- | | |",
"| | |----------- |",
"| | | |",
"| 1 | | |",
"| | | |",
"| -------------- |",
"| | | |",
"|----------- | 4 |",
"| 3 | |",
"| | |",
"| | |",
"| | |",
"--------------------------------------"
};
int map_width = 38;
int map_height = 18;
// 各个分区号在map中的位置
Point partitions[5];
// startx 和 starty分别是数组在ncurses界面内的列、行坐标
int startx, starty;
int main()
{
initscr();
// start_color();
// noecho();
curs_set(0);
cbreak();
init_color(COLOR_WHITE, 1000, 1000, 1000);
init_pair(1, COLOR_WHITE, COLOR_BLACK);
init_point(partitions+0, 8, 6);
init_point(partitions+1, 4, 16);
init_point(partitions+2, 13, 17);
init_point(partitions+3, 12, 29);
init_point(partitions+4, 3, 26);
startx = (COLS - map_width) / 2 ;
starty = (LINES - map_height) / 2 + 3;
char *title = "Floodfill Algorithm -- Jack";
mvprintw(2, (COLS-strlen(title))/2, "%s", title);
refresh();
for (int i = 0; i < 18; ++i)
{
for (int j = 0; j < 38; ++j)
mvprintw(starty+i, startx+j, "%c", map[i][j]);
}
int choice = -1;
int oldchoice = -1;
mvprintw(starty + 2, 3, " ");
mvprintw(starty + 2, 3, "Part: ");
refresh();
choice = getch();
attron(A_BOLD);
mvprintw(starty + 2, 3+6, "%c", choice);
attroff(A_BOLD);
refresh();
oldchoice = choice;
change_part( choice-'0'-1, '+');
/***********************************************\
* 这里因为没有对choice的值进行检测或者限定 *
* 直接使用choice进行操作,如果接受了恶意输入 *
* 会导致程序异常退出,损坏shell *
\***********************************************/
while (1) {
mvprintw(starty + 2, 3, "Part: ");
refresh();
choice = getch();
attron(A_BOLD);
mvprintw(starty + 2, 3+6, "%c", choice);
attroff(A_BOLD);
refresh();
if (choice == '0') { break; }
change_part(oldchoice - '0' - 1, ' ');
change_part( choice-'0'-1, '+');
oldchoice = choice;
}
endwin();
return 0;
}
void change_point(int y , int x, int ch)
{
mvprintw(y, x, "%c", ch);
}
void change_part(int part_num, int ch)
{
int next[4][2] = {
{0, 1},
{1, 0},
{0, -1},
{-1, 0}
};
/* prepare a queue and two index */
Point queue[18*39] = {0};
char book[18][38] = {0};
int head , tail;
head = tail = 0;
queue[tail].y = partitions[part_num].y;
queue[tail].x = partitions[part_num].x;
++tail;
book[partitions[part_num].y][partitions[part_num].x] = 1;
/* prepare two var for the next axe */
int ny, nx;
/* while head < tail */
while (head < tail)
{
/* doing smthing in each direction */
for (int i = 0; i < 4; ++i)
{
ny = queue[head].y + next[i][0];
nx = queue[head].x + next[i][1];
/* if segmentation fault */
if (ny >= 18 || ny < 0 || nx < 0 || nx >= 38) { continue; };
if ( book[ny][nx] != 1 && map[ny][nx] != '-' && map[ny][nx] != '|')
{
book[ny][nx] = 1;
change_point(starty + ny, startx + nx, ch);
queue[tail].y = ny;
queue[tail].x = nx;
tail += 1;
}
}
head += 1;
}
refresh();
}
void init_point(Point *p, int y, int x)
{
p->y = y;
p->x = x;
}