填充算法与curses油漆桶

我们都知道Windows的画图里面有个油漆桶工具,可以把选中的封闭区域都填充成自定义的颜色,这就是填充算法的应用。我在这里用Ncurses写成了一个小的填充算法的程序,看下图:

程序控制

程序运行期间,输入区域编号就可以使用‘+’填充该区域。

算法思想

这个算法还是广度搜索算法,只是遇到边界的时候(选定区域的边界)就不继续进行向外探索。

小工具代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#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;
}

总结

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

猜你喜欢

转载自www.cnblogs.com/litran/p/10541070.html
今日推荐