填充算法与curses油漆桶
我们都知道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; }