C++ 小游戏之推箱子
来源:互联网 发布:网络电视直播系统 编辑:程序博客网 时间:2024/05/02 04:41
做完C的贪吃蛇游戏后,感觉还不错,刚好记得在HDU上做过一道关于推箱子游戏的算法题目,即双BFS。
所以我决定来做做C++的小游戏推箱子,由于刚学C++,对C++还是不很熟练,但是思路还是很清楚的,
编写代码还是很舒服的。!
现在晒晒我的代码和详细解释,希望多交流~!
//*******************************************************//********************小小推箱子*************************//*******************************************************//**************版权所有***2011.9.24***咸鱼**************//*******************************************************//*****************如写的不好,请见谅*********************//************每次运行程序的地图是不同的*****************//*******************************************************
/*Sokoban.h: 类定义 Sokoban.c: 类成员函数实现Use_Sokoban.c: 主函数请用VC6(别编译器的也行)先运行Use_Sokoban.c文件,要编译该文件一下,再点Project-> Add To Project-> Files 选择Sokoban.c文件,即将Sokoban.c加载到工程里,最后运行就OK拉。*///*******************************************************Sokoban.h//*******************************************************#ifndef SOKOBAN_H_ //防止文件重复包含#define SOKOBAN_H_#include <queue>using std::queue;//每一步的数据类型struct node { int bx, by; //箱子的坐标 int px, py; //人的坐标};//推箱子类class Sokoban {private: enum {L = 15, H = 7}; char GameMap[H][L]; //地图 int Pex, Pey; //人的位置 int Boxx, Boxy; //箱子的位置 int Succeed, Prove; //是否成功到目的地, 是否可玩性 int dx[4], dy[4]; //方向数组protected: char Empty; char People; char Box; char Block; char Target; int dir; //记录按键方向 node s, e;public: Sokoban(); //构建函数 ~Sokoban() {} //析构函数,即为inline //地图初始化函数 void Initial(); //箱子路劲验证函数,参数为箱子坐标(bx,by),人坐标(px,py) void Box_Bfs(int bx, int by, int px, int py); //人路劲验证函数,人所到的目的地(ex,ey) bool People_Bfs(int ex, int ey); //地图刷新函数 void Show(); //按键判断函数 void Button(); //箱子人移动函数 void Move(); //验证越界函数 bool Check(int x, int y); };#endif//*******************************************************Sokoban.cpp//*******************************************************#include "Sokoban.h"#include <cstring>#include <cstdlib>#include <ctime>#include <iostream>#include <conio.h>using std::cout;using std::endl;Sokoban::Sokoban() //构建函数即对变量初始化{ dir = -1; Succeed = Prove = 0; memset(GameMap, '.', sizeof(GameMap)); Empty = '.'; People = 'P'; Box = '#'; Block = '*'; Target = 'T'; //方向依次为上右下左 dx[0] = -1; dx[1] = 0; dx[2] = 1; dx[3] = 0; dy[0] = 0; dy[1] = 1; dy[2] = 0; dy[3] = -1; //随机种子,使程序每次运行时所产生的随机数不同 srand(time(0));}//地图初始化函数void Sokoban::Initial(){ int count = 0, x, y; //对地图中随机产生25个阻碍物 while(count != 25) { x = rand()%H; y = rand()%L; if(GameMap[x][y] == Empty) { GameMap[x][y] = Block; count++; } } while(true) //随机产生人开始的位置 { x = rand()%H; y = rand()%L; if(GameMap[x][y] == Empty) { GameMap[x][y] = People; Pex = x; Pey = y; break; } } while(true) //随机产生箱子开始的位置 { x = rand()%H; y = rand()%L; //不让箱子在地图的边界处 if(GameMap[x][y] == Empty && x != 0 && y != 0 && x != H-1 && y != L-1) { GameMap[x][y] = Box; Boxx = x; Boxy = y; break; } } while(true) //随机产生目标的位置 { x = rand()%H; y = rand()%L; if(GameMap[x][y] == Empty) { GameMap[x][y] = Target; break; } } //对游戏地图检查是否可将箱子推到目的地,即判断游戏可玩性 Sokoban::Box_Bfs(Boxx, Boxy, Pex, Pey); //如游戏不可玩,即再随机产生地图 if(!Prove) { memset(GameMap, '.', sizeof(GameMap)); Sokoban::Initial(); } else Sokoban::Show();}//箱子路劲验证函数//用BFS算法对箱子验证是否可到目的地void Sokoban::Box_Bfs(int bx, int by, int px, int py){ queue<node>_Box; //创建箱子队列 //visit对上一步走到下一步的记录,防止箱子走重复路劲 //visit[i][j][z][k]表示箱子从点(i,j)到点(z,k) //visit[][][][]为0时表示为走过,1时表示已走过 int visit[H][L][H][L]; memset(visit, 0, sizeof(visit)); //visit数组初始化 s.bx = bx; s.by = by; //将起始的箱子、人位置放入队列 s.px = px; s.py = py; _Box.push(s); int pe_x, pe_y; while(!_Box.empty()) //队列为空时跳出 { s = _Box.front(); _Box.pop(); if(GameMap[s.bx][s.by] == Target) //到达目的地 { Prove = 1; break; } for(int i = 0; i < 4; i++) { e.bx = s.bx + dx[i]; e.by = s.by + dy[i]; switch(i) //人推箱子的位置 { case 0: pe_x = s.bx + dx[2]; pe_y = s.by + dy[2]; break; case 1: pe_x = s.bx + dx[3]; pe_y = s.by + dy[3]; break; case 2: pe_x = s.bx + dx[0]; pe_y = s.by + dy[0]; break; case 3: pe_x = s.bx + dx[1]; pe_y = s.by + dy[1]; break; } //验证箱子和人的位置的合法性 if(!Check(e.bx, e.by) || !Check(pe_x, pe_y) || GameMap[e.bx][e.by] == Block || GameMap[pe_x][pe_y] == Block || visit[s.bx][s.by][e.bx][e.by] ) continue; //如人可推箱子即进入队列 if(Sokoban::People_Bfs(pe_x, pe_y)) { //保存人推箱子后的位置 e.px = pe_x; e.py = pe_y; _Box.push(e); visit[s.bx][s.by][e.bx][e.by] = 1; //箱子路劲的标记 } } }} //人路劲验证函数//用BFS算法对人验证是否可推箱子bool Sokoban::People_Bfs(int ex, int ey){ queue<node>_People; node t, end; //visit数组对人的路劲进行标记,0为未走过,1为走过 int visit[H][L]; //visit数组初始化为0 memset(visit, 0, sizeof(visit)); t.px = s.px; t.py = s.py; //人初始位置进入队列 _People.push(t); visit[t.px][t.py] = 1; while(!_People.empty()) //对立为空时跳出 { t = _People.front(); _People.pop(); if(t.px == ex && t.py == ey) //人可到达(ex,ey)该点 return 1; for(int i = 0; i < 4; i++) { end.px = t.px + dx[i]; end.py = t.py + dy[i]; //检查人的位置合法性 if(!Check(end.px, end.py) || GameMap[end.px][end.py] == Block || GameMap[end.px][end.py] == Box || visit[end.px][end.py]) continue; //进入队列 _People.push(end); visit[end.px][end.py] = 1; //记录 } } return 0;} //地图刷新函数void Sokoban::Show(){ int i, j; while(true) { //每半秒刷新一次地图 clock_t s = clock(); while(clock() - s < CLOCKS_PER_SEC/2) ; //先判断按键在移动 Sokoban::Button(); Sokoban::Move(); system("cls"); for(i = 0; i < H; i++) { for(j = 0; j < L; j++) cout << GameMap[i][j]; cout << endl; } cout << endl; cout << "\n**********************************" << endl; cout << "* 小小C++语言推箱子游戏 *" << endl; cout << "* 游戏规则: *" << endl; cout << "* P: 人 #: 箱子 *" << endl; cout << "* *: 障碍物 T: 目的地 *" << endl; cout << "**********************************" << endl; cout << "* 每次游戏地图不一样 *" << endl; cout << "* 人将箱子推到目的地即过关 *" << endl; cout << "*所给地图,一定可过关,请慎重移箱子*" << endl; cout << "* 箱子无路可走时,机器不会提示 *" << endl; cout << "**********************************" << endl; //箱子成功到达目的地 if(Succeed) { cout << "\n ^_^ >_<" << endl; cout << "恭喜过关成功! 再来一盘吧" << endl; getchar(); break; } }} //按键判断函数void Sokoban::Button(){ int key; if(kbhit() != 0) //检查当前是否有键盘输入,若有则返回一个非0值,否则返回0 { while(kbhit() != 0) //可能存在多个按键,要全部取完,以最后一个为主 key = getch(); //将按键从控制台中取出并保存到key中 switch(key) { //上 case 72: dir = 0; break; //右 case 77: dir = 1; break; //下 case 80: dir = 2; break; //左 case 75: dir = 3; break; } }} //人推箱子移动函数void Sokoban::Move(){ int x, y; //有按键时 if(dir != -1) { //人所推向的位置坐标 x = Pex + dx[dir]; y = Pey + dy[dir]; //人所推位置为空,即走向该位置 if(Check(x, y) && GameMap[x][y] == '.') { GameMap[Pex][Pey] = '.'; //人的位置改变 GameMap[x][y] = 'P'; Pex = x; Pey = y; dir = -1; //按键记录为无即-1 } else //人所推位置为箱子,即将箱子推向该方向的前面这点 if(Check(x, y) && GameMap[x][y] == '#' && Check(x+dx[dir], y+dy[dir]) && GameMap[ x+dx[dir] ][ y+dy[dir] ] == '.') { GameMap[Boxx][Boxy] = '.'; //箱子的位置改变 GameMap[x+dx[dir] ][ y+dy[dir] ] = '#'; Boxx = x + dx[dir]; Boxy = y + dy[dir]; GameMap[Pex][Pey] = '.'; //人的位置改变 GameMap[x][y] = 'P'; Pex = x; Pey = y; dir = -1; } else //将箱子推向该方向的前面这点为目的地 if(Check(x, y) && GameMap[x][y] == '#' && Check(x+dx[dir], y+dy[dir]) && GameMap[ x+dx[dir] ][ y+dy[dir] ] == 'T') { GameMap[Boxx][Boxy] = '.'; //箱子的位置改变 GameMap[x+dx[dir] ][ y+dy[dir] ] = '#'; Boxx = x + dx[dir]; Boxy = y + dy[dir]; GameMap[Pex][Pey] = '.'; //人的位置改变 GameMap[x][y] = 'P'; Pex = x; Pey = y; dir = -1; Succeed = 1; //记录成功到达目的地 } }} //判断越界情况bool Sokoban::Check(int x, int y){ if(x < 0 || x >= H || y < 0 || y >= L) return 0; else return 1;}//*************************************************Use_Sokoban.cpp//*************************************************#include <iostream>#include "Sokoban.h"using namespace std; int main(){ Sokoban s; s.Initial(); return 0;}
- 012-C语言小游戏之推箱子
- c语言小游戏,推箱子
- C++ 小游戏之推箱子
- C语言实现推箱子小游戏
- c语言控制台推箱子小游戏
- 微信HTML5小游戏之推箱子
- Java小游戏之推箱子游戏
- 推箱子小游戏
- 推箱子小游戏--控制台
- 推箱子小游戏
- 推箱子小游戏源码
- 推箱子小游戏实现
- C语言 推箱子小游戏 可重玩 可选关 保存记录
- c语言实现的推箱子小游戏-1
- C语言,用EGE图形库实现推箱子小游戏
- C#游戏编程:《控制台小游戏系列》之《推箱子》
- QT 推箱子小游戏编写
- 推箱子小游戏v1.5
- SGU103
- 号码字符串与BCD编码互转 c#
- 编程珠玑第8章-课后习题10题补充
- 如何预测用户query意图
- android中执行shell
- C++ 小游戏之推箱子
- IIS 5.1成功配置说明
- 从狄仁杰的测字占卜到一淘网的Query分析
- ORA-39213: Metadata processing is not available 解决方法
- 生成CSV
- 从狄仁杰的测字占卜到一淘网的Query分析之大结局
- redhat 5.5系统下安装mw54u无线usb网卡驱动
- volatile关键字的使用
- 把无符号整形字符串转化为整形