四百行C语言代码写一个推箱子程序, 完成广度优先遍历并输出,数据实现动态跟进

这些代码我用了一个队列和两个栈,先用队列入所有的路径,直到目的地,第二个栈用来过滤无用的路径,第三个栈用来存储最短路径…
箱子和目的地的对数可以任意设置多对,只需要改地图Map二维数组的中的数字即可, 有足够的注释, 完全可以看得懂
地图的形状和大小都支持任意修改:
注意: #define Row 和 #define Col 已经规定了地图的行列数 修改时注意即可

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <Windows.h>
#include <queue>
#include <stack> 
#define Row 7 
#define Col 8
using namespace std;
//节点坐标 
struct node{
	int X;
	int Y;
};
typedef node *Node; 

//定义小人
struct People{
	int ROW;	//行 
	int COL;	//列 
};
struct People Person={0,0}; //小人的初始定义 

stack<Node> Stack;	//定义栈对象
stack<Node> History;//定义栈对象存储历史路径 
queue<Node> Que;	//定义队列对象

int P[Row][Col];	//P作为背景	

int Success=3;	//箱子是否全部到达目的地的 全部到达,Success=0 

Node RecordPath[30];	//记录BFS遍历的历史路径 

Node BoxStart;		//只是一个箱子的坐标
Node BoxEnd;	//只是一个目的地的坐标

//BFS遍历时的方向 
int Direction[4][2]={
	{0,1},{1,0},{0,-1},{-1,0} 
};
	

 //地图 0表示路, 1表示墙, 2表示人, 3表示箱子, 4表示箱子目的地 
int Map_1[Row][Col] = { 
		{1,1,1,1,1,1,1,1}, 
		{1,0,0,0,0,0,0,1},
		{1,0,4,3,2,0,0,1},
		{1,0,3,0,0,0,0,1},
		{1,0,0,0,1,0,0,1},
		{1,0,0,4,1,0,0,1},
		{1,1,1,1,1,1,1,1},
		};
int Map_2[Row][Col] = { 
		{1,1,1,1,1,1,1,1}, 
		{1,0,0,0,1,0,0,1},
		{1,0,4,0,0,0,0,1},
		{1,0,3,0,0,3,2,1},
		{1,0,0,0,1,0,0,1},
		{1,0,4,0,1,0,0,1},
		{1,1,1,1,1,1,1,1},
		};

//节点初始化 
Node inital(){	
	Node N;
	N=(Node)malloc(sizeof(struct node));
	N->X=0;
	N->Y=0;
	return N;
}		

//背景初始化
void BackGround(int Map[Row][Col]){
	int i,j;		
	for(i=0;i<Row;i++){	//背景初始化 
		for(j=0;j<Col;j++){
			if(Map[i][j]==0 || Map[i][j]==4 || Map[i][j]==1){	//显示的路径 目的地 墙 
				P[i][j]=Map[i][j];
			}
			if(Map[i][j]==2 ){	//背景 
				P[i][j]=0;
			}
		}
							
	}

}

//展示地图 
void ShowMap(int Map[Row][Col]){
	
	for(int i=0;i<Row;i++){
		for(int j=0;j<Col;j++){
			if(Map[i][j]==1){
				printf("■");
			}
			else if(Map[i][j]==0 || Map[i][j]==-1){
				printf("  ");
			}
			else if(Map[i][j]==2){
				printf("◆");
			}
			else if(Map[i][j]==3){
				printf("☆");
			}
			else if(Map[i][j]==4){
				printf("ⅹ");
			}
			else if(Map[i][j]==5){//箱子已到达目的地 
				printf("★");
			}	
		}
		printf("\n");
	} 
}

//得到人的地址
void GetDirection(int Map[Row][Col]){
	int i,j;
		Success=0;	//初始化 
	for(i=0;i<Row;i++){
		for(j=0;j<Col;j++){ 
			if(Map[i][j]== 2 ){//得到人的地址 
				Person.ROW=i;
				Person.COL=j;
			} 
			if(Map[i][j]== 3){	//箱子全部到达目的地时,应该不存在箱子了,K=0, 
				Success++; 
			}
		}
	}
}

