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;}



	
				
		
原创粉丝点击