上代码
#include <iostream>
using namespace std;
const char gStateData[] = "\
########\n\
# .. p #\n\
# oo #\n\
# #\n\
########";
const int gStateWidth = 8;
const int gStateHeight = 5;
enum Object
{
OBJ_SPACE,
OBJ_WALL,
OBJ_GOAL,
OBJ_BLOCK,
OBJ_BLOCK_ON_GOAL,
OBJ_MAN,
OBJ_MAN_ON_GOAL,
OBJ_UNKNOWN,
};
void initialize(Object* state, int width, int height, const char* stageData);
void draw(const Object* state, int width, int height);
void update(Object* state, char input, int width, int height);
bool checkClear(const Object* state, int width, int height);
int main()
{
// 使用一维数组存放状态数据
Object* state = new Object[gStateWidth * gStateHeight];
// 初始化
initialize(state, gStateWidth, gStateHeight, gStateData);
// 主循环
while (true)
{
// 首先绘制
draw(state, gStateWidth, gStateHeight);
// 通关检测
if (checkClear(state, gStateWidth, gStateHeight))
break;
// 提示如何操作
cout << "a:left s:right w:up z:down. command?" << endl;
char input;
cin >> input;
// 更新
update(state, input ,gStateWidth, gStateHeight);
}
// 通关祝贺信息
cout << "Contratulation's ! you won." << endl;
// 析构
delete[] state;
state = NULL;
// 阻止窗口闪退
system("pause");
return 0;
}
// 初始化函数,根据stateData填充
void initialize(Object* state, int width, int height, const char* stageData)
{
const char* d = stageData;
int x = 0, y = 0;
while ((*d) != '\0')
{
Object t;
switch(*d)
{
case '#': t = OBJ_WALL; break;
case ' ': t = OBJ_SPACE; break;
case 'o': t = OBJ_BLOCK; break;
case 'O': t = OBJ_BLOCK_ON_GOAL; break;
case '.': t = OBJ_GOAL; break;
case 'p': t = OBJ_MAN; break;
case 'P': t = OBJ_MAN_ON_GOAL; break;
case '\n': x = 0; ++y; t = OBJ_UNKNOWN; break;
default: t = OBJ_UNKNOWN; break;
}
++d;
if (t != OBJ_UNKNOWN)
{
state[y * width + x] = t; // 写入
++x;
}
}
}
// 绘制
void draw(const Object* state, int width, int height)
{
// Object的可能值
const char font[] = {' ', '#', '.', 'o', 'O', 'p', 'P'};
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
cout << font[state[i * width + j]];
cout << endl;
}
}
// 根据输入的方向键更新数据
void update(Object* state, char input, int width, int height)
{
int dx = 0, dy = 0;
switch (input)
{
case 'a': dx = -1; break;
case 's': dx = 1; break;
case 'w': dy = -1; break;
case 'z': dy = 1; break;
default:
break;
}
// 查询人物坐标
int sub = 0;
for (; sub < width * height; ++sub)
if (state[sub] == OBJ_MAN || state[sub] == OBJ_MAN_ON_GOAL)
break;
int xPos = sub % width;
int yPos = sub / width;
int xMov = xPos + dx;
int yMov = yPos + dy;
// 检测坐标的合理性
if (xMov < 0 || xMov >= width || yMov < 0 || yMov >= height)
return ;
// 该方向上是空白或者终点,人物则移动
int pPosSub = yPos * width + xPos;
int pMovSub = yMov * width + xMov;
if (state[pMovSub] == OBJ_SPACE || state[pMovSub == OBJ_GOAL])
{
state[pMovSub] = (state[pMovSub] == OBJ_GOAL) ? OBJ_MAN_ON_GOAL : OBJ_MAN;
state[pPosSub] = (state[pPosSub] == OBJ_MAN_ON_GOAL) ? OBJ_GOAL : OBJ_SPACE;
}
// 如果该方向上是箱子,并且该方向的下下个格子似乎空白或终点,则可以移动
else if (state[pMovSub] == OBJ_BLOCK || state[pMovSub] == OBJ_BLOCK_ON_GOAL)
{
// 下下个点坐标
int xMovNext = xMov + dx;
int yMovNext = yMov + dy;
if (xMovNext < 0 || xMovNext >= width || yMovNext < 0 || yMovNext >= height)
return ;
// 计算下下个点的下标
int pMovNext = yMovNext * width + xMovNext;
if (state[pMovNext] == OBJ_SPACE || state[pMovNext] == OBJ_GOAL)
{
state[pMovNext] = (state[pMovNext] == OBJ_GOAL) ? OBJ_BLOCK_ON_GOAL : OBJ_GOAL;
state[pMovSub] = (state[pMovSub] == OBJ_BLOCK_ON_GOAL) ? OBJ_MAN_ON_GOAL : OBJ_MAN;
state[pPosSub] = (state[pPosSub] == OBJ_MAN_ON_GOAL) ? OBJ_GOAL : OBJ_SPACE;
}
}
}
// 如果没有方块了则判定为通关
bool checkClear(const Object* state, int width, int height)
{
for (int i = 0; i < width * height; ++i)
if (state[i] == OBJ_BLOCK)
return false;
return true;
}