c++、c实现推箱子小游戏

  经过四次的修改和优化,终于将推箱子这个游戏完整的写出来了,今天就像大家分享一下这个游戏的编写。

  这个游戏界面的编写总的来说不困难,主要是推动箱子的算法。

  (1)利用数组和windows api 即可写出界面

    

 1 #define N 15
 2 #define M 15
 3 int map[N][M] = {
 4     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
 5     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
 6     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
 7     { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 },//0->空白
 8     { 0, 0, 0, 0, 1, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0 },//1->墙
 9     { 0, 0, 0, 0, 1, 0, 3, 0, 0, 1, 0, 0, 0, 0, 0 },//2->人
10     { 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0 },//3->箱子
11     { 0, 0, 0, 1, 4, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0 },//4->位置
12     { 0, 0, 0, 1, 4, 3, 0, 0, 1, 0, 1, 0, 0, 0, 0 },
13     { 0, 0, 0, 1, 4, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0 },
14     { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
15     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
16     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
17     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
18     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
19 
20 void PushBox::Color(int m)//封装到PushBox类里
21 {
22     HANDLE consolehwnd;//创建句柄,详细句柄知识,请百度一下或查MSDN
23     consolehwnd = GetStdHandle(STD_OUTPUT_HANDLE);//实例化句柄
24     SetConsoleTextAttribute(consolehwnd, m);
25 }
26 
27 
28 
29 void PushBox::Drop(int map[N][M])
30 {
31     int i, j;
32     for (i = 0; i < N; i++)
33     {
34         for (j = 0; j < M; j++)
35             switch (map[i][j])
36         {
37             case 0:    Color(7);           std::cout << "  "; break;
38             case 1:    Color(4);  std::cout << ""; break;
39             case 2: Color(10); std::cout << ""; break;
40             case 3: Color(5);  std::cout << ""; break;
41             case 4: Color(1);  std::cout << ""; break;
42             case 5: Color(7);  std::cout << ""; break;//箱子到达目标位置
43             case 6: Color(10); std::cout << ""; break;//表示人与位置重叠
44 
45         }
46         std::cout << "\n";
47     }
48 }

 

 

 

 

  

 

  (2)推箱子算法:本人比较笨,没有找到捷径,所以就穷举了推箱子步骤,分析如下:

      以人为中心,出现两种可能:人在空位 ②人在目标位置上

       ①有六种可能:(注:x1,y1, x2, y2为坐标的偏移量,i ,为人所在的坐标 )

       

      

     ②人在目标位置上 同样也有六种可能:

        

    用if语句进行对这12中可能进行判断,除了处理这几种能够移动的外,其他没有可能移动,分析清楚,则很容写出移动算法:

        

        

  1 int PushBox::push(int map[N][M],int x1,int x2,int y1,int y2)
  2 {
  3     int i, j;
  4     Postion(map, &i, &j);
  5     /*******************人在空格处*/
  6     if (map[i][j] == 2)
  7     {
  8         //人前是箱子,箱子在空格处
  9         if (map[i + x1][j + y1] == 3)
 10         {    //箱子前面为空格S
 11             if (map[i + x2][j + y2] == 0)
 12             {
 13                 map[i][j] = 0;
 14                 map[i + x1][j + y1] = 2;
 15                 map[i + x2][j + y2] = 3;
 16                 return 1;
 17             }
 18             //箱子前面为位置
 19             if (map[i + x2][j + y2] == 4)
 20             {
 21                 map[i][j] = 0;
 22                 map[i + x1][j + y1] = 2;
 23                 map[i + x2][j + y2] = 5;
 24                 return 1;
 25             }
 26         }
 27         //人前为箱子,箱子在位置上
 28         if (map[i + x1][j + y1] == 5)
 29         {
 30             //箱子前面为空
 31             if (map[i + x2][j + y2] == 0)
 32             {
 33                 map[i + x2][j + y2] = 3;
 34                 map[i + x1][j + y1] = 6;
 35                 map[i][j] = 0;
 36                 return 1;
 37 
 38             }
 39             //箱子前面为位置
 40             if (map[i + x2][j + y2] == 4)
 41             {
 42                 map[i][j] = 0;
 43                 map[i + x1][j + y1] = 6;
 44                 map[i + x2][j + y2] = 5;
 45                 return 1;
 46             }
 47 
 48         }
 49         /*--------------------*/
 50         //人前为空格
 51         if (map[i + x1][j + y1] == 0)
 52         {
 53             map[i + x1][j + y1] = 2;
 54             map[i][j] = 0;
 55             return 1;
 56         }
 57         //人前为位置
 58         if (map[i + x1][j + y1] == 4)
 59         {
 60             map[i + x1][j + y1] = 6;
 61             map[i][j] = 0;
 62             return 1;
 63         }
 64         return 0;
 65     }
 66     /*******************人在位置上*/
 67     if (map[i][j] == 6)
 68     {
 69         //位置前面是箱子,箱子在空格
 70         if (map[i + x1][j + y1] == 3)
 71         {
 72             //箱子前面为空格
 73             if (map[i + x2][j + y2] == 0)
 74             {
 75                 map[i][j] = 4;
 76                 map[i + x1][j + y1] = 2;
 77                 map[i + x2][j + y2] = 3;
 78                 return 1;
 79             }
 80             //箱子前面为位置
 81             if (map[i + x2][j + y2] == 4)
 82             {
 83                 map[i][j] = 4;
 84                 map[i + x1][j + y1] = 2;
 85                 map[i + x2][j + y2] = 5;
 86                 return 1;
 87             }
 88         }
 89         //位置前面是箱子,箱子在位置
 90         if (map[i + x1][j + y1] == 5)
 91         {
 92             //箱子前面是空格
 93             if (map[i + x2][j + y2] == 0)
 94             {
 95                 map[i][j] = 4;
 96                 map[i + x1][j + y1] = 6;
 97                 map[i + x2][j + y2] = 3;
 98                 return 1;
 99             }
100             //箱子前面是位置
101             if (map[i + x2][j + y2] == 4)
102             {
103                 map[i][j] = 4;
104                 map[i + x1][j + y1] = 6;
105                 map[i + x2][j + y2] = 5;
106                 return 1;
107             }
108         }
109 
110         /*-----------------*/
111         //人前为位置
112         if (map[i + x1][j + y1] == 4)
113         {
114             map[i + x1][j + y1] = 6;
115             map[i][j] = 4;
116             return 1;
117         }
118         //人前为空格
119         if (map[i + x1][j + y1] == 0)
120         {
121             map[i + x1][j + y1] = 2;
122             map[i][j] = 4;
123             return 1;
124         }
125         return 0;
126     }return 0;
127 }

 

        

    这里写返回1值既可以减少系统的判断,还可以判断是否执行了移动操作,方便统计移动的步数

 

    (3)编写获取人的位置函数、判断是否获胜

      获取人的位置,只需要判断得到地图中6或者2其中一个坐标,由于需要横坐标和纵坐标,所以利用指针得到位置

      

void PushBox::Postion(int map[N][M], int *cl, int *cow)
{
    int i, j;
    for (i = 0; i < N; i++)
    {
        for (j = 0; j < M; j++)
        {
            if (map[i][j] == 2 || map[i][j] == 6)goto ML;
        }
    }ML:
    *cl = i;
    *cow = j;
}

 

    判断是否获胜:即地图中没有目标位置,就获胜,若胜利返回1值,否则返回0;

int PushBox::juide(int map[N][M])
{
    int i, j;
    for (i = 0; i < N; i++)
    {
        for (j = 0; j < M; j++)
        {
            if (map[i][j] == 6)return 0;
            if (map[i][j] == 4)return 0;
        }

        if (i == N - 1 && j == M - 1)return 1;
    }
}

 

 

    (4)编写移动方向算法,并统计执行步数

    

int PushBox::move(int map[N][M], char ch)
{

    static int step = 0;
    int x1, x2, y1, y2;
    switch (ch)
    {
    case 's':
    case 'S': x1 = 1; x2 = 2; y1 = 0; y2 = 0;
        if (push(map, x1, x2, y1, y2)) step++; return step;

    case 'w':
    case 'W': x1 = -1; x2 = -2; y1 = 0; y2 = 0;
        if (push(map,x1,x2,y1,y2)) step++; return step;

    case 'A':
    case 'a': x1 = 0; x2 = 0; y1 = -1; y2 = -2;
        if (push(map,x1,x2,y1,y2)) step++; return step;
    case 'D':
    case 'd': x1 = 0; x2 = 0; y1 = 1; y2 = 2;
        if (push(map,x1,x2,y1,y2)) step++; return step;
    }
}

 

 

 

 

  (5)Push类的封装,将以上的几个方法封装到类里,建立头文件

 1 #include <iostream>
 2 using namespace std;
 3 #include <windows.h>
 4 #include <string.h>
 5 #include <conio.h>
 6 #include <fstream>
 7 #pragma warning(disable:4996)
 8 #define N 15
 9 #define M 15
10 
11 //建立一个推箱子相关操作的类
12 /*--------------------------PushBox类编写--------------------------------------*/
13 /****************************************************************************/
14 class PushBox{
15 public:
16     int move(int map[N][M], char ch);//移动箱子
17     void Drop(int map[N][M]);//箱子界面编写
18     int  juide(int map[N][M]);//判断是否全部移入位置,成功返回1,失败返回0
19 private:
20     int push(int map[N][M],int x1,int x2,int y1,int y2);
21     void Color(int m);
22     void Postion(int map[N][M], int *i, int *j);
23 };

 

  (6)主函数的编写:这里我将地图放入外部txt文件中,方便以后添加地图

  

#include <iostream>
using namespace std;
#include <windows.h>
#include <string.h>
#include <conio.h>
#include "Push.h"
#pragma warning(disable:4996)
#define N 15
#define M 15

int read_map(int *p);
void change_map(int *p, char *temp);
//主函数

int main()
{
    int map[N][M] = { 0 };
    PushBox box;
    int *p = &map[0][0];
    int select = read_map(p);
    int step = 0;
    while (1)
    {
        cout << "你选择的关卡是:" << select << endl;
        cout << "你走了:" << step << "";
        box.Drop(map);
        cout << "W-----向上           S------向下" << endl;
        cout << "A-----向左           S------向右" << endl;
        char ch;
        ch = _getch();
        step = box.move(map, ch);
        system("cls");
        if (box.juide(map))break;
    }
    std::cout << "你赢了!";
    std::cout << "共走:" << step << "";
    getchar();
    getchar();
}



/*选择关卡*/
int read_map(int *p)
{
    int ch;
    cout << "请输入关卡:";
    cin >> ch;
    char temp[15];
    switch (ch)
    {
    case 1:strcpy(temp, "map/map_1.txt"); change_map(p, temp); system("cls"); return 1;
    case 2:strcpy(temp, "map/map_2.txt"); change_map(p, temp); system("cls"); return 1;
    }

}
/*打开关卡*/
void change_map(int *p, char *temp)
{
    ifstream infile;
    infile.open(temp);
    while (!infile.eof())
    {
        infile >> *p;
        p++;
    }
    infile.close();
}

 

  程序分析图:

      

 

  经过调试运行,暂时还没有发现BUG,一下是源代码,希望大家发现了以后给我留言,写得不好的地方希望大家能够指出

   源文件

 1 /**************************************************
 2 * Name            : 推箱子
 3 * FileName        : PushBox.cpp
 4 * Author        : 和导
 5 * Version        : V4.0
 6 * Date            :
 7 *Description    : 制作一个简单的推箱子
 8 
 9 *Function List  : (1)void read_map(int *p);
10                   (2)void change_map(int *p, char *temp);
11 --------------
12 History:
13 <author>        <time>            <reviseInf>
14 和导            2016/4/1         把类封装到头文件中,重写推函数,添加地图
15 ****************************************************/
16 
17 
18 #include <iostream>
19 using namespace std;
20 #include <windows.h>
21 #include <string.h>
22 #include <conio.h>
23 #include "Push.h"
24 #pragma warning(disable:4996)
25 #define N 15
26 #define M 15
27 
28 int read_map(int *p);
29 void change_map(int *p, char *temp);
30 //主函数
31 
32 int main()
33 {
34     int map[N][M] = { 0 };
35     PushBox box;
36     int *p = &map[0][0];
37     int select = read_map(p);
38     int step = 0;
39     while (1)
40     {
41         cout << "你选择的关卡是:" << select << endl;
42         cout << "你走了:" << step << "";
43         box.Drop(map);
44         cout << "W-----向上           S------向下" << endl;
45         cout << "A-----向左           S------向右" << endl;
46         char ch;
47         ch = _getch();
48         step = box.move(map, ch);
49         system("cls");
50         if (box.juide(map))break;
51     }
52     std::cout << "你赢了!";
53     std::cout << "共走:" << step << "";
54     getchar();
55     getchar();
56 }
57 
58 
59 
60 /*选择关卡*/
61 int read_map(int *p)
62 {
63     int ch;
64     cout << "请输入关卡:";
65     cin >> ch;
66     char temp[15];
67     switch (ch)
68     {
69     case 1:strcpy(temp, "map/map_1.txt"); change_map(p, temp); system("cls"); return 1;
70     case 2:strcpy(temp, "map/map_2.txt"); change_map(p, temp); system("cls"); return 1;
71     }
72 
73 }
74 /*打开关卡*/
75 void change_map(int *p, char *temp)
76 {
77     ifstream infile;
78     infile.open(temp);
79     while (!infile.eof())
80     {
81         infile >> *p;
82         p++;
83     }
84     infile.close();
85 }
View Code

 

 头文件   

  1 #include <iostream>
  2 using namespace std;
  3 #include <windows.h>
  4 #include <string.h>
  5 #include <conio.h>
  6 #include <fstream>
  7 #pragma warning(disable:4996)
  8 #define N 15
  9 #define M 15
 10 
 11 //建立一个推箱子相关操作的类
 12 /*--------------------------PushBox类编写--------------------------------------*/
 13 /****************************************************************************/
 14 class PushBox{
 15 public:
 16     int move(int map[N][M], char ch);//移动箱子
 17     void Drop(int map[N][M]);//箱子界面编写
 18     int  juide(int map[N][M]);//判断是否全部移入位置,成功返回1,失败返回0
 19 private:
 20     int push(int map[N][M],int x1,int x2,int y1,int y2);
 21     void Color(int m);
 22     void Postion(int map[N][M], int *i, int *j);
 23 };
 24 
 25 int PushBox::move(int map[N][M], char ch)
 26 {
 27 
 28     static int step = 0;
 29     int x1, x2, y1, y2;
 30     switch (ch)
 31     {
 32     case 's':
 33     case 'S': x1 = 1; x2 = 2; y1 = 0; y2 = 0;
 34         if (push(map, x1, x2, y1, y2)) step++; return step;
 35 
 36     case 'w':
 37     case 'W': x1 = -1; x2 = -2; y1 = 0; y2 = 0;
 38         if (push(map,x1,x2,y1,y2)) step++; return step;
 39 
 40     case 'A':
 41     case 'a': x1 = 0; x2 = 0; y1 = -1; y2 = -2;
 42         if (push(map,x1,x2,y1,y2)) step++; return step;
 43     case 'D':
 44     case 'd': x1 = 0; x2 = 0; y1 = 1; y2 = 2;
 45         if (push(map,x1,x2,y1,y2)) step++; return step;
 46     }
 47 }
 48 
 49 void PushBox::Drop(int map[N][M])
 50 {
 51     int i, j;
 52     for (i = 0; i < N; i++)
 53     {
 54         for (j = 0; j < M; j++)
 55             switch (map[i][j])
 56         {
 57             case 0:    Color(7);           std::cout << "  "; break;
 58             case 1:    Color(4);  std::cout << ""; break;
 59             case 2: Color(10); std::cout << ""; break;
 60             case 3: Color(5);  std::cout << ""; break;
 61             case 4: Color(1);  std::cout << ""; break;
 62             case 5: Color(7);  std::cout << ""; break;
 63             case 6: Color(10); std::cout << ""; break;
 64 
 65         }
 66         std::cout << "\n";
 67     }
 68 }
 69 
 70 int PushBox::juide(int map[N][M])
 71 {
 72     int i, j;
 73     for (i = 0; i < N; i++)
 74     {
 75         for (j = 0; j < M; j++)
 76         {
 77             if (map[i][j] == 6)return 0;
 78             if (map[i][j] == 4)return 0;
 79         }
 80 
 81         if (i == N - 1 && j == M - 1)return 1;
 82     }
 83 }
 84 
 85 int PushBox::push(int map[N][M],int x1,int x2,int y1,int y2)
 86 {
 87     int i, j;
 88     Postion(map, &i, &j);
 89     /*******************人在空格处*/
 90     if (map[i][j] == 2)
 91     {
 92         //人前是箱子,箱子在空格处
 93         if (map[i + x1][j + y1] == 3)
 94         {    //箱子前面为空格S
 95             if (map[i + x2][j + y2] == 0)
 96             {
 97                 map[i][j] = 0;
 98                 map[i + x1][j + y1] = 2;
 99                 map[i + x2][j + y2] = 3;
100                 return 1;
101             }
102             //箱子前面为位置
103             if (map[i + x2][j + y2] == 4)
104             {
105                 map[i][j] = 0;
106                 map[i + x1][j + y1] = 2;
107                 map[i + x2][j + y2] = 5;
108                 return 1;
109             }
110         }
111         //人前为箱子,箱子在位置上
112         if (map[i + x1][j + y1] == 5)
113         {
114             //箱子前面为空
115             if (map[i + x2][j + y2] == 0)
116             {
117                 map[i + x2][j + y2] = 3;
118                 map[i + x1][j + y1] = 6;
119                 map[i][j] = 0;
120                 return 1;
121 
122             }
123             //箱子前面为位置
124             if (map[i + x2][j + y2] == 4)
125             {
126                 map[i][j] = 0;
127                 map[i + x1][j + y1] = 6;
128                 map[i + x2][j + y2] = 5;
129                 return 1;
130             }
131 
132         }
133         /*--------------------*/
134         //人前为空格
135         if (map[i + x1][j + y1] == 0)
136         {
137             map[i + x1][j + y1] = 2;
138             map[i][j] = 0;
139             return 1;
140         }
141         //人前为位置
142         if (map[i + x1][j + y1] == 4)
143         {
144             map[i + x1][j + y1] = 6;
145             map[i][j] = 0;
146             return 1;
147         }
148         return 0;
149     }
150     /*******************人在位置上*/
151     if (map[i][j] == 6)
152     {
153         //位置前面是箱子,箱子在空格
154         if (map[i + x1][j + y1] == 3)
155         {
156             //箱子前面为空格
157             if (map[i + x2][j + y2] == 0)
158             {
159                 map[i][j] = 4;
160                 map[i + x1][j + y1] = 2;
161                 map[i + x2][j + y2] = 3;
162                 return 1;
163             }
164             //箱子前面为位置
165             if (map[i + x2][j + y2] == 4)
166             {
167                 map[i][j] = 4;
168                 map[i + x1][j + y1] = 2;
169                 map[i + x2][j + y2] = 5;
170                 return 1;
171             }
172         }
173         //位置前面是箱子,箱子在位置
174         if (map[i + x1][j + y1] == 5)
175         {
176             //箱子前面是空格
177             if (map[i + x2][j + y2] == 0)
178             {
179                 map[i][j] = 4;
180                 map[i + x1][j + y1] = 6;
181                 map[i + x2][j + y2] = 3;
182                 return 1;
183             }
184             //箱子前面是位置
185             if (map[i + x2][j + y2] == 4)
186             {
187                 map[i][j] = 4;
188                 map[i + x1][j + y1] = 6;
189                 map[i + x2][j + y2] = 5;
190                 return 1;
191             }
192         }
193 
194         /*-----------------*/
195         //人前为位置
196         if (map[i + x1][j + y1] == 4)
197         {
198             map[i + x1][j + y1] = 6;
199             map[i][j] = 4;
200             return 1;
201         }
202         //人前为空格
203         if (map[i + x1][j + y1] == 0)
204         {
205             map[i + x1][j + y1] = 2;
206             map[i][j] = 4;
207             return 1;
208         }
209         return 0;
210     }return 0;
211 }
212 
213 void PushBox::Postion(int map[N][M], int *cl, int *cow)
214 {
215     int i, j;
216     for (i = 0; i < N; i++)
217     {
218         for (j = 0; j < M; j++)
219         {
220             if (map[i][j] == 2 || map[i][j] == 6)goto ML;
221         }
222     }ML:
223     *cl = i;
224     *cow = j;
225     ;
226 }
227 
228 void PushBox::Color(int m)
229 {
230     HANDLE consolehwnd;//创建句柄,详细句柄知识,请百度一下或查MSDN
231     consolehwnd = GetStdHandle(STD_OUTPUT_HANDLE);//实例化句柄
232     SetConsoleTextAttribute(consolehwnd, m);
233 }
View Code

 

两个地图张

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    0    0    0    0    0    0    0
0    0    0    0    0    1    4    1    0    0    0    0    0    0    0
0    0    0    0    0    1    0    1    0    0    0    0    0    0    0
0    0    1    1    1    1    3    1    1    1    1    0    0    0    0
0    0    1    4    0    0    3    2    3    4    1    0    0    0    0
0    0    1    1    1    1    1    3    1    1    1    0    0    0    0
0    0    0    0    0    0    1    0    1    0    0    0    0    0    0
0    0    0    0    0    0    1    4    1    0    0    0    0    0    0
0    0    0    0    0    0    1    1    1    0    0    0    0    0    0
View Code

 

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    0    0    0    0    0    0    0
0    0    0    1    2    0    0    1    0    0    0    0    0    0    0
0    0    0    1    0    3    3    1    0    1    1    1    0    0    0
0    0    0    1    0    3    0    1    0    1    4    1    0    0    0
0    0    0    1    1    1    0    1    1    1    4    1    0    0    0
0    0    0    0    1    1    0    0    0    0    4    1    0    0    0
0    0    0    0    1    0    0    0    1    0    0    1    0    0    0
0    0    0    0    1    0    0    0    1    1    1    1    0    0    0
0    0    0    0    1    1    1    1    1    0    0    0    0    0    0    
View Code

 

 文件放置如图:

 

 

posted @ 2016-04-01 16:29  梵高  阅读(23478)  评论(0编辑  收藏  举报