本来是想用esayx写的 发现好像用不着,直接改的窗口背景颜色做的,后来还改进了鼠标绘制地图 ,地图大小可以设置,寻路的过程也可以设置放慢的速度,作为大一的一个实践小项目,第一次发csdn,和大家一起分享。
#include<cstdio>
#include<stdlib.h>
#include<windows.h>
#include<conio.h>
#define RED 1
#define YELLOW 21
#define HYELLOW 22
#define GREEN 3
#define HGREEN 32
#define BLUE 4
#define PURPLE 5
#define GRAY 6
#define BLACK 7
#define WHITE 8
#define START 1
#define END -2
#define WALL -1
#define WAY 0
#define YES 1
#define NO 0
#define SLEEPTIME 0
struct Size{//尺寸
int width;
int height;
};
struct MazeMap{//地图
Size size;
short** EachLine;//该数组存放每一行的头指针
};
struct NodeIndex{//作为坐标标记出入队列
int X;
int Y;
NodeIndex* nextnode;
};
struct Queue{//链队列
NodeIndex* head;
NodeIndex* tail;
int num;
};
void InitDataQueue(Queue &indexqueue){//初始化队列
indexqueue.head = NULL;
indexqueue.tail = NULL;
indexqueue.num = 0;
}
NodeIndex OutputData(Queue &indexqueue){
NodeIndex nodeindex;
NodeIndex* p;
nodeindex.nextnode = NULL;
nodeindex.X = -1;
nodeindex.Y = -1;
if(indexqueue.num == 0){
return nodeindex;
}
nodeindex = *indexqueue.head;
p = indexqueue.head->nextnode;
free(indexqueue.head);
indexqueue.head = p;
indexqueue.num--;
return nodeindex;
}
void InputData(Queue &indexqueue,NodeIndex nodeindex){//尾插法直接数据入队
NodeIndex* p;
p = (NodeIndex*)malloc(sizeof(NodeIndex));
if(p == NULL){
printf("系统忙,无法运行\n");
exit(-1);
}
*p = nodeindex;
p->nextnode = NULL;
if(indexqueue.num == 0){
indexqueue.tail = p;
indexqueue.head = indexqueue.tail;
}else{
indexqueue.tail->nextnode = p;
indexqueue.tail = p;
}
indexqueue.num++;
}
void InitMazeMap(MazeMap &mazemap,Size size){//初始化地图数据
mazemap.size = size;
mazemap.EachLine = (short**)malloc(sizeof(short*)*size.height);
if(mazemap.EachLine == NULL){
printf("系统忙,无法运行\n");
exit(-1);
}
short** p,start;
p = mazemap.EachLine;
for(int i=0;i<size.height;i++){
*p = (short*)malloc(sizeof(short)*size.width);
if(p == NULL){
printf("系统忙,无法运行\n");
exit(-1);
}
p++;
}
short* to_p;
p = mazemap.EachLine;
to_p = *p;
for(int i=0;i<size.height;i++){
for(int j=0;j<size.width;j++){
if(i==0 || i==size.height-1 ||j==0 || j==size.width-1){
*to_p = WALL;
}else{
*to_p = WAY;
}
//printf("%d ",*to_p);//调试用于查看数据和数据内存地址
to_p++;
}
//printf("\n");
p++;
to_p = *p;
}
}
void GoTo_XY(int x,int y){//移动光标的函数
HANDLE handle_out;
handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = {x*2,y};
SetConsoleCursorPosition(handle_out,pos);
}
void Color(int color,HANDLE handle_out){//切换颜色函数
switch (color){
case RED:{
SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_INTENSITY );
break;
}
case GREEN:{
SetConsoleTextAttribute(handle_out,BACKGROUND_GREEN);
break;
}
case HGREEN:{
SetConsoleTextAttribute(handle_out,BACKGROUND_GREEN|BACKGROUND_INTENSITY);
break;
}
case BLUE:{
SetConsoleTextAttribute(handle_out,BACKGROUND_BLUE);
break;
}
case GRAY:{
SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE);
break;
}
case PURPLE:{
SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_BLUE);
break;
}
case YELLOW:{
SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_GREEN);
break;
}
case HYELLOW:{
SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_INTENSITY);
break;
}
case BLACK:{
SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|COMMON_LVB_REVERSE_VIDEO);
break;
}
case WHITE:{
SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY);
break;
}
}
}
POINT GetPosition(){//获取鼠标位置函数
POINT pxy ={0,0};
LPPOINT pxyf = &pxy;
GetCursorPos(pxyf);
return pxy;
}
void SetTheWall(MazeMap &mazemap,Size size,HANDLE handle_out,POINT &start,POINT &end){
int key = 0,Sset = 0,Eset = 0,statue = 1;
int Rx = 0,Ry = 0;
GoTo_XY(0,size.height+2);
Color(WHITE,handle_out);
printf("操作说明: \n");
printf("1.按下空格的同时移动鼠标绘制地图 \n");
printf("2.按下P键可以重新定位画笔位置 \n");
printf("3.按下Enter键结束当前地图绘制 \n");
printf("4.按下S键设置鼠标当前位置为起点 \n");
printf("5.按下E键设置鼠标当前位置为终点 \n");
POINT pxy ={0,0};
GoTo_XY(0,0);
Color(WHITE,handle_out);
printf("[]<——将鼠标放到框内,双击键盘P键定位鼠标");
fflush(stdin);
while(_getch() != 112){
GoTo_XY(0,0);
printf("[]<——放到这里哦,双击P键定位鼠标 ");
}
while(statue){
key = _getch();
pxy = GetPosition();
switch (key){
case 32:{//绘制墙体
pxy.x = (pxy.x-Rx)/16;
pxy.y = (pxy.y-Ry)/16;
if(pxy.x<size.width && pxy.y<size.height){
GoTo_XY(pxy.x,pxy.y);
mazemap.EachLine[pxy.y][pxy.x] = -1;
printf(" ");
}
break;
}
case 114:{//擦除
pxy.x = (pxy.x-Rx)/16;
pxy.y = (pxy.y-Ry)/16;
if(pxy.x>0 && pxy.x<size.width && pxy.y<size.height && pxy.y>0){
if(mazemap.EachLine[pxy.y][pxy.x] == START){
Sset = 0;
}else if(mazemap.EachLine[pxy.y][pxy.x] == END){
Eset = 0;
}
mazemap.EachLine[pxy.y][pxy.x] = 0;
GoTo_XY(pxy.x,pxy.y);
Color(GRAY,handle_out);
printf(" ");
Color(WHITE,handle_out);
}
break;
}
case 112:{//鼠标定位
Rx = pxy.x;
Ry = pxy.y;
break;
}
case 115:{//起点绘制
if(Sset == 1){
break;
}
pxy.x = (pxy.x-Rx)/16;
pxy.y = (pxy.y-Ry)/16;
if(pxy.x<size.width && pxy.y<size.height){
start.x = pxy.x;
start.y = pxy.y;
mazemap.EachLine[pxy.y][pxy.x] = START;
Color(BLUE,handle_out);
GoTo_XY(pxy.x,pxy.y);
printf(" S");
Color(WHITE,handle_out);
Sset = 1;
}
break;
}
case 101:{//终点绘制
if(Eset == 1){
break;
}
pxy.x = (pxy.x-Rx)/16;
pxy.y = (pxy.y-Ry)/16;
if(pxy.x<size.width && pxy.y<size.height){
end.x = pxy.x;
end.y = pxy.y;
mazemap.EachLine[pxy.y][pxy.x] = END;
Color(YELLOW,handle_out);
GoTo_XY(pxy.x,pxy.y);
printf(" E");
Color(WHITE,handle_out);
Eset = 1;
}
break;
}
case 13:{
if(Sset && Eset){
statue = 0;
}else{
Color(WHITE,handle_out);
GoTo_XY(0,0);
printf("请设置起点终点!");
Color(WHITE,handle_out);
_getch();
}
break;
}
}
GoTo_XY(0,0);
printf("[]当前位置:X:%d Y:%d key:%d(画笔不准可放到左边方框重定位) ",pxy.x,pxy.y,key);
}
}
void PrintMap(MazeMap mazemap,HANDLE handle_out){//显示地图函数
Size size = mazemap.size;
short** p;
short* to_p;
p = mazemap.EachLine;
to_p = *p;
for(int i=0;i<size.height;i++){
GoTo_XY(0,i);
for(int j=0;j<size.width;j++){
if(*to_p == WAY){
Color(GRAY,handle_out);
printf(" ");
}else{
Color(WHITE,handle_out);
printf(" ");
}
to_p++;
}
p++;
to_p = *p;
}
}
void HideCursor(){//隐藏光标
CONSOLE_CURSOR_INFO cursor_info = {1,0};//第二个值为零隐藏
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
void SetHandle(HANDLE &handle_out,HANDLE &handle_in,Size size){//获取并设置窗口句柄
handle_out = GetStdHandle(STD_OUTPUT_HANDLE);//获得标准输出设备句柄
handle_in = GetStdHandle(STD_INPUT_HANDLE);
SMALL_RECT rc = {1,1,size.width*2,size.height+5};//设置窗口位置和大小
SetConsoleWindowInfo(handle_out,true,&rc); //设置窗口信息,第二个参数为设置参数是否执行
}
void SetStartEnd(MazeMap &mazemap,POINT start,POINT end,HANDLE &handle_out){//设置出发点和终点
mazemap.EachLine[start.y][start.x] = START;
Color(BLUE,handle_out);
GoTo_XY(start.x,start.y);
printf("S ");
mazemap.EachLine[end.y][end.x] = END;
Color(YELLOW,handle_out);
GoTo_XY(end.x,end.y);
printf("E ");
}
int SrcMethod(MazeMap &mazemap,NodeIndex nodeindex,Queue &indexqueue,int drie){//找路的方法
int nodevalue = 0; //Bug(1) [&]
NodeIndex fblr[4] = {{0,1},{-1,0},{1,0},{0,-1}}; //分别对应上下左右
if(mazemap.EachLine[nodeindex.Y+(fblr[drie].Y)][nodeindex.X+(fblr[drie].X)] == END){
return YES;
}
if(mazemap.EachLine[nodeindex.Y+(fblr[drie].Y)][nodeindex.X+(fblr[drie].X)] == WAY ){
mazemap.EachLine[nodeindex.Y+(fblr[drie].Y)][nodeindex.X+(fblr[drie].X)] = mazemap.EachLine[nodeindex.Y][nodeindex.X]+1;
nodeindex.X = nodeindex.X+(fblr[drie].X);
nodeindex.Y = nodeindex.Y+(fblr[drie].Y);
GoTo_XY(nodeindex.X,nodeindex.Y);
printf(" ");
InputData(indexqueue,nodeindex);
Sleep(SLEEPTIME);
}
return NO;
}
int FindThePeth(MazeMap mazemap,NodeIndex &endindex,NodeIndex &startindex,HANDLE &handle_out){
int value[4] = {0};
int i ,min,mark = 0;
while(true){
i=0;//(bug_2)注意每次归零,否则有情况不可达
value[0] = mazemap.EachLine[endindex.Y][endindex.X+1];//R
value[1] = mazemap.EachLine[endindex.Y][endindex.X-1];//L
value[2] = mazemap.EachLine[endindex.Y+1][endindex.X];//F
value[3] = mazemap.EachLine[endindex.Y-1][endindex.X];//B
while(value[i]<=0){//既然能够到达,必然有一个可走的(值大于0的点)
i++;
}
mark = i;
min = value[i];
for(i=0;i<4;i++){
if(value[i] >0 && value[i]<min){
mark = i;
min = value[i];
}
}
switch(mark){
case 0:{
endindex.X = endindex.X+1;
break;
}
case 1:{
endindex.X = endindex.X-1;
break;
}
case 2:{
endindex.Y = endindex.Y+1;
break;
}
case 3:{
endindex.Y = endindex.Y-1;
break;
}
}
if(endindex.X == startindex.X && endindex.Y == startindex.Y){
return YES;
}
GoTo_XY(endindex.X,endindex.Y);
Color(RED,handle_out);
printf(" ");
Sleep(SLEEPTIME);
}
}
void DrawMap(MazeMap &mazemap){//测试用地图绘制
}
int main(){
HANDLE handle_out,handle_in;
MazeMap mazemap;
Queue indexqueue;
Size map_size;
printf("请输入要生成的地图尺寸:\n");
printf("宽度(10--50较为适宜):");
scanf("%d",&map_size.width);
while(map_size.width<10 || map_size.width>50){
printf("输入数据超出限制,请重新输入");
scanf("%d",&map_size.width);
}
printf("高度度(10--50较为适宜):");
scanf("%d",&map_size.height );
while(map_size.height<10 || map_size.height>50){
printf("输入数据超出限制,请重新输入");
scanf("%d",&map_size.height);
}
POINT start = {0,0};
POINT end = {0,0};
int srcstatue = NO,nodevalue = 0;
SetHandle(handle_out,handle_in,map_size);
HideCursor();
InitMazeMap(mazemap,map_size);//初始化操作
InitDataQueue(indexqueue);
for(int i=0;i<map_size.height+2;i++){//输出字符固定布局位置,否则拖动窗口大小会被刷新排版
GoTo_XY(map_size.width,i);
Color(BLACK,handle_out);
printf("|");
}
PrintMap(mazemap,handle_out);
SetTheWall(mazemap,map_size,handle_out,start,end);
NodeIndex nodeindex,startindex,endindex;
nodeindex.X = start.x;
nodeindex.Y = start.y;
startindex.X = nodeindex.X;
startindex.Y = nodeindex.Y;
endindex.X = end.x;
endindex.Y = end.y;
InputData(indexqueue,nodeindex);
while(indexqueue.num != 0){
nodeindex = OutputData(indexqueue);
if(nodeindex.X != start.x || nodeindex.Y != start.y){
Color(HYELLOW,handle_out);
GoTo_XY(nodeindex.X,nodeindex.Y);
printf(" ");
Color(HGREEN,handle_out);
}
if(SrcMethod(mazemap,nodeindex,indexqueue,0) == YES ){
srcstatue = YES;
break;
}
if(SrcMethod(mazemap,nodeindex,indexqueue,3) == YES ){
srcstatue = YES;
break;
}
if(SrcMethod(mazemap,nodeindex,indexqueue,2) == YES ){
srcstatue = YES;
break;
}
if(SrcMethod(mazemap,nodeindex,indexqueue,1) == YES ){
srcstatue = YES;
break;
}
GoTo_XY(0,map_size.height);
Color(GREEN,handle_out);
printf("当前可走节点个数:%d ",indexqueue.num);
}
if(srcstatue==YES){
FindThePeth(mazemap,endindex,startindex,handle_out);
GoTo_XY(0,map_size.height+1);
printf("路径已找到 ");
}else{
GoTo_XY(0,map_size.height+1);
printf("出口不可达 ");
}
/*for(int i=0;i<map_size.height;i++){
for(int j=0;j<map_size.width;j++){
printf("%2d ",mazemap.EachLine[i][j]);//调试用于查看数据和数据内存地址
}
printf("\n");
}*/
GoTo_XY(0,map_size.height+5);//运行结束以后恢复位置以及背景
Color(BLACK,handle_out);
CloseHandle(handle_in);
CloseHandle(handle_out);
return 0;
}