游戏简介
经典的推箱子是一个来自日本的古老游戏,目的是在训练你的逻辑思考能力。箱子只可以推, 不可以拉, 而且一次只能推动一个,胜利条件就是把所有的箱子都推到目的地。
思路
模拟题。难点在于推箱子的动作,如果箱子前方是箱子或者墙壁都不能被推动,是目的地或空地可以。撤回操作是通过一个三维数组记录每一步来实现的,貌似使用起来非常玄学,我都懒得调了。
代码
main.cpp
1 #include"main.h" 2 #include"GoBack.h" 3 #include"Intruduce.h" 4 #include"PlayGame.h" 5 6 int map1[ROW][COL] = { 7 { 0,0,1,1,1,0,0,0}, //0代表空白 8 { 0,0,1,2,1,0,0,0}, //1代表墙 9 { 0,0,1,0,1,1,1,1}, //3代表箱子 10 { 1,1,1,3,3,0,2,1}, 11 { 1,2,0,3,6,1,1,1}, 12 { 1,1,1,1,3,1,0,0}, 13 { 0,0,0,1,2,1,0,0}, 14 { 0,0,0,1,1,1,0,0} }; 15 int map2[ROW][COL] = { 16 { 0,1,1,1,1,1,1,0 }, //0代表空白 17 { 0,1,0,0,0,0,1,1 }, //1代表墙 18 { 1,1,2,1,1,3,0,1 }, //2代表目的地 19 { 1,0,2,2,3,0,0,1 }, //3代表箱子 20 { 1,0,0,1,3,0,0,1 }, //6代表人 21 { 1,0,0,6,0,1,1,1 }, 22 { 1,1,1,1,1,1,0,0 } }; 23 int map3[ROW][COL] = { 24 { 1,1,1,1,1,1,1,1}, //0代表空白 25 { 1,1,0,6,0,1,1,1}, //1代表墙 26 { 1,1,3,1,3,0,0,1}, //2代表目的地 27 { 1,0,0,0,0,1,0,1}, //3代表箱子 28 { 1,1,2,2,3,3,2,1}, //6代表人 29 30 { 1,1,0,2,0,1,1,1}, 31 { 1,1,1,0,0,1,1,1}, 32 { 1,1,1,1,1,1,1,1} }; 33 34 int lastmap1[STEP][ROW][COL]; 35 int lastmap2[STEP][ROW][COL]; 36 int lastmap3[STEP][ROW][COL]; 37 int stepNumber = 0; //步数 38 int flag = 0; //是否按ESC退出 39 40 41 int main() 42 { 43 int select; 44 45 intruduce(); 46 scanf_s("%d", &select); 47 system("cls"); 48 switch (select) 49 { 50 case 1: 51 gotoxy(0, 0); 52 playGame(map1, lastmap1); 53 break; 54 case 2: 55 gotoxy(0, 0); 56 playGame(map2, lastmap2); 57 break; 58 case 3: 59 gotoxy(0, 0); 60 playGame(map3, lastmap3); 61 break; 62 default: 63 break; 64 } 65 66 getchar(); 67 return 0; 68 }
PlayGame.cpp
1 #include"main.h" 2 #include"PlayGame.h" 3 #include"GoBack.h" 4 #include"Intruduce.h" 5 6 //打印当前地图 7 void DrawMap(int map[][COL]) 8 { 9 for (int i = 0; i < ROW; i++) 10 { 11 for (int j = 0; j < COL; j++) 12 { 13 switch (map[i][j]) 14 { 15 case 0: 16 printf(" "); 17 break; 18 case 1: 19 printf("■"); 20 break; 21 case 2: 22 printf("☆"); 23 break; 24 case 3: 25 case 5: 26 printf("□"); 27 break; 28 case 6: 29 case 8: 30 printf("♀"); 31 break; 32 } 33 } 34 printf(" "); 35 } 36 } 37 38 //得到人的当前位置 39 void position(int *pRow, int *pCol, int map[][COL]) 40 { 41 for (int i = 0; i < ROW; i++) 42 { 43 for (int j = 0; j < COL; j++) 44 { 45 if (map[i][j] == 6 || map[i][j] == 8) 46 { 47 *pRow = i; 48 *pCol = j; 49 break; //由于最多只有一个,所以找到一个即可以跳出循环 50 } 51 } 52 } 53 } 54 55 //控制人的移动 56 void move(int *pRow, int *pCol, int map[][COL], int lastmap[][ROW][COL]) 57 { 58 int r = *pRow, c = *pCol; 59 char ch = _getch(); 60 61 reserveMap(map, lastmap); 62 switch (ch) 63 { 64 case 'W': 65 case 'w': 66 if ((r > 0) && (map[r - 1][c] == 0 || map[r - 1][c] == 2)) //上面第一个为空地或目的地,人上移 67 { 68 map[r - 1][c] += 6; 69 map[r][c] -= 6; 70 } 71 else if ((r > 0) && (map[r - 1][c] == 3 || map[r - 1][c] == 5)) //上面一个是箱子,要先判断箱子上方的情况 72 { 73 if ((r > 1) && (map[r - 2][c] == 0 || map[r - 2][c] == 2)) //如果箱子箱子上方是空的或目的地 74 { 75 map[r - 2][c] += 3; //箱子移来标值加3 76 map[r - 1][c] += 3; //箱子移走-3,人以来+6 77 map[r][c] -= 6; 78 } 79 } 80 system("cls"); 81 DrawMap(map); 82 stepNumber++; 83 break; 84 case 'S': 85 case 's': 86 if ((r < ROW - 1) && (map[r + 1][c] == 0 || map[r + 1][c] == 2)) //上面第一个为空地或目的地,人上移 87 { 88 map[r + 1][c] += 6; 89 map[r][c] -= 6; 90 } 91 else if ((r < ROW - 1) && (map[r + 1][c] == 3 || map[r + 1][c] == 5)) //上面一个是箱子,要先判断箱子上方的情况 92 { 93 if ((r < ROW - 2) && (map[r + 2][c] == 0 || map[r + 2][c] == 2)) //如果箱子箱子上方是空的或目的地 94 { 95 map[r + 2][c] += 3; //箱子移来标值加3 96 map[r + 1][c] += 3; //箱子移走-3,人以来+6 97 map[r][c] -= 6; 98 } 99 } 100 system("cls"); 101 DrawMap(map); 102 stepNumber++; 103 break; 104 case 'A': 105 case 'a': 106 if ((c > 0) && (map[r][c - 1] == 0 || map[r][c - 1] == 2)) //上面第一个为空地或目的地,人上移 107 { 108 map[r][c - 1] += 6; 109 map[r][c] -= 6; 110 } 111 else if ((c > 0) && (map[r][c - 1] == 3 || map[r][c - 1] == 5)) //上面一个是箱子,要先判断箱子上方的情况 112 { 113 if ((c > 1) && (map[r][c - 2] == 0 || map[r][c - 2] == 2)) //如果箱子箱子上方是空的或目的地 114 { 115 map[r][c - 2] += 3; //箱子移来标值加3 116 map[r][c - 1] += 3; //箱子移走-3,人以来+6 117 map[r][c] -= 6; 118 } 119 } 120 system("cls"); 121 DrawMap(map); 122 stepNumber++; 123 break; 124 case 'D': 125 case 'd': 126 if ((c < COL - 1) && (map[r][c + 1] == 0 || map[r][c + 1] == 2)) //上面第一个为空地或目的地,人上移 127 { 128 map[r][c + 1] += 6; 129 map[r][c] -= 6; 130 } 131 else if ((c < COL - 1) && (map[r][c + 1] == 3 || map[r][c + 1] == 5)) //上面一个是箱子,要先判断箱子上方的情况 132 { 133 if ((c < COL - 2) && (map[r][c + 2] == 0 || map[r][c + 2] == 2)) //如果箱子箱子上方是空的或目的地 134 { 135 map[r][c + 2] += 3; //箱子移来标值加3 136 map[r][c + 1] += 3; //箱子移走-3,人以来+6 137 map[r][c] -= 6; 138 } 139 } 140 system("cls"); 141 DrawMap(map); 142 stepNumber++; 143 break; 144 case 'K': 145 case 'k': 146 stepNumber--; 147 if (stepNumber < 0) //处理第一步就撤回的情况 148 { 149 printf("Can not back!"); 150 stepNumber++; 151 break; 152 } 153 goBack(map, lastmap); 154 system("cls"); 155 DrawMap(map); 156 if (stepNumber == 0) 157 { 158 gotoxy(20, 20); 159 printf("Can not back!"); 160 stepNumber++; 161 } 162 break; 163 case 'Q': 164 case 'q': 165 flag = 1; 166 break; 167 default: 168 break; 169 } 170 } 171 172 //判断是否已获胜 173 bool testWin(int *pRow, int *pCol, int map[][COL]) 174 { 175 int i, j, count = 0; //count表示未填目的地的数量 176 int r = *pRow, c = *pCol; 177 for (i = 0; i < ROW; i++) 178 for (j = 0; j < COL; j++) 179 if (map[i][j] == 2) 180 count++; 181 if ((!count) && (map[r][c] != 8)) // 182 return true; //目的地被填满,返回true 183 else 184 return false; //还未被填满,放回flase 185 } 186 187 //玩游戏 188 void playGame(int map[][COL], int lastmap[][ROW][COL]) 189 { 190 int pRow, pCol; 191 192 DrawMap(map); 193 position(&pRow, &pCol, map); 194 do 195 { 196 move(&pRow, &pCol, map, lastmap); 197 position(&pRow, &pCol, map); 198 } while (!testWin(&pRow, &pCol, map) && (flag == 0)); 199 if (testWin(&pRow, &pCol, map) == 1) 200 { 201 printf("You win! "); 202 getchar(); 203 } 204 }
Intruduce.cpp
1 #include"main.h" 2 #include"Intruduce.h" 3 4 void gotoxy(int x, int y)//函数gotoxy:定义光标位置 5 { 6 COORD coord;//坐标系coord 7 HANDLE handle; 8 9 coord.X = x;//横坐标X 10 coord.Y = y;//纵坐标 y 11 handle = GetStdHandle(STD_OUTPUT_HANDLE); 12 SetConsoleCursorPosition(handle, coord); 13 } 14 15 void hidecursor()//函数hidecursor:隐藏光标 16 { 17 CONSOLE_CURSOR_INFO curinfo; 18 HANDLE Out; 19 20 Out = GetStdHandle(STD_OUTPUT_HANDLE); 21 curinfo.dwSize = 1;//光标百分比厚度:1~100 22 curinfo.bVisible = 0;//是否可见 23 SetConsoleCursorInfo(Out, &curinfo); 24 } 25 26 void intruduce() 27 { 28 int i; 29 system("cls"); 30 HANDLE consolehwnd;//创建句柄 31 consolehwnd = GetStdHandle(STD_OUTPUT_HANDLE); 32 SetConsoleTextAttribute(consolehwnd, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); 33 //设置为亮白色 34 35 hidecursor(); 36 for (i = 14; i < 39; i++) 37 { 38 gotoxy(i * 2, 4); 39 printf("■"); 40 } 41 42 for (i = 5; i < 20; i++) 43 { 44 gotoxy(28, i); 45 printf("■"); 46 gotoxy(76, i); 47 printf("■"); 48 } 49 50 gotoxy(47, 5); 51 printf("推箱子1.0"); 52 53 for (i = 15; i < 38; i++) 54 { 55 gotoxy(i * 2, 6); 56 printf("■"); 57 } 58 gotoxy(47, 7); 59 printf("规则说明"); 60 61 gotoxy(30, 9); 62 printf("1.共有三个关卡"); 63 gotoxy(30, 10); 64 printf("2.按1选择关卡,按2选择关卡二,按3选择关卡三"); 65 gotoxy(30, 11); 66 printf("3.WSAD控制上下左右,K撤回,Q退出"); 67 gotoxy(30, 12); 68 printf("4.进入游戏前请关闭中文输入法"); 69 70 71 72 for (i = 15; i < 38; i++) 73 { 74 gotoxy(i * 2, 17); 75 printf("■"); 76 } 77 78 for (i = 14; i < 39; i++) 79 { 80 gotoxy(i * 2, 20); 81 printf("■"); 82 } 83 84 gotoxy(49, 18); 85 printf("关卡:"); 86 }
GoBack.cpp
1 #include"main.h" 2 #include"GoBack.h" 3 4 //将map保存到lastmap 5 void reserveMap(int map[][COL], int lastmap[][ROW][COL]) 6 { 7 for (int i = 0; i < ROW; i++) 8 for (int j = 0; j < COL; j++) 9 lastmap[stepNumber][i][j] = map[i][j]; 10 } 11 12 //将lastmap还原到map 13 void goBack(int map[][COL], int lastmap[][ROW][COL]) 14 { 15 //reserveMap(map, lastmap1, stepNumber); 16 for (int i = 0; i < ROW; i++) 17 for (int j = 0; j < COL; j++) 18 map[i][j] = lastmap[stepNumber][i][j]; 19 }
main.h
1 #include<stdio.h> 2 #include<Windows.h> 3 #include<conio.h> 4 #define KIND 3 5 #define STEP 20 6 #define ROW 20 7 #define COL 20 8 9 extern int map1[ROW][COL], map2[ROW][COL], map3[ROW][COL]; //记录初始地图 10 extern int lastmap1[STEP][ROW][COL],lastmap2[STEP][ROW][COL],lastmap3[STEP][ROW][COL]; //记录当前地图的前一幅 11 extern int stepNumber; //步数 12 extern int flag; //是否按ESC退出
PlayGame.h
1 void DrawMap(int map[][COL]); 2 void position(int *pRow, int *pCol, int map[][COL]); 3 void move(int *pRow, int *pCol, int map[][COL], int lastmap[][ROW][COL]); 4 bool testWin(int *pRow, int *pCol, int map[][COL]); 5 void playGame(int map[][COL], int lastmap[][ROW][COL]);
Intruduce.h
1 void gotoxy(int x, int y); 2 void hidecursor(); 3 void intruduce();
GoBack.h
1 #include"main.h" 2 void reserveMap(int map[][COL], int lastmap[][ROW][COL]); 3 void goBack(int map[][COL], int lastmap[][ROW][COL]);
在VS2017里新建项目,添加上面的每一项,复制粘贴,实测能够运行。
参考链接:百度百科 推箱子