一,项目来源
来源:https://www.cnblogs.com/heyu123/p/14844284.html
运行环境:win11,devC++编译器
运行结果:
相关代码:
点击查看代码
#include<iostream>
#include<stdlib.h>
#include<conio.h>
using namespace std;
int map[8][8]={
{1,1,1,1,1,1,1,1},//0 空地
{1,0,0,0,1,0,0,1},//1 墙
{1,0,1,0,1,4,3,1},//3 目的地
{1,0,0,0,0,4,3,1},//4 箱子
{1,0,1,0,1,4,3,1},//5 人
{1,0,0,0,1,0,0,1},//7 箱子和目的地重合
{1,1,1,1,1,5,0,1},//8 人和目的地
{0,0,0,0,1,1,1,1}};
void GamePaint()
{
//输出
for(int i=0;i<8;i++)
{
for(int j=0;j<8;j++)
{
switch(map[i][j])
{
case 0:printf(" ");break;
case 1:printf("■");break;
case 3:printf("");break;
case 4:printf("□");break;
case 5:printf("");break;
case 7:printf("");break;
case 8:printf("");break;
}
}
cout<<endl;
}
}
void GamePlay()
{
int r,c;//人的下标
int flag=0;
for(r=0;r<8;r++)
{
for(c=0;c<8;c++)
{if(map[r][c]==5||map[r][c]==8)
{
flag=1;
break;
}
}
if(flag)
break;
}
cout<<"人的下标:"<<r<<" "<<c;
char key;
key=getch();
switch(key)
{
case 'w':
if(map[r-1][c]==0||map[r-1][c]==3)//人的前面是空地或目的地
{ map[r-1][c]+=5; //人来+5
map[r][c]-=5;//人走-5
}
else if(map[r-1][c]==4||map[r-1][c]==7)//人前面是箱子或箱子加目的地
{
if(map[r-2][c]==0||map[r-2][c]==3)//人前面的前面是空地或目的地
{
map[r-2][c]+=4;
map[r-1][c]+=1;
map[r][c]-=5;
}
}
break;
case 's':
if(map[r+1][c]==0||map[r+1][c]==3)//人的后面是空地或目的地
{ map[r+1][c]+=5; //人来+5
map[r][c]-=5;//人走-5
}
else if(map[r+1][c]==4||map[r+1][c]==7)//人后面是箱子或箱子加目的地
{
if(map[r+2][c]==0||map[r+2][c]==3)//人后面的前面是空地或目的地
{
map[r+2][c]+=4;
map[r+1][c]+=1;
map[r][c]-=5;
}
}
break;
case 'a':
if(map[r][c-1]==0||map[r][c-1]==3)//人的左面是空地或目的地
{ map[r][c-1]+=5; //人来+5
map[r][c]-=5;//人走-5
}
else if(map[r][c-1]==4||map[r][c-1]==7)//人左面是箱子或箱子加目的地
{
if(map[r][c-2]==0||map[r][c-2]==3)//人左面的左面是空地或目的地
{
map[r][c-2]+=4;
map[r][c-1]+=1;
map[r][c]-=5;
}
}
break;
case 'd':
if(map[r][c+1]==0||map[r][c+1]==3)//人的右面是空地或目的地
{ map[r][c+1]+=5; //人来+5
map[r][c]-=5;//人走-5
}
else if(map[r][c+1]==4||map[r][c+1]==7)//人右面是箱子或箱子加目的地
{
if(map[r][c+2]==0||map[r][c+2]==3)//人右面的右面是空地或目的地
{
map[r][c+2]+=4;
map[r][c+1]+=1;
map[r][c]-=5;
}
}
break;
}
}
int main()
{ while(1)//让下面语句不断运行
{system("cls");//清屏函数
GamePaint();
GamePlay();
}
return 0;
}
二,问题分析
主要问题:
1.人物与箱子字符大小不统一(可能因不同环境而异?),导致地图错位,无法实现预期效果
2.游戏中使用的地图是固定的,缺乏多样性
3.游戏中的用户交互(如人物移动、箱子推动等)虽然通过键盘控制实现,但可能缺乏直观的视觉反馈或操作提示
4.缺少“悔棋”设计,走错一步可能导致整局重开
5.游戏中可能缺乏自动保存或手动保存进度的功能
三,程序重构
1.像素大小不一: 等特殊字符与代表空地的“ ”的小不同,导致地图错位。我们可以通过重新调试字符成功达到预期
函数GamPaint
void GamePaint() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
switch (map[i][j]) {
case 0: cout<<" "; break;
case 1: cout<<"■ "; break;
case 3: cout<<" "; break;
case 4: cout<<"□ "; break;
case 5: cout<<" "; break;
case 7: cout<<" "; break;
case 8: cout<<" "; break;
}
}
cout << endl;
}
}
2.撤销上一步操作:我们需要用vector记录每一步的操作,通过一个栈来存储每一步的map状态。以便在按下按键(暂定为使用“f”键)时可以重新打印数组,从而回退到上一步的状态
- SaveState():将当前的map状态保存到history中
- Undo():撤销上一步操作,恢复到上一步的map状态
- GamePlay():在每次操作后调用SaveState()保存当前状态,并在按下“f”键时调用Undo()撤销操作
map状态记录与调用相关函数
void SaveState()
{
vector<vector<int>> currentMap(8, vector<int>(8));
for(int i=0;i<8;i++)
{
for(int j=0;j<8;j++)
{
currentMap[i][j] = map[i][j];
}
}
history.push_back(currentMap);
}
void Undo()
{
if(history.size() > 1)
{
history.pop_back(); // 移除当前状态
vector<vector<int>> previousMap = history.back(); // 获取上一步的状态
for(int i=0;i<8;i++)
{
for(int j=0;j<8;j++)
{
map[i][j] = previousMap[i][j];
}
}
}
}
void GamePlay()//游戏实现函数,调用以上两个函数已完成“悔棋”功能
{
case 'f': // 撤销上一步操作
Undo();
return;
}
3.引导性与地图单一性:通过增加游戏初始界面,基于用户选择与基本引导来优化用户体验;同时,丰富游戏地图,并在初始化期间,根据用户选择调用不同的地图
- test1234:存储了多个地图,用户可以通过选择编号切换地图
- StartGame():用户初始界面,给予用户选择与引导
- CheckWin():判断游戏是否结束的函数
引导与地图相关函数
void StartGame()
{
int a = 0;
cout << "——欢迎游玩推箱子小游戏——" << endl;
cout << " (按下wasd控制,f上一步)" << endl;
cout << "—— 输入编号进入游戏 ——" << endl;
cout << "—— 1.simple ——" << endl;
cout << "—— 2.castle ——" << endl;
cout << "—— 3.tight ——" << endl;
cout << "—— 4.double ——" << endl;
cin >> a;
switch (a) {
case 1: memcpy(map, test1, sizeof(test1)); break;
case 2: memcpy(map, test2, sizeof(test2)); break;
case 3: memcpy(map, test3, sizeof(test3)); break;
case 4: memcpy(map, test4, sizeof(test4)); break;
default: memcpy(map, test1, sizeof(test1)); break;
}
}
bool CheckWin()
{
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 8; j++)
{
if(map[i][j] == 3) // 如果还有目的地
{
return false;
}
}
}
return true;
}
四,二次开发项目测试
全部代码
#include<iostream>
#include<stdlib.h>
#include<conio.h>
#include<vector>
#include<cstring> // memcpy函数
#include<windows.h> // Sleep函数
using namespace std;
int map[8][8]; // 当前地图
int test4[8][8] = { // double
{1,1,1,1,1,1,1,1},
{1,0,0,0,1,0,0,1},
{1,0,1,0,1,4,3,1},
{1,0,0,0,0,4,3,1},
{1,0,1,0,1,4,3,1},
{1,0,0,0,1,0,0,1},
{1,1,1,1,1,5,0,1},
{0,0,0,0,1,1,1,1}
};
int test2[8][8] = { // castle
{0,0,1,1,1,1,0,0},
{0,0,1,3,3,1,0,0},
{0,1,1,0,3,1,1,0},
{0,1,0,0,4,3,1,0},
{1,1,0,4,0,0,1,1},
{1,0,0,1,4,4,0,1},
{1,0,0,5,0,0,0,1},
{1,1,1,1,1,1,1,1}
};
int test1[8][8] = { // simple
{1,1,1,1,1,1,1,1},
{1,0,4,0,0,0,3,1},
{1,0,0,0,0,0,0,1},
{1,0,3,0,4,0,0,1},
{1,0,0,0,4,0,0,1},
{1,0,3,0,0,0,0,1},
{1,0,0,0,0,0,5,1},
{1,1,1,1,1,1,1,1}
};
int test3[8][8] = { // tight
{0,0,1,1,1,1,0,0},
{0,0,1,5,0,1,0,0},
{1,1,1,0,4,1,0,0},
{1,0,4,4,3,1,1,0},
{1,0,4,3,3,0,1,0},
{1,0,4,3,3,0,1,0},
{1,0,0,0,1,1,1,0},
{1,1,1,1,1,0,0,0}
};
vector<vector<vector<int> > > history; // 用于存储每一步的map状态
void GamePaint()
{
// 输出
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 8; j++)
{
switch(map[i][j])
{
case 0: cout << " "; break;
case 1: cout << "■ "; break;
case 3: cout << " "; break;
case 4: cout << "□ "; break;
case 5: cout << " "; break;
case 7: cout << " "; break;
case 8: cout << " "; break;
}
}
cout << endl;
}
}
void SaveState()
{
vector<vector<int> > currentMap(8, vector<int>(8));
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 8; j++)
{
currentMap[i][j] = map[i][j];
}
}
history.push_back(currentMap);
}
void Undo()
{
if(history.size() > 1)
{
history.pop_back(); // 移除当前状态
vector<vector<int> > previousMap = history.back(); // 获取上一步的状态
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 8; j++)
{
map[i][j] = previousMap[i][j];
}
}
}
}
bool CheckWin()
{
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 8; j++)
{
if(map[i][j] == 3) // 如果还有目的地
{
return false;
}
}
}
return true;
}
void GamePlay()
{
int r, c; // 人的下标
int flag = 0;
for(r = 0; r < 8; r++)
{
for(c = 0; c < 8; c++)
{
if(map[r][c] == 5 || map[r][c] == 8)
{
flag = 1;
break;
}
}
if(flag)
break;
}
cout << "人的下标:" << r << " " << c;
char key;
key = getch();
switch(key)
{
case 'w':
if(map[r-1][c] == 0 || map[r-1][c] == 3)
{
map[r-1][c] += 5; // 人来+5
map[r][c] -= 5; // 人走-5
}
else if(map[r-1][c] == 4 || map[r-1][c] == 7)
{
if(map[r-2][c] == 0 || map[r-2][c] == 3)
{
map[r-2][c] += 4;
map[r-1][c] += 1;
map[r][c] -= 5;
}
}
break;
case 's':
if(map[r+1][c] == 0 || map[r+1][c] == 3)
{
map[r+1][c] += 5; // 人来+5
map[r][c] -= 5; // 人走-5
}
else if(map[r+1][c] == 4 || map[r+1][c] == 7)
{
if(map[r+2][c] == 0 || map[r+2][c] == 3)
{
map[r+2][c] += 4;
map[r+1][c] += 1;
map[r][c] -= 5;
}
}
break;
case 'a':
if(map[r][c-1] == 0 || map[r][c-1] == 3)
{
map[r][c-1] += 5; // 人来+5
map[r][c] -= 5; // 人走-5
}
else if(map[r][c-1] == 4 || map[r][c-1] == 7)
{
if(map[r][c-2] == 0 || map[r][c-2] == 3)
{
map[r][c-2] += 4;
map[r][c-1] += 1;
map[r][c] -= 5;
}
}
break;
case 'd':
if(map[r][c+1] == 0 || map[r][c+1] == 3)
{
map[r][c+1] += 5; // 人来+5
map[r][c] -= 5; // 人走-5
}
else if(map[r][c+1] == 4 || map[r][c+1] == 7)
{
if(map[r][c+2] == 0 || map[r][c+2] == 3)
{
map[r][c+2] += 4;
map[r][c+1] += 1;
map[r][c] -= 5;
}
}
break;
case 'f': // 撤销上一步操作
Undo();
return;
}
SaveState(); // 保存当前状态
}
void StartGame()
{
int a = 0;
cout << "——欢迎游玩推箱子小游戏——" << endl;
cout << " (按下wasd控制,f上一步)" << endl;
cout << "—— 输入编号进入游戏 ——" << endl;
cout << "—— 1.simple ——" << endl;
cout << "—— 2.castle ——" << endl;
cout << "—— 3.tight ——" << endl;
cout << "—— 4.double ——" << endl;
cin >> a;
switch (a) {
case 1: memcpy(map, test1, sizeof(test1)); break;
case 2: memcpy(map, test2, sizeof(test2)); break;
case 3: memcpy(map, test3, sizeof(test3)); break;
case 4: memcpy(map, test4, sizeof(test4)); break;
default: memcpy(map, test1, sizeof(test1)); break;//输错默认进行图1
}
}
int main()
{
StartGame(); // 开始界面
SaveState(); // 保存初始状态
while(1) // 让下面语句不断运行
{
system("cls");
GamePaint();
if(CheckWin())
{
cout << "恭喜你,游戏成功!!!!" << endl;
break;
}
GamePlay();
}
return 0;
}
项目截图:
五,项目总结与反思
- 使用一个容器(vector<vector<vector >>)来存储每一步的 map 状态,且map状态保存与恢复需要确保每次保存的状态是独立的,避免引用问题;
- 通过这次二次开发,我学到了如何设计“状态管理”、“目标检测”等功能。这些设计模式可以推广到其他应用程序中,具有很高的通用性。通过尝试逆向开发,我也以用户的视角注意到了更多作为开发者容易忽视的部分,逆向软件工程的本质是从需求出发,分析问题,设计解决方案,从而不断地优化和改进。
来源链接:https://www.cnblogs.com/123456789syf/p/18737535
© 版权声明
本站所有资源来自于网络,仅供学习与参考,请勿用于商业用途,否则产生的一切后果将由您(转载者)自己承担!
如有侵犯您的版权,请及时联系3500663466#qq.com(#换@),我们将第一时间删除本站数据。
如有侵犯您的版权,请及时联系3500663466#qq.com(#换@),我们将第一时间删除本站数据。
THE END
暂无评论内容