学习心得之——c++用类实现基于控制台的推箱子小游戏

第一次发表博客有点紧张啦!那么今天我们就来讨论一下面向对象中对推箱子小游戏的一个思考。

以下来源于自己的一个作业,可能想法和分析不够完善,如果您有其他想法,欢迎批评交流。

    在推箱子的小游戏中,我设置了两个类Board类和Object类。Board类用提供生成游戏界面和进行游戏的方法,而Object类则是地图上的不同物品。

    在写这个游戏的时候,我发现这个游戏清晰的由两部分组成,第一是由棋盘,第二是由物品(包括人,箱子,墙,空白),而棋盘上包含了这些东西。因此,我可以暂且设计两个类BoardObject。再考虑棋盘,游戏中只需要一个棋盘就行了,每局地图的不同我们可以用指针指向不同的物品来形成。然后考虑Object类,看能否派生出子类。由于该游戏只需要控制人的移动(箱子的移动是由于人的移动产生的),所以我们只需要一个移动以及判断移动的函数。再加上这些Object除了名字以外并没有区别,所以并不需要派生出子类,我们仅仅需要在类中添加一个flag标记Object的种类即可。然后考虑如何进行移动,由于棋盘上Object的种类和数量是既定的,所以我们只需要固定数量的对象,然后每次改变棋盘每个位置指向的对象即可。

    然后我们再来找Object有没有其他共性。我们可以发现,由于空白(space)和目的地都是可以走人(以及箱子的),则我们可以再用一个bool变量state标记来区别他们,将目的地看成是一个特殊的space(或者是object,后面你会发现为什么这样说)。若为true,则它为目的地。到了这一步以后,我们很自然的发现,我们同样可以用state来区分箱子是否已经在目的地里了,因此判断方法变得更为简洁。

    在前面说到了,我们可以交换两个pointer指向的对象来实现移动,那么如果人与目的地发生交换或者箱子与目的地发生交换时,指针指向改变,那不是目的地的位置也移动了吗?和前面提到的一样,由于棋盘上的object是既定的,那么state标记为trueobject的数量也是固定的,我们可以每次成功移动都先交换objectstate,在进行指针的交换,那么目的地的位置就是固定的。到了这里,你会发现目的地其实就是statetrueobject(因为墙不发生移动,所以不参与到state的交换),我们每次交换state的过程也就是保证目的地固定的过程(即棋盘上某点指向的对象的state总为true)。

    思考完怎么移动后,我们来考虑移动的规则(因为你只有知道方式,才能去思考该方式对应的规则)。人的每次移动,无非就是三种情况:遇到space(空白),wall(墙)和box(箱子)(按照上述的思路,我们已经认为目的地是特殊的Object,所以不考虑在内),遇到空白很简单,直接按上述移动方式交换;遇到墙不移动;遇到箱子时,因为箱子可以移动(但不可以自发移动),那么此时我们可以将箱子视为人再用人的判断规则去判断(唯一的区别就是如果此时前面也为箱子那么不移动)。我们先判断箱子,若箱子可移动则说明人也可移动,那么先移动箱子再移动人。

    解决了移动方法和移动规则后,只剩下判断是否胜利或者是否失败。这就很简单了:若每个箱子都在目的地上(及每个箱子的state均为true)则胜利;若任意一个箱子的任意两边都是墙,则肯定失败。


    下面附上代码。

 
  
/****************************Author:wangyiheng*************************/
/****************************tuixiangzi***********************************/
/*****************************2018.7.6***********************************/

