悔步是通过链表来实现的,在人物推动箱子移动后,记录人物移动方向和箱子运动情况,记录数据时用头插法,悔步时直接读取链表中数据即可。
代码如下:
//*
#include<stdio.h>
#include<conio.h> //system("cls") //_getch();
#include<windows.h> //Sleep();
#include<stdlib.h>
int map[10][10] = //游戏地图
{
{0,0,0,0,1,1,1,0,0,0},
{0,0,0,0,1,2,1,0,0,0},
{0,0,0,0,1,0,1,0,0,0},
{0,0,0,0,1,4,1,1,1,1},
{1,1,1,1,1,0,4,0,2,1},
{1,2,0,4,0,3,1,1,1,1},
{1,1,1,1,4,1,0,0,0,0},
{0,0,0,1,0,1,0,0,0,0},
{0,0,0,1,2,1,0,0,0,0},
{0,0,0,1,1,1,0,0,0,0}
};
//int map[10][10] = //测试地图
//{
// {1,1,1,1,1,1,1,1,1,1},
// {1,0,0,0,0,2,0,0,0,1},
// {1,0,0,0,0,0,0,0,0,1},
// {1,2,0,0,0,4,0,0,0,1},
// {1,0,2,2,0,0,4,0,2,1},
// {1,2,0,4,0,3,0,0,0,1},
// {1,0,0,0,4,0,0,0,0,1},
// {1,0,0,0,0,0,0,2,0,1},
// {1,0,0,0,2,0,0,0,0,1},
// {1,1,1,1,1,1,1,1,1,1}
//};
struct HistoryStep
{
int boxIsMove; //记录人物移动是否推动箱子
int direction; //记录人物移动的运动方向
struct HistoryStep* next;
};
struct HistoryStep* hStep_List(int direction, struct HistoryStep* head,int NextIsBox); //单链表记录人物的运动方向(头插法)
struct HistoryStep* Regret_Step(struct HistoryStep* head); //悔步,利用链表中记录的数据来悔步
void NoUse(); //游戏说明
void DrawMap(); //绘制地图
void UpMove(int row, int col, int regret); //人向上移动 ,regret是悔步信号
void DownMove(int row, int col, int regret); //人向下移动
void LeftMove(int row, int col, int regret); //人向左移动
void RightMove(int row, int col, int regret); //人向右移动
int NextIsBox(char input, int row, int col); //判断人物下一位置是否是箱子
int JudgeMove(int num, int row, int col); //判断人物是否移动
struct HistoryStep* PlayGame(struct HistoryStep* head); //运行游戏
int GameOver(); //判断游戏是否结束
struct HistoryStep* hStep_List(int direction, struct HistoryStep* head, int NextIsBox)// 头插法创建单链表
{
static int i = 0;
struct HistoryStep* q = head;
struct HistoryStep* p = (struct HistoryStep*)malloc(sizeof(struct HistoryStep));
if (p)
{
p->boxIsMove = NextIsBox;
p->direction = direction;
p->next = NULL;
}
if (i == 0)
{
head = p;
i++;
}
else
{
head = p;
if (head)
{
head->next = q;
}
}
return head;
}
struct HistoryStep* Regret_Step(struct HistoryStep* head) //悔步
{
int row = -1, col = -1;//初始化人的坐标
for (int i = 0; i < 10; i++)//行
{
for (int j = 0; j < 10; j++)//列
{
if (map[i][j] == 3 || map[i][j] == 5)//找到人的位置
{
row = i;
col = j;
}
}
}
switch (head->direction)
{
case 72:
DownMove(row, col, head->boxIsMove);//人物向下移动,如果悔步信号为1,同时移动箱子
break;
case 75:
RightMove(row, col, head->boxIsMove);
break;
case 80:
UpMove(row, col, head->boxIsMove);
break;
case 77:
LeftMove(row, col, head->boxIsMove);
break;
default:
break;
}
if (head->next)
{
head = head->next; //head后移
}
else
{
head->direction = 0;
}
return head;
}
void NoUse() //游戏说明
{
printf("\n加载中");
for (int t = 0; t < 11; t++)
{
printf(".");
Sleep(111);
}
printf("\n\n游戏说明:\n\n方向键控制移动\n\n按空格键悔步\n");
printf("\n按任意键开始游戏\n");
char c = _getch();
system("cls");
}
void DrawMap() //绘制地图
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
switch (map[i][j])
{
case 0:printf(" ");//路
break;
case 1:printf("■");//墙
break;
case 2:printf("※");//终点
break;
case 3://人
case 5://人在终点 //此程序的测试地图中有这个情况
printf("♀");//人
break;
case 4:printf("□");//箱子
break;
case 6:printf("◆");//箱子到终点
break;
default:
break;
}
if (j == 9)
{
printf("\n");
}
}
}
}
void UpMove(int row, int col, int regret) //人向上移动
{
if (map[row - 1][col] == 0 || map[row - 1][col] == 2)//人上面是路或者终点
{
map[row - 1][col] += 3; //路变人或者终点变人 0->3 或者 2->5
map[row][col] -= 3; //人变路或者终点 3->0 或者 5->2
if (regret == 1) //悔步:这一步需要移动箱子
{
map[row][col] += 4;//在上面,人已经变路或者终点,这一步路或者终点变箱子 0->4 或者 2->6
map[row + 1][col] -= 4; //箱子变路或者终点 6->2 或者 4->0
}
}
else if (map[row - 1][col] == 4 || map[row - 1][col] == 6)//人上面是箱子
{
if (map[row - 2][col] == 0 || map[row - 2][col] == 2)//箱子上面路或者终点
{
map[row - 2][col] += 4;//路变箱子或者终点变箱子 0->4 或者 2->6
map[row - 1][col] -= 1;//箱子变人或者箱子在终点变人在终点 4->3 或者 6->5
map[row][col] -= 3;//人变路或终点 3->0 或者 6->3
}
}
}
void DownMove(int row, int col, int regret)//人向下移动
{
if (map[row + 1][col] == 0 || map[row + 1][col] == 2)
{
map[row + 1][col] += 3;
map[row][col] -= 3;
if (regret == 1)
{
map[row][col] += 4;
map[row - 1][col] -= 4;
}
}
else if (map[row + 1][col] == 4 || map[row + 1][col] == 6)
{
if (map[row + 2][col] == 0 || map[row + 2][col] == 2)
{
map[row + 2][col] += 4;
map[row + 1][col] -= 1;
map[row][col] -= 3;
}
}
}
void LeftMove(int row, int col, int regret)//人向左移动
{
if (map[row][col - 1] == 0 || map[row][col - 1] == 2)
{
map[row][col - 1] += 3;
map[row][col] -= 3;
if (regret == 1)
{
map[row][col] += 4;
map[row][col + 1] -= 4;
}
}
else if (map[row][col - 1] == 4 || map[row][col - 1] == 6)
{
if (map[row][col - 2] == 0 || map[row][col - 2] == 2)
{
map[row][col - 2] += 4;
map[row][col - 1] -= 1;
map[row][col] -= 3;
}
}
}
void RightMove(int row, int col, int regret)//人向右移动
{
if (map[row][col + 1] == 0|| map[row][col + 1] == 2)
{
map[row][col + 1] += 3;
map[row][col] -= 3;
if (regret == 1)
{
map[row][col] += 4;
map[row][col - 1] -= 4;
}
}
else if (map[row][col + 1] == 4|| map[row][col + 1] == 6)
{
if (map[row][col + 2] == 0|| map[row][col + 2] == 2)
{
map[row][col + 2] += 4;
map[row][col + 1] -= 1;
map[row][col] -= 3;
}
}
}
int NextIsBox(char input, int row, int col) //判断下一位置是否为箱子
{
int isBox = 0;
switch (input)
{
case 72:
if (map[row - 1][col] == 4 || map[row - 1][col] == 6)
{
isBox = 1;
}
break;
case 75:
if (map[row][col - 1] == 4 || map[row][col - 1] == 6)
{
isBox = 1;
}
break;
case 80:
if (map[row + 1][col] == 4 || map[row + 1][col] == 6)
{
isBox = 1;
}
break;
case 77:
if (map[row][col + 1] == 4 || map[row][col + 1] == 6)
{
isBox = 1;
}
break;
default:
break;
}
return isBox;
}
int JudgeMove(int num, int row, int col) //判断人物是否移动
{
if (map[row][col] == num)
{
return 0;
}
return 1;
}
struct HistoryStep* PlayGame(struct HistoryStep* head) //运行游戏
{
int num = 0; //记录人是3还是5
int row = -1, col = -1; //初始化人的位置
int nextIsBox = 0; //记录人物下一位置是否为箱子
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (map[i][j] == 3 || map[i][j] == 5)//找到人的位置
{
row = i;
col = j;
num = map[i][j];
}
}
}
char input = _getch();//_getch()函数接收键盘输入的数据
switch (input)
{
case 72: //向上移动 //72是↑的键码值,下面同理
nextIsBox = NextIsBox(input, row, col); //判断人物下一位置是否为箱子
UpMove(row, col, 0); //人向上移动,有箱子时会推动箱子
if (JudgeMove(num, row, col)) //判断人物是否移动,移动了就记录运动方向
{
head = hStep_List(72, head, nextIsBox);
//printf("%d %d", head->direction, head->boxIsMove); //实时打印人物移动方向数据和箱子移动数据
}
break;
case 75://向左移动
nextIsBox = NextIsBox(input, row, col);
LeftMove(row, col, 0);
if (JudgeMove(num, row, col))
{
head = hStep_List(75, head, nextIsBox);
//printf("%d %d", head->direction, head->boxIsMove);
}
break;
case 80://向下移动
nextIsBox = NextIsBox(input, row, col);
DownMove(row, col, 0);
if (JudgeMove(num, row, col))
{
head = hStep_List(80, head, nextIsBox);
//printf("%d %d", head->direction, head->boxIsMove);
}
break;
case 77://向右移动
nextIsBox = NextIsBox(input, row, col);
RightMove(row, col, 0);
if (JudgeMove(num, row, col))
{
head = hStep_List(77, head, nextIsBox);
//printf("%d %d", head->direction, head->boxIsMove);
}
break;
case 32://悔步
//printf("%d %d", head->direction, head->boxIsMove);
head = Regret_Step(head);
break;
default:
break;
}
return head;
}
int GameOver() //判断游戏是否概束
{
int boxs = 0;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (map[i][j] == 4)
{
boxs++;
}
}
}
return !boxs;
}
int main(void)
{
struct HistoryStep* head = NULL;
system("color f0");
system("mode con cols=27 lines=11");
NoUse();
while (1)
{
DrawMap();
head = PlayGame(head);
if (GameOver())
{
DrawMap();
Sleep(300);
system("cls");
break;
}
Sleep(50);
system("cls");
}
//for (struct HistoryStep* p = head; p != NULL; p = p->next) //打印链表中记录的运动步骤
//{
// switch (p->direction)
// {
// case 72:
// printf(" ↑ ");
// break;
// case 75:
// printf(" ← ");
// break;
// case 80:
// printf(" ↓ ");
// break;
// case 77:
// printf(" → ");
// break;
// default:
// break;
// }
//}
printf("\n 恭喜过关!\n\n");
return 0;
}//*/
本人的运行测试环境为VS2019,写的有问题地方还请指出。