编制一个求解迷宫通路的图形界面演示程序。
问题描述:
1) 输入一个任意大小的迷宫,任设起点、终点、障碍,用栈求出一条走出迷宫的路径,并显示在屏幕上。
2) 根据用户界面提示,用键盘输入。Home 键设置迷宫起点,End 键设终点,上下左右箭头键移动,Enter 键添加墙,Del 键删除墙,完成后按 F9键演示,Esc 键退出。
3)橙色的实心小圆圈表示起点,绿色实心圆圈表示终点,空心圆圈表示足迹,红色方块表示墙。
4)本程序只求出一条成功的通路,但若对求解函数 MazePath 稍加更改即可求得全部路径。此外,因受图形界面限制,不能保存或载入测试文件(此功能可在 Maze_text 中实现)。
5)当未输入起点时,消息显示“Error: You must set Startplace.”;
未输入终点时,显示“Error: You must set Endplace.” 找到路径时,
屏幕显示足迹,并在消息框出现 Path found,否则消去足迹,显示 Path not found.
#include<stdio.h>
#include<malloc.h>
#include <conio.h>
#include<time.h>
#include<Windows.h>
#include <graphics.h>
#define size 15
typedef struct {
int i;
int j;
int di;
}Box;
void mazepath();
void drawload(Box* st,int top);
void mademap();
void create();
void keyboard();
void draw_s();
void del();
void enter();
void home();
void end();
void f9();
void init_map();
void close();
void error();
void help();
void P(int* n);
int w, h, x, y, homenum, endnum,flag_x=0;
int** map;
int main(){
mademap();
while (1) {
keyboard();
if (homenum == 1 && endnum == 1)
mazepath();
if (homenum == 0) {
MessageBoxA(GetForegroundWindow(), TEXT("Error: You must set Startplace."), TEXT("错误!"), MB_OK);
}
if(endnum==0)
MessageBoxA(GetForegroundWindow(), TEXT("Error: You must set Endplace."), TEXT("错误!"), MB_OK);
for (size_t i = 0; i < h; i++)
for (size_t j = 0; j < w; j++)
if (map[i][j] == -1)
map[i][j] = 0;
}
}
void keyboard() {
static char ch = 0;
while (1)
{
draw_s();
while (!kbhit());
ch = _getch();
if (ch == -32) {
ch = _getch();
switch (ch)
{
case 77:ch = 'd'; break;
case 75:ch = 'a'; break;
case 80:ch = 's'; break;
case 72:ch = 'w'; break;
default:
break;
}
}
if (ch == 'd' || ch == 'D') {
if (x + 3 > w) {
x = 1;
continue;
}
x += 1;
}
if (ch == 'a' || ch == 'A') {
if (x - 2 <= -1) {
x = w - 2;
continue;
}
x -= 1;
}
if (ch == 's' || ch == 'S') {
if (y + 3 > h) {
y = 1;
continue;
}
y += 1;
}
if (ch == 'w' || ch == 'W') {
if (y - 2 <= -1) {
y = h - 2;
continue;
}
y -= 1;
}
if (ch == 'x' || ch == 'X') {
flag_x = (flag_x + 1) % 2;
MessageBoxA(GetForegroundWindow(), TEXT("模式已更改"), TEXT("提示"), MB_OK);
}
if (ch == 'H' || ch == 'h')
help();
if (ch == 71)
home();
if (ch == 79)
end();
if (ch == 13)
enter();
if (ch == 8)
del();
if (ch == 59)
init_map();
if (ch == 'u' || ch == 'U')
create();
if (ch == 67) {
f9();
return;
}
if (ch == VK_ESCAPE)
exit(0);
}
}
void mademap() {
double n;
system("mode con cols=25 lines=5");
help();
printf("请输入你要生成的迷宫大小
(需要算上迷宫周围墙体)
");
while (1) {
printf("宽:");
scanf("%lf", &n);
w = (int)n;
if (w > 4 && w == n)
{
break;
}
error();
}
while (1) {
printf("高:");
scanf("%lf", &n);
h = (int)n;
if (h > 4 && h == n)
{
break;
}
error();
}
map = (int**)malloc(sizeof(int*) * h);
if (map == NULL) {
MessageBoxA(GetForegroundWindow(), TEXT("内存不足!"), TEXT("错误!"), MB_OK);
exit(0);
}
for (size_t i = 0; i < h; i++) {
map[i] = (int*)malloc(sizeof(int) * w);
if (map[i] == NULL) {
MessageBoxA(GetForegroundWindow(), TEXT("内存不足!"), TEXT("错误!"), MB_OK);
exit(0);
}
}
init_map();
x = y = 1;
}
void del() {
map[y][x] = 0;
}
void enter() {
map[y][x] = 1;
}
void home() {
for (size_t i = 0; i < h; i++)
for (size_t j = 0; j < w; j++)
if (map[i][j] == 8)
map[i][j] = 0;
map[y][x] = 8;
}
void end() {
for (size_t i = 0; i < h; i++)
for (size_t j = 0; j < w; j++)
if (map[i][j] == -8)
map[i][j] = 0;
map[y][x] = -8;
}
void f9(){
homenum = endnum = 0;
for (size_t i = 0; i < h; i++)
for (size_t j = 0; j < w; j++) {
if (map[i][j] == 8)
homenum++;
if (map[i][j] == -8)
endnum++;
}
}
void draw_s() {
static int flag = 0;
if (flag == 0) {
initgraph(w * size + 1, h * size + 1 + 30);
settextcolor(WHITE);
settextstyle(13, 0, _T("宋体"));
outtextxy(0, h * size + 3, "找到路径(条):");
flag = 1;
}
for (size_t i = 0; i < h; i++)
for (size_t j = 0; j < w; j++)
{
if (x == j && y == i) {
setfillcolor(YELLOW);
fillrectangle(j * size, i * size, (j + 1) * size, (i + 1) * size);
continue;
}
if (map[i][j] == 0) {
clearrectangle(j * size, i * size, (j + 1) * size, (i + 1) * size);
}
if (map[i][j] == 1) {
setfillcolor(RED);
fillrectangle(j * size, i * size, (j + 1) * size, (i + 1) * size);
}
if (map[i][j] == 8) {
setfillcolor(0x0099FF);
fillcircle(j * size + (size / 2), i * size + (size / 2), size / 2);
}
if (map[i][j] == -8) {
setfillcolor(GREEN);
fillcircle(j * size + (size / 2), i * size + (size / 2), size / 2);
}
}
}
void init_map() {
for (size_t i = 0; i < h; i++)
for (size_t j = 0; j < w; j++) {
map[i][j] = 0;
if (i == 0 || j == 0||i==h-1||j==w-1) {
map[i][j] = 1;
}
}
}
void close() {
closegraph();
for (size_t i = 0; i < h; i++)
free(map[i]);
free(map);
exit(0);
}
void error() {
MessageBoxA(GetForegroundWindow(), TEXT("请规范输入!"), TEXT("错误!"), MB_OK);
}
void help() {
MessageBoxA(GetForegroundWindow(), TEXT("F1重置地图 F9开始寻路 ESC退出程序 Enter设置墙 Delete删除墙 P中止寻路
X改变寻路模式 Home设置启点 End设置终点 U生成随机地图 H帮助 方向键控制移动"), TEXT("帮助"), MB_OK);
}
void mazepath(){
FILE* f = NULL;
Box* st = NULL, * shortload = NULL;
int i = 0, j = 0, di = 0, i1 = 0, j1 = 0, top = -1, xe = 0, ye = 0, shorttop = -1, flag_h = 0;
long long int x = 0;
bool find = 0;
char s[10] = { NULL };
st = (Box*)malloc(sizeof(Box) * w * h);
if (st==NULL)
{
MessageBoxA(GetForegroundWindow(), TEXT("内存不足!"), TEXT("错误!"), MB_OK);
close();
}
if (flag_x==1)
{
f = fopen("maze_text.txt","w");
if (f == NULL) {
MessageBoxA(GetForegroundWindow(), TEXT("创建文件失败!"), TEXT("错误!"), MB_OK);
free(st);
close();
}
shortload= (Box*)malloc(sizeof(Box) * w * h);
if (shortload == NULL)
{
MessageBoxA(GetForegroundWindow(), TEXT("内存不足!"), TEXT("错误!"), MB_OK);
free(st);
fclose(f);
close();
}
}
for (size_t i2 = 0; i2 < h; i2++)
for (size_t j2 = 0; j2 < w; j2++) {
if (map[i2][j2] == 8) {
top++;
st[top].i = j2; st[top].j = i2; st[top].di = -1;
}
if (map[i2][j2] == -8) {
xe = j2; ye = i2;
}
}
HANDLE handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)P,&flag_h, 0, 0);flag_h = 1;
while (top != -1) {
i = st[top].i; j = st[top].j; di = st[top].di;
if (i == xe && j == ye) {
if (flag_x == 0) {
x++;
sprintf(s, "%d", x);
outtextxy(83, h * size + 3, s);
flag_h = 0;
CloseHandle(handle);
MessageBoxA(GetForegroundWindow(), TEXT("Path found"), TEXT("提示!"), MB_OK);
drawload(st, top);
free(st);
return;
}
else {
fprintf(f, "路径:");
for (size_t n = 0; n <= top; n++)
fprintf(f, "(%d,%d)", st[n].i, st[n].j);
fprintf(f, "
");
if (x == 0)
shorttop = top;
x++;
sprintf(s, "%d", x);
outtextxy(83, h * size + 3, s);
if (top <= shorttop)
for (size_t n = 0; n <= top; n++) {
shortload[n].i = st[n].i; shortload[n].j = st[n].j; shortload[n].di = st[n].di;
shorttop = top;
}
top--;
map[st[top].j][st[top].i] = -1;
i = st[top].i; j = st[top].j; di = st[top].di; i1 = j1 = 0;
find = 0;
}
}
else
find = 0;
while (di < 4 && !find) {
di++;
switch (di) {
case 0:i1 = i - 1; j1 = j; break;
case 1:i1 = i; j1 = j + 1; break;
case 2:i1 = i + 1; j1 = j; break;
case 3:i1 = i; j1 = j - 1; break;
}
if (map[j1][i1] == 0 || map[j1][i1] == -8)find = 1;
}
if (find) {
st[top].di = di;
top++;
st[top].i = i1; st[top].j = j1; st[top].di = -1;
if (map[st[top].j][st[top].i] != 8 && map[st[top].j][st[top].i] != -8)map[j1][i1] = -1;
}
else {
if (map[st[top].j][st[top].i] == 8) top--;
else {
map[st[top].j][st[top].i] = 0;
top--;
}
}
if (flag_h == 0)
break;
}
flag_h = 0;
free(st);
CloseHandle(handle);
if (flag_x == 0)
MessageBoxA(GetForegroundWindow(), TEXT("Path not found"), TEXT("提示!"), MB_OK);
else {
fprintf(f, "共%d条路",x);
fclose(f);
MessageBoxA(GetForegroundWindow(), TEXT("所有路径添加到maze_text"), TEXT("提示!"), MB_OK);
MessageBoxA(GetForegroundWindow(), TEXT("即将输出已知最短路径,若无路径将不输出"), TEXT("提示!"), MB_OK);
if (x > 0)
drawload(shortload, shorttop);
free(shortload);
}
}
void create() {
init_map();
srand(time(NULL));
for (size_t i = 1; i < h - 1; i++)
for (size_t j = 1; j < w - 1; j++) {
map[i][j] = rand() % 2;
if (rand() % 2 == 1)
j++;
}
}
void P(int *x) {
int i = 4;
char ch = 0;
outtextxy(0, h * size + 17, "正在寻路");
setfillcolor(BLUE);
while (*x!=0) {
if (kbhit()) {
ch = getch();
if (ch == 'p' || ch == 'P') {
*x = 0;
MessageBoxA(GetForegroundWindow(), TEXT("寻路中止"), TEXT("提示"), MB_OK);
}
}
fillrectangle(i * size, h * size + 20, (i + 1) * size + 2, h * size + 25);
Sleep(300);
if (i > w - 3) {
clearrectangle(4 * size - 1, h * size + 19, w * size , h * size + 26);
i = 3;
}
i++;
}
clearrectangle(4 * size - 1, h * size + 19, w * size, h * size + 26);
outtextxy(0, h * size + 17, "完成寻路");
}
void drawload(Box *st,int top) {
clearrectangle(x * size, y * size, (x + 1) * size, (y + 1) * size);
if (map[y][x]==1)
{
setfillcolor(RED);
fillrectangle(x * size, y * size, (x + 1) * size, (y + 1) * size);
}
if (map[y][x] == 8) {
setfillcolor(0x0099FF);
fillcircle(x * size + (size / 2), y * size + (size / 2), size / 2);
}
if (map[y][x] == -8) {
setfillcolor(GREEN);
fillcircle(x * size + (size / 2), y * size + (size / 2), size / 2);
}
int i = 1;
while (1) {
circle(st[i].i * size + (size / 2), st[i].j * size + (size / 2), size / 2);
if (i == top)
break;
i++;
Sleep(100);
}
while (!kbhit());
draw_s();
}
ps:画图机制可改进