//得到一个箱子及 一个目的地, 已扫描的路径初始化
void GetBoxDirection(int Map[Row][Col]){
	//初始化
	BoxStart=inital();			
	BoxEnd=inital();
	int i,j;		
	for(i=0;i<Row;i++){	//背景初始化 
		for(j=0;j<Col;j++){
			if(Map[i][j]==3){	//就只找一个箱子
				BoxStart->X=i;
				BoxStart->Y=j;
			}
			if(Map[i][j]==4){	//就只找一个目的地
				BoxEnd->X=i;
				BoxEnd->Y=j;
			}
			if(P[i][j]==-1){	//已扫描的路径初始化 
				P[i][j]=0;
			}
		}
	}
}

//地图背景刷新
void Refresh(int Map[Row][Col], int PersonROW, int PersonCOL){
	//当人站在目的地的位置时, 认定目的地的值不变
		if( P[PersonROW][PersonCOL] == 4){	//背景刷新
	    	Map[PersonROW][PersonCOL]=4;		//小人当前位置设定
		}else{
			Map[PersonROW][PersonCOL] = 0;
		}
}

//广度遍历 
void BFS(int Map[Row][Col], Node BoxStart, Node BoxEnd){
	if(BoxEnd->X!=0 && BoxEnd->Y!=0 && BoxStart->X!=0 && BoxStart->Y!=0){	//当所有箱子都退到目的地时,就不再进行遍历 
		 
	P[BoxStart->X][BoxStart->Y]=-1;	//表示已经过
	Node N = inital();	//定义一个节点 
	N->X=BoxStart->X;	//一个箱子的坐标 
	N->Y=BoxStart->Y;
	Que.push(N);
	while(Map[BoxEnd->X][BoxEnd->Y]!=Map[Que.back()->X][Que.back()->Y]){
		
		for(int i=0;i<4; i++){	//上下左右四个方向入队列 
			int tx = Que.front()->X+Direction[i][0];
			int ty = Que.front()->Y+Direction[i][1];
			
			//不能超过边界值
			if(tx<0||tx>Row ||ty<0||ty>Col)
				continue;

			if(Map[tx][ty]==0 && P[tx][ty]==0){	//将路径入队列 
				P[tx][ty]=-1;
				Node N = inital();	//申请一个节点
				N->X=tx;
				N->Y=ty;
				Que.push(N);	//入队列	
			}
			else if(Map[tx][ty]==4)	//找到终点后 
			{	
				Node N = inital();	//申请一个节点
				N->X=tx;
				N->Y=ty;
				Que.push(N);
				break;
			}				
		}
		Stack.push(Que.front());	//队列出一个元素,栈就存队列出的元素	
		Que.pop();	//一个元素出队列 
	}
	//清空队列
	while (!Que.empty())
	{
		Que.pop();
	}

	//栈的元素开始出栈,回溯到起点
	//取出栈的第一个和第二个元素
		Node node_1=Stack.top();
		Node node_2=Stack.top();	//默认给一个初始值,以避免当箱子邻近目的地时node_2出现内容为空的情况	
		Stack.pop();	
		int i=1;
	while(!Stack.empty()){
		node_2=Stack.top();
		
		//找上一个节点位置
		if(node_1->Y==node_2->Y ){ 
			if((node_1->X-1)==node_2->X || (node_1->X+1)==node_2->X ){	//上边, 下边 
				History.push(node_1);	//存入栈中		
				node_1=node_2;
				Stack.pop();	
			}else{
				Stack.pop();
			} 
		} 
		else if(node_1->X==node_2->X){ 
			if((node_1->Y-1)==node_2->Y || (node_1->Y+1)==node_2->Y){	//左边, 右边 
				History.push(node_1);	//存入栈中
				node_1=node_2;
				Stack.pop();
				
			}else{
				Stack.pop();
			} 
		}
			 
		else{	//不是该节点相邻节点的话,就直接弹出来,再找下一个		
			Stack.pop();
		}
	}
	
	//当node_1和node_2都回到起点的时候, 结束 
	if( node_1->X!=0 || node_1->Y!=0) 
	if(node_1->X==node_2->X && node_1->Y==node_2->Y){
		printf(" (%d,%d)",node_1->X,node_1->Y);
	}
	
	//打印历史路径
	while(!History.empty()){
		printf(" (%d,%d)",History.top()->X,History.top()->Y);
		History.pop();
	}
	printf("\n");//换行 使地图在历史路径下边
}else{
	printf("\n");
}
}