#include
#include
#include
#include
#include
#include
#include
#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77
#define MIN_LEVEL 1
#define MAX_LEVEL 4
using namespace std ;
void   SelectColor ( int iColor){                  //颜色函数
    HANDLE  hConsole =
         GetStdHandle ((STD_OUTPUT_HANDLE)); //得到控制台输出设备的句柄
     SetConsoleTextAttribute (hConsole, iColor); //设置控制台设备的属性
}
int aiMap1[ 14 ][ 16 ] = {
    { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 1 , 1 , 1 , 2 , 2 , 2 , 2 , 1 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 1 , 3 , 4 , 2 , 1 , 1 , 2 , 1 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 2 , 3 , 4 , 5 , 4 , 2 , 2 , 3 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 2 , 3 , 2 , 4 , 2 , 4 , 3 , 1 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 , 1 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
};
int aiMap2[ 14 ][ 16 ] = {
    { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 2 , 2 , 1 , 1 , 2 , 2 , 2 , 1 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 2 , 2 , 2 , 4 , 2 , 2 , 2 , 1 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 2 , 2 , 1 , 1 , 1 , 2 , 4 , 1 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 2 , 1 , 3 , 3 , 3 , 1 , 2 , 1 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 1 , 1 , 2 , 1 , 3 , 3 , 1 , 1 , 2 , 1 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 1 , 2 , 4 , 2 , 2 , 4 , 2 , 2 , 4 , 2 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 5 , 2 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
};
int aiMap3[ 14 ][ 16 ] = {
    { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 },
{ 0 , 0 , 1 , 1 , 2 , 2 , 1 , 2 , 2 , 1 , 2 , 2 , 2 , 1 , 0 , 0 },
{ 0 , 0 , 1 , 2 , 4 , 2 , 1 , 1 , 1 , 1 , 4 , 2 , 2 , 1 , 0 , 0 },
{ 0 , 0 , 1 , 2 , 2 , 4 , 3 , 3 , 3 , 3 , 2 , 4 , 2 , 1 , 0 , 0 },
{ 0 , 0 , 1 , 1 , 2 , 2 , 2 , 2 , 1 , 2 , 5 , 2 , 1 , 1 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
};
int aiMap4[ 14 ][ 16 ] = {
    { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 1 , 2 , 2 , 2 , 1 , 3 , 2 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 1 , 1 , 2 , 2 , 4 , 3 , 3 , 3 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 1 , 2 , 2 , 4 , 2 , 1 , 6 , 3 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 1 , 2 , 1 , 1 , 4 , 1 , 2 , 1 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 2 , 2 , 2 , 4 , 2 , 2 , 4 , 2 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 2 , 2 , 2 , 1 , 2 , 2 , 2 , 2 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 5 , 2 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
};
class Object {
     int flag; //1为空白 2为墙 3为箱子 4为人
     bool status; //true为目的地
public:
     Object ( int a, bool b) : flag (a), status (b) {}
     int Get_Flag () { return flag; }
     bool Get_Status () { return status; }
     void Change_Status ( bool s) { status = s; }
};
class Board {
    Object * board[ 14 ][ 16 ];
     int x, y; //人的位置坐标
     static int step; //游戏步数
public:
     Board ();
     ~Board ();
     void Input ( char c);
     bool Move_Box ( int begin_x, int begin_y, int end_x, int end_y); //箱子移动及其判断方式
     bool Move ( int begin_x, int begin_y, int end_x, int end_y, char c); //人的移动及其判断方式
     void Print () const ; //打印界面
     bool Judge_Win (); //判断是否胜利
     void Set_game ( int i); //设置游戏关卡数
     void Menu (); //主菜单
     void New_Game ( int i); //开始游戏
     void Fresh (); //清空棋盘以进入下一关
};
int Board::step = 0 ;
void Board::New_Game ( int i) {
     Set_game (i);
     while ( 1 ) {
         Print ();
         char c = _getch ();
         Input (c);
         if ( Judge_Win () && i == MAX_LEVEL) {
            cout << " \t\t 恭喜通关!! \n " ;
             break ;
        }
         if ( Judge_Win ()) {
            i ++ ;
            cout << " \t\t 恭喜过关 下面来到第" << i << "关" << endl;
             Fresh ();
             Set_game (i);
        }
        
    }
}
Board::~Board () {
     for ( int i = 0 ; i < 14 ;i ++ )
         for ( int j = 0 ; j < 16 ;j ++ ) {
             if (board[i][j] != NULL )
             delete board[i][j];
        }
}
Board::Board () {
     for ( int i = 0 ; i < 14 ;i ++ )
         for ( int j = 0 ; j < 16 ;j ++ )
            board[i][j] = NULL ;
}
void Board::Fresh () {
     for ( int i = 0 ; i < 14 ;i ++ )
         for ( int j = 0 ; j < 16 ;j ++ ) {
             if (board[i][j] != NULL )
                 delete board[i][j];
        }
    step = 0 ;
}
void Board::Input ( char c) {
     switch (c) {
     case KEY_LEFT:
         if ( Move (x, y, x, y - 1 , c)) {
            step ++ ;
            y = y - 1 ;
        }
         break ;
     case KEY_UP:
         if ( Move (x, y, x - 1 , y, c)) {
            step ++ ;
            x = x - 1 ;
        }
         break ;
     case KEY_DOWN:
         if ( Move (x, y, x + 1 , y, c)) {
            step ++ ;
            x = x + 1 ;
        }
         break ;
     case KEY_RIGHT:
         if ( Move (x, y, x, y + 1 , c)) {
            step ++ ;
            y = y + 1 ;
        }
         break ;
    }
}
void Board::Set_game ( int l) {
     switch (l) {
     case 1 :
         for ( int i = 0 ;i < 14 ;i ++ )
             for ( int j = 0 ;j < 16 ;j ++ ) {
                 if (aiMap1[i][j] == 1 ) board[i][j] = new Object ( 2 , false ); //设置墙
                 if (aiMap1[i][j] == 2 ) board[i][j] = new Object ( 1 , false ); //设置空白
                 if (aiMap1[i][j] == 3 )board[i][j] = new Object ( 1 , true ); //设置目的地
                 if (aiMap1[i][j] == 4 )board[i][j] = new Object ( 3 , false ); //设置箱子
                 if (aiMap1[i][j] == 5 ) {
                    board[i][j] = new Object ( 4 , false ); //设置人
                    x = i, y = j;
                }
                 if (aiMap1[i][j] == 6 )board[i][j] = new Object ( 3 , true ); //设置已经到达目的地的箱子
            }
         break ;
     case 2 :
         for ( int i = 0 ;i < 14 ;i ++ )
             for ( int j = 0 ;j < 16 ;j ++ ) {
                 if (aiMap2[i][j] == 1 ) board[i][j] = new Object ( 2 , false );
                 if (aiMap2[i][j] == 2 ) board[i][j] = new Object ( 1 , false );
                 if (aiMap2[i][j] == 3 )board[i][j] = new Object ( 1 , true );
                 if (aiMap2[i][j] == 4 )board[i][j] = new Object ( 3 , false );
                 if (aiMap2[i][j] == 5 ) {
                    board[i][j] = new Object ( 4 , false );
                    x = i, y = j;
                }
                 if (aiMap2[i][j] == 6 )board[i][j] = new Object ( 3 , true );
            }
         break ;
     case 3 :
         for ( int i = 0 ;i < 14 ;i ++ )
             for ( int j = 0 ;j < 16 ;j ++ ) {
                 if (aiMap3[i][j] == 1 ) board[i][j] = new Object ( 2 , false );
                 if (aiMap3[i][j] == 2 ) board[i][j] = new Object ( 1 , false );
                 if (aiMap3[i][j] == 3 )board[i][j] = new Object ( 1 , true );
                 if (aiMap3[i][j] == 4 )board[i][j] = new Object ( 3 , false );
                 if (aiMap3[i][j] == 5 ) {
                    board[i][j] = new Object ( 4 , false );
                    x = i, y = j;
                }
                 if (aiMap3[i][j] == 6 )board[i][j] = new Object ( 3 , true );
            }
         break ;
     case 4 :
         for ( int i = 0 ;i < 14 ;i ++ )
             for ( int j = 0 ;j < 16 ;j ++ ) {
                 if (aiMap4[i][j] == 1 ) board[i][j] = new Object ( 2 , false );
                 if (aiMap4[i][j] == 2 ) board[i][j] = new Object ( 1 , false );
                 if (aiMap4[i][j] == 3 )board[i][j] = new Object ( 1 , true );
                 if (aiMap4[i][j] == 4 )board[i][j] = new Object ( 3 , false );
                 if (aiMap4[i][j] == 5 ) {
                    board[i][j] = new Object ( 4 , false );
                    x = i, y = j;
                }
                 if (aiMap4[i][j] == 6 )board[i][j] = new Object ( 3 , true );
            }
         break ;
    }
}
bool Board::Move ( int begin_x, int begin_y, int end_x, int end_y, char c) {
     bool begin = board[begin_x][begin_y]-> Get_Status (), end = board[end_x][end_y]-> Get_Status ();
     //space
     if (board[end_x][end_y]-> Get_Flag () == 1 ) {
        board[begin_x][begin_y]-> Change_Status (end);
        board[end_x][end_y]-> Change_Status (begin);
         swap (board[begin_x][begin_y], board[end_x][end_y]);
         return true ;
    }
     //wall
     else if (board[end_x][end_y]-> Get_Flag () == 2 )
         return false ;
     //box
     else if (board[end_x][end_y]-> Get_Flag () == 3 ) {
         int flag = 0 ;
         switch (c) {
         case KEY_LEFT:
             if ( Move_Box (end_x, end_y, end_x, end_y - 1 ))flag = 1 ;
             break ;
         case KEY_RIGHT:
             if ( Move_Box (end_x, end_y, end_x, end_y + 1 )) flag = 1 ;
             break ;
         case KEY_UP:
             if ( Move_Box (end_x, end_y, end_x - 1 , end_y))flag = 1 ;
             break ;
         case KEY_DOWN:
             if ( Move_Box (end_x, end_y, end_x + 1 , end_y))flag = 1 ;
             break ;
        }
         if (flag) {
            board[begin_x][begin_y]-> Change_Status (end);
            board[end_x][end_y]-> Change_Status (begin);
             swap (board[begin_x][begin_y], board[end_x][end_y]);
             return flag;
        }
    }
     return false ;
}
bool Board::Move_Box ( int begin_x, int begin_y, int end_x, int end_y) {
     if (board[end_x][end_y]-> Get_Flag () == 1 ) {
         bool begin = board[begin_x][begin_y]-> Get_Status (), end = board[end_x][end_y]-> Get_Status ();
        board[begin_x][begin_y]-> Change_Status (end);
        board[end_x][end_y]-> Change_Status (begin);
         swap (board[begin_x][begin_y], board[end_x][end_y]);
         return true ;
    }
     return false ;
}
bool Board::Judge_Win () {
     bool flag = true ;
     for ( int i = 0 ; i < 14 ;i ++ )
         for ( int j = 0 ; j < 16 ;j ++ )
             if (board[i][j] != NULL && board[i][j]-> Get_Flag () == 3 && board[i][j]-> Get_Status () != true )
                flag = false ;
     return flag;
}
void Board::Print () const {
     system ( "cls" );
     for ( int i = 0 ; i < 14 ;i ++ ) {
         for ( int j = 0 ; j < 16 ;j ++ ) {
             if (board[i][j] == NULL )cout << "  " ;
             if (board[i][j] != NULL ) {
                 if (board[i][j]-> Get_Flag () == 2 ) {
                     SelectColor ( 14 ); /*墙*/
                     printf ( "▓" );
                }
                 if (board[i][j]-> Get_Flag () == 1 ) {
                     if (board[i][j]-> Get_Status ()) {
                         SelectColor ( 11 ); /*目的地*/
                         printf ( "○" );
                    }
                     else printf ( "  " );
                }
                 if (board[i][j]-> Get_Flag () == 4 ) {
                     SelectColor ( 10 );
                     printf ( "♀" );
                }
                 if (board[i][j]-> Get_Flag () == 3 ) {
                     if (board[i][j]-> Get_Status () == true ) {
                         SelectColor ( 9 );
                         printf ( "☆" );
                    }
                     else {
                         SelectColor ( 11 );
                         printf ( "●" );
                    }
                }
            }
        }
        cout << endl;
    }
    cout << " \n\n\t\t 已走步数:" << step << endl;
}
void Board::Menu () {
     system ( "cls" );      /*清屏*/
     system ( "color 0E" ); /*设置颜色*/
     printf ( " \n\n\t\t Welcome to play box! \n\n " );
     printf ( " \t\t Person:♀  Wall:▓ Box: ●  Target:○  Reach target:☆ \n " );
     printf ( " \t\t Up:w \n\t\t Down:s \n\t\t Left:a \n\t\t Right:d \n\n " );
     printf ( " \t\t Press number 1 to start new game \n\t\t\n " );
     printf ( " \t\t Press number 2 to choose level \n\t\t\n " );
     printf ( " \t\t Press number 3 to quit from game \n\t\t\n " );
     printf ( " \t\t Press right number to continue:" );
     int i;
    cin >> i;
     switch (i) {
     case 1 :
         New_Game ( 1 );
         break ;
     case 2 :
        cout << " \t\t 请输入进入的关卡(1-4) \n " ;
         int level;
        cin >> level;
         while (level < MIN_LEVEL || level > MAX_LEVEL) {
            cout << " \t\t 输入错误!!请输入重新进入的关卡(1 - 4) \n " ;
            cin >> level;
        }
         New_Game (level);
         break ;
     case 3 :
         exit ( 0 );
    }
}
int main () {
    Board game;
    cout << "begin" << endl;
    game. Menu ();
}


感谢您的观看!!如有错误不足,请您务必不吝赐教!!


你可能感兴趣的:(学习心得之——c++用类实现基于控制台的推箱子小游戏)