填充算法与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;
}

  

总结

这个小程序是我一个多小时两个小时裸写的,虽然广度搜索算法真的非常简单,但还是挺有成就感的。

posted @ 2019-03-16 10:50  不怕旅途多坎坷  阅读(599)  评论(0编辑  收藏  举报