首先要玩这个游戏得先获取键盘的键值,从而判定方向
获取方向键的功能:使用头文件 getch.h 中的gech函数
代码如下:
#ifndef GETCH_H
#define GETCH_H
#include <termios.h>
#include <unistd.h>
// 修改终端的控制方式,1取消回显、确认 2获取数据 3还原
static int getch(void)
{
// 记录终端的配置信息
struct termios old;
// 获取终端的配置信息
tcgetattr(STDIN_FILENO,&old);
// 设置新的终端配置
struct termios new = old;
// 取消确认、回显
new.c_lflag &= ~(ICANON|ECHO);
// 设置终端配置信息
tcsetattr(STDIN_FILENO,TCSANOW,&new);
// 在新模式下获取数据
int key_val = 0;
do{
key_val += getchar();
}while(stdin->_IO_read_end - stdin->_IO_read_ptr);
// 还原配置信息
tcsetattr(STDIN_FILENO,TCSANOW,&old);
return key_val;
}
#endif//GETCH_H
建立好头文件后由电脑到虚拟的LINUX环境步骤如下:
1、在windows中把getch.h头文件放入共享文件夹
2、终端进入贡献文件夹:
cd /media/sf_Share
3、复制头文件到共享库
sudo cp getch.h /usr/include/
4、加读取权限:
sudo chmod +r /usr/include/gerch.h
分别测试一下上下左右的键值
#include <stdio.h>
#include<getch.h>
int main(int argc,const char*argv[])
{
for(int i=0;i<4;i++)
printf("%d ",getch());
}
得到的方向以及键值如下:
上:183 下:184 右:185 左:186
再大致分析一下代码的整体轮廓
1.确定各种对应关系,墙体、路等用什么表示
2.画好地图
3.移动规则
4.判定规则
准备好这些就可以写代码啦
1.首先分析一下情况
推箱子游戏由路、墙、人、箱子以及目标组成
所以可以考虑用不同的数字代表这些情景,结合二维数组构成基本的地图
我这里的设定如下:分别用数字0、1、 2、 3、 4代表路、墙、人、箱子以及目标
2.地图定义如下:
int arry[8][8]={
{1,1,1,1,1,1,1,1},
{1,1,1,4,4,1,1,1},
{1,1,1,0,4,1,1,1},
{1,1,0,0,3,4,1,1},
{1,1,0,3,0,0,1,1},
{1,0,0,1,3,3,0,1},
{1,2,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1}
};//0路1墙2人3箱子4目标
打印效果如下
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
switch(arry[i][j])
{
case 1:
printf(" * ");break;
case 0:
printf(" ");break;
case 2:
printf(" @ ");break;
case 3:
printf(" # ");break;
case 4:
printf(" o ");break;
}
}
printf("\n");
}
可以看到已经有了基本轮廓
3.然后我们分析一下移动规则:
(1)移动方向前方是路则可以向前
移动方向前方是目标可以向前
以前前方如果是箱子,而箱子前方是目标或者路可以向前推动
4.胜利规则的判定,由于目标点是自己定的,知道坐标的情况下可以直接判断目标点上的值,
例如这里是(1,3)(1,4)(2,4)(3,5)
如果这些坐标上的值都等于3,说明箱子都归位了
在二维数组的基础上和好理解,定义indix1、indix2分别是人的行和列下标
则人的:
上方向 arry [indix1-1] [indix2]
下方向 arry [indix1+1] [indix2]
左方向 arry [indix1] [indix2-1]
右方向 arry [indix1] [indix2+1]
向上移动的代码例子如下:
switch(getch())//获取键值
{
case 183: //移动方向向上
if(arry[indix1-1][indix2]==0||arry[indix1-1][indix2]==4)//行坐标-1,判断上方是路或者目标则可以向上移动,
{
arry[indix1-1][indix2]=2; //把地图上人的位置重新赋值、更新
if((indix1==1&&(indix2==3||indix2==4))||(indix1==2&&indix2==4)||(indix1==3&&indix2==5))
arry[indix1][indix2]=4; //走出的位置是目标点,标记回目标
else
arry[indix1][indix2]=0; //否则变回路
indix1=indix1-1; //把人的下标更新,方便下次判断
cnt++; //记录步数
}
else if(arry[indix1-1][indix2]==3) //如果上方是箱子的话
{
if(arry[indix1-2][indix2]==0||arry[indix1-2][indix2]==4) //箱子前面如果是路或者目标则可以推
{
arry[indix1-2][indix2]=3; //箱子的位置更新
arry[indix1-1][indix2]=2; //人的位置更新
if((indix1==1&&(indix2==3||indix2==4))||(indix1==2&&indix2==4)||(indix1==3&&indix2==5))
arry[indix1][indix2]=4; //走出的位置是目标点,标记回目标
else
arry[indix1][indix2]=0; //否则变回路
indix1=indix1-1; //把人的下标更新,方便下次判断
cnt++;
}
}
break;
后面几个方向的原理类似,只要把代码复制下去改一下方向即可,篇幅原因,这里不贴出来
几个方向间的代码有很多的雷同之处,可以考虑总结一下优化代码
在前面提到过,这是方向的表示:
上方向 arry [indix1-1] [indix2]
下方向 arry [indix1+1] [indix2]
左方向 arry [indix1] [indix2-1]
右方向 arry [indix1] [indix2+1]
对于上下方向、左右方向,可以分别用一个变量表示,获取相应键值后对不同变
量进行赋值这里用up表示上下、on表示左右
方向 arry [indix1+up] [indix2+on]对于(up,on)=(-1,0)/(1,0)/(0,-1)/(0,1)就能表示各个方向了
对于移动、推箱子后的更新,可以考虑另一种赋值关系,这样对于出入目标值、成功的判断就不用坐标判断法
定义如下:
1、人移动到新的位置或者目标,则该处坐标+=2,即加上人对应的数值,离开则-=2
这样子若移动的方向是路0+2=2,若是目标4+2=6,所以6打印的也是人
离开原位2-2=0,还原路;6-2=4还原目标
2、推箱子也是一样,如果能推,箱子要移动到的坐标的值+=3,人移动到箱子的位置-=1;离开原位-=2
这样子若移动的方向是路0+4=2,移动到箱子的位置3-1=2(打印的还是人),离开原位2-2=0,还原路;、
若是目标4+3=7,所以7打印的也是箱子,并且是到了目标的箱子!!
原理基本就这样
优化后的代码
cnt=0; //记录箱子进入目标的个数,全部进入判定成功
up=0; //清除上一次的方向
on=0; //清除上一次的方向
switch(getch()) //获取键值并决定移动方向
{
case 183:
up--;
break;
case 184:
up++;
break;
case 185:
on++;
break;
case 186:
on--;
break;
}
if(0==arry[indix1+up][indix2+on]||4==arry[indix1+up][indix2+on]) //是路或者目标
{
arry[indix1+up][indix2+on] +=2; //新位置
arry[indix1][indix2] -=2; //旧位置
indix1 +=up; //更新人的坐标
indix2 +=on;
step++; //记录步数
}
else if(3==arry[indix1+up][indix2+on]||7==arry[indix1+up][indix2+on]) //是箱子
{
if(arry[indix1+up*2][indix2+on*2]==0||arry[indix1+up*2][indix2+on*2]==4)
//箱子要移动的方向是路或者目标
{
arry[indix1+up*2][indix2+on*2] +=3; //箱子的新位置
arry[indix1+up][indix2+on] -=1; //人去到箱子原位置
arry[indix1][indix2] -=2; //人原来的位置
indix1 +=up; //更新人的下标
indix2 +=on;
step++; //记录步数
}
}
总的代码如下:
#include <stdio.h>
#include<getch.h>
#include<stdlib.h>
int main(int argc,const char*argv[])
{
int arry[8][8]={
{0,0,0,1,1,1,0,0},
{0,0,1,4,4,1,0,0},
{0,0,1,0,4,1,1,0},
{1,1,0,0,3,4,1,0},
{1,1,0,3,0,0,1,1},
{1,0,0,0,3,3,0,1},
{1,2,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1}
};//1墙2人3箱子4目标
//3+4=7箱子
//2+4=6人
int up,on,i,j,cnt=0,step=0,indix1=6,indix2=1;
while(1)
{
system("clear"); //清屏
cnt=0;
up=0;
on=0;
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
switch(arry[i][j])
{
case 1:
printf(" * ");break;
case 0:
printf(" ");break;
case 2:
printf(" @ ");break;
case 3:
printf(" # ");break;
case 4:
printf(" o ");break;
case 6:
printf(" @ ");break;
case 7:
cnt++; //统计一下目标与箱子叠加的个数
printf(" # ");break;
}
}
printf("\n");
}
if(cnt==4) //四个箱子都在目标位置上就说你成功了
{
printf("走了:%d步数",step);
return 0;
}
cnt=0;
up=0;
on=0;
switch(getch())
{
case 183:
up--;
break;
case 184:
up++;
break;
case 185:
on++;
break;
case 186:
on--;
break;
}
if(0==arry[indix1+up][indix2+on]||4==arry[indix1+up][indix2+on])
{
arry[indix1+up][indix2+on] +=2;
arry[indix1][indix2] -=2;
indix1 +=up;
indix2 +=on;
step++;
}
else if(3==arry[indix1+up][indix2+on]||7==arry[indix1+up][indix2+on])
{
if(arry[indix1+up*2][indix2+on*2]==0||arry[indix1+up*2][indix2+on*2]==4)
{
arry[indix1+up*2][indix2+on*2] +=3;
arry[indix1+up][indix2+on] -=1;
arry[indix1][indix2] -=2;
indix1 +=up;
indix2 +=on;
step++;
}
}
}
}