//小人,箱子移动 
void Move(int X,int Y,int Map[Row][Col]){
	GetDirection(Map); //得到人的当前位置 
	//小人的下一个坐标 
    int nextPersonRow = Person.ROW + X;
    int nextPersonCol = Person.COL + Y;
 	//箱子的下一个位置 
	int nextBoxRow=nextPersonRow + X;
	int nextBoxCol=nextPersonCol + Y;
     
    //如果小人的下一个坐标是路径 目的地 
    if(Map[nextPersonRow][nextPersonCol]==0 || Map[nextPersonRow][nextPersonCol] == 4 ){
    	Map[nextPersonRow][nextPersonCol] = 2;
		
		Refresh(Map,Person.ROW,Person.COL); //背景刷新 
  
    	Person.ROW = nextPersonRow;
    	Person.COL = nextPersonCol;
    }
    
    //如果小人的下一个坐标是箱子的位置,且箱子被推动后的下一个位置不是墙,另一个箱子,已被占的目的地 
    if(Map[nextPersonRow][nextPersonCol]==3 && Map[nextBoxRow][nextBoxCol]!=1 && Map[nextBoxRow][nextBoxCol]!=3 &&Map[nextBoxRow][nextBoxCol]!=5){
		
		//箱子移动到目的地的情况 
    	if(Map[nextBoxRow][nextBoxCol]==4){
    		Map[nextBoxRow][nextBoxCol]=5;
		}
		else{	//没移动到目的地 
			Map[nextBoxRow][nextBoxCol]=3;
		}
		
		Refresh(Map,Person.ROW,Person.COL); //背景刷新 
		
		Map[nextPersonRow][nextPersonCol] = 2;	//小人下一个位置值
	        Person.ROW = nextPersonRow;
	    	Person.COL = nextPersonCol;
	    
	}	
    
    //如果小人的下一个坐标是箱子已放到目的地的坐标时 条件是小人移动箱子后,箱子的下一个位置不能是墙和另一个箱子 
    if(Map[nextPersonRow][nextPersonCol] == 5 && (Map[nextBoxRow][nextBoxCol]!=1 && Map[nextBoxRow][nextBoxCol]!=3)){
			 	
		Map[nextPersonRow][nextPersonCol] = 2; 
		Map[nextBoxRow][nextBoxCol]=3;
		
		Refresh(Map,Person.ROW,Person.COL); //背景刷新 
			
		Person.ROW = nextPersonRow;
    	Person.COL = nextPersonCol;
	}
    
    //如果小人的下一个坐标是墙或是另一个箱子 
    if(Map[nextPersonRow][nextPersonCol]==1 || Map[nextPersonRow][nextPersonCol]==3 ){
        //什么也不做 
    }
     
}

//控制移动 
void ControlMove(int Map[Row][Col]){
	
	while(1){
		//清屏 
		system("CLS");
    	
		//定位一个箱子和目的地
		GetBoxDirection(Map);
		
		//展示地图
		ShowMap(Map);
		
		//由上面的定位开始找最短路径, 并且打印
		BFS(Map,BoxStart,BoxEnd);
		 
    	//接收小人要走的方向 
    	rewind(stdin);
    	//输入下一步 
   		char dir = getch();
   		
	    switch(dir){
	    
	        //小人向上移动 
	        case 'w':
	        case 'W':
	            Move(-1,0,Map);
	        break;
	        
	        //小人向下移动 
	        case 's':
	        case 'S':
	        	Move(1,0,Map);
	        break;
	        //小人向右移动 
	        case 'd':
	        case 'D':
	        	Move(0,1,Map);
	        break;
	        //小人向左移动 
	        case 'a':
	        case 'A':
	        	Move(0,-1,Map);
	        break;     
	    }
	    
		//判断是否全部箱子已经推到目的地	 
		if(Success==0){
			printf("闯关成功!"); 
			break; 
		}				
	}	

}
  
 //主函数 
int main(){
	//第一关 
	BackGround(Map_1);
	ControlMove(Map_1);
	//第二关 
	BackGround(Map_2); 
	ControlMove(Map_2);	 
	system("pause");
}

在这里插入图片描述
有一个致命的缺点是:
只能显示坐标值最大的星星箱子到坐标值最大的目的地"X"的最短路径, 当推完第一个箱子后,自动显示下一个箱子到目的地的最短路径

(目前没发现bug, 若发现有bug希望能私信我)

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值