二维数组基本操作的编程实现.docx
《二维数组基本操作的编程实现.docx》由会员分享,可在线阅读,更多相关《二维数组基本操作的编程实现.docx(6页珍藏版)》请在冰豆网上搜索。
二维数组基本操作的编程实现
二维数组基本操作的编程实现
实验四二维数组基本操作的编程实现 一、实验目的 掌握二维数组的建立、读取数据、压缩存储等基本操作的编程实现,存储结构可以在顺序结构或链接结构中任选,也可以全部实现。
也鼓励学生利用基本操作进行一些应用的程序设计。
二、实验要求 1.修改程序:
补充推箱子游戏的遗缺的部分,使之能正常运行,逻辑结果正确。
之后增加至少一关自己的关数,墙体,箱子的最初位置,人的最初位置自己设定,要求必须有解,而且有一定的破解难度。
主要的问题是部分移动方向的代码没有给出,另外计数器的整体工作不正常,更完善的修改包括启用栈结构实现后悔的机制。
2.运行程序了解二维结构:
稀疏矩阵的压缩和解压缩、生命繁衍模型、迷宫问题等,通过这些程序的运行过程或结果体会二维结构在程序设计中的重要性和实用性。
原始数据构建方式最简模式为:
键盘输入。
其他的方式也在鼓励之中:
数据内置,计算机自动生成,文件读入。
三、程序说明程序中用于建立栈的类 //节点classReback{public:
intre_key_up;intre_key_down;intre_key_left;intre_key_right;intre_count;intre_movex;intre_movey;intre_movexold;intre_moveyold;intre_peopleflag;intre_Maptemp[11][11];Reback*next;Reback*before; 1 }; Reback*headp=newReback;//头指针Reback*tailp=newReback;//尾指针 说明:
此类用于存储每一步的游戏临时数据,用于回退 程序中的功能函数 voidmyDraw(HWNDhWnd,HDC&dc);//界面的绘制 voidKey_D(HWND&hWnd,HDC&dc,intkey_value);//响应键盘voidinit();//初始化函数 voidCueatMap(intAimMap[11]);//创建地图voidrememberbefore();//保存数据(入栈)voidreturnbefore();//还原数据voiddelrecord();//删除数据(清空栈) 功能的实现:
1.游戏中的鼠标操作的实现:
caseWM_LBUTTONDOWN:
//鼠标左键点击消息 { intx,y,i=0,j=0,count=0; x=LOWORD(lParam);//相对于窗口的位置y=HIWORD(lParam);if(x>=775&&y elseif(x>=0&&x elseif(x>600&&y>120&&x elseif(x>600&&y>200&&x if(Mapdatacounnt+1 Mapdatacounnt++;if(Mapdatacounnt-1>=0){} CueatMap(Mapdata[Mapdatacounnt]);InvalidateRect(hWnd,NULL,true); Mapdatacounnt--;delrecord(); SendMessage(hWnd,WM_SYSCOMMAND,SC_MOVE+HTCAPTION,0);//发送消息delrecord();//释放资源 PostQuitMessage(0);//发送窗口销毁消息用于关闭窗口 2 } } } delrecord(); CueatMap(Mapdata[Mapdatacounnt]);InvalidateRect(hWnd,NULL,true); elseif(x>600&&y>280&&x elseif(x>600&&y>410&&x ShellExecute(hWnd,\,\,\,\,SW_SHOW);returnbefore(); InvalidateRect(hWnd,NULL,true); 说明:
此处的设计方法为,先获取鼠标在窗口中的点击坐标,然后判断该坐标点是否在设定的区域,如果是,则执行相应的操作 2.游戏中键盘操作的实现:
/*键盘消息处理函数*/ voidKey_D(HWND&hWnd,HDC&hdc,intkey_value){//用于响应键盘消息的处理 //限定区域if(count!
=4){ rememberbefore();switch(key_value){case38:
{//在key_up-40之前进行判断看执行此计算后是否还在游戏区域内其他方向相同 if((key_up-40+key_down+40)/40>0){} key_up-=40; }break; if((key_left+key_right+40+40)/40 }break;key_right+=40; case39:
{ case40:
{ if((key_up+key_down+40+40)/40 }break;key_down+=40; case37:
{ if((key_left-40+key_right+40)/40>0) 3 } } {} }break;key_left-=40; keyflag=key_value; InvalidateRect(hWnd,NULL,true); 说明:
获取发生键盘消息时对应的键值,判断此时是否游戏过关,如果没过关就记录当前的游戏数据,响应方向键,如果过关就响应回车键,进入下一关,同时调用屏幕刷新函数。
3.推箱子的逻辑功能实现:
于对四个方向的处理大致相同,此处仅对向上移动进行说明 …… /*运动方向及相应的处理*/ } elseif(Map[(movex)/40][(movey)/40]==3)//前面是箱子接下来判断箱子的前面的情况{ //1箱子前面是路 if(Map[(movex)/40-1][(movey)/40]==0){ Map[(movex)/40-1][(movey)/40]=3;//把箱子的前面换成箱子Map[(movex)/40][(movey)/40]=4;//,当前的箱子位置换成人,movexold=movex;//之前路过moveyold=movey; /*下面的判断都是即将到达的地方*//*向上运动*/if(keyflag==38){//上 if(Map[movex/40][movey/40]==0){//前面是路 Map[(movex)/40][(movey)/40]=4;if(peopleflag==1){ } peopleflag=0; Map[(movexold)/40][(moveyold)/40]=0; Map[(movexold)/40][(moveyold)/40]=2; //在之前已经经过了限制此时不会越界 movey=key_left+key_right+40;//即将要到达的地方movex=key_up+key_down+40;//二维数组中x控制行y控制列 }else{ 4 } } if(peopleflag==1){//之前人已经到了位置上 }else{} movexold=movex;moveyold=movey; peopleflag=0;//人离开了位置 Map[(movexold)/40][(moveyold)/40]=2;//当前人的位置换成位置 Map[(movexold)/40][(moveyold)/40]=0;//当前人的位置换成位置 //2箱子前面是放置位置 elseif(Map[(movex)/40-1][(movey)/40]==2){ }else{} key_up+=40; PlaySound(TEXT(\),NULL,SND_FILENAME|SND_ASYNC);Map[(movex)/40-1][(movey)/40]=5;//把箱子的前面换成“完成”,Map[(movex)/40][(movey)/40]=4;//当前的箱子位置换成人Map[(movexold)/40][(moveyold)/40]=0;count++;movexold=movex;moveyold=movey; elseif(Map[(movex)/40][(movey)/40]==5){//前面是放置完成表示箱子已经推到位置 //放置完成的状态下前面的情况//1放置完成的前面是路把箱子推出去if(Map[(movex)/40-1][(movey)/40]==0){//路 } Map[(movex)/40-1][(movey)/40]=3;//把放置完成的的前面换成箱子Map[(movex)/40][(movey)/40]=2;//,当前的完成换成位置if(peopleflag==0){//之前人的位置不是放置位置为:
路} else{//之前人的位置是放置位置}count--;movexold=movex;moveyold=movey; Map[(movexold)/40][(moveyold)/40]=2;//之前人的位置换成\放置位置\Map[(movexold)/40][(moveyold)/40]=0;//之前人的位置换成路peopleflag=1;//人已经到了位置上 5
} //2放置完成的前面是放置位置 elseif(Map[(movex)/40-1][(movey)/40]==2){ }else{} key_up+=40; Map[(movex)/40-1][(movey)/40]=5;//把放置完成的前面换成“完成”,Map[(movex)/40][(movey)/40]=2;//当前的放置完成换成位置if(peopleflag==1){//之前人在位置上} else{//之前人不在位置上} peopleflag=1;//即将在位置上movexold=movex;moveyold=movey; Map[(movexold)/40][(moveyold)/40]=0;//路 Map[(movexold)/40][(moveyold)/40]=2;//位置 elseif(Map[(movex)/40][(movey)/40]==2){//前面是位置 } elseif(Map[(movex)/40][(movey)/40]==1){}} key_up+=40; Map[(movex)/40][(movey)/40]=2;//当前的放置完成换成位置if(peopleflag==1){//之前人在位置上} else{//之前人不在位置上} peopleflag=1;//即将在位置上movexold=movex;//之前路过moveyold=movey; Map[(movexold)/40][(moveyold)/40]=0;//路 Map[(movexold)/40][(moveyold)/40]=2;//位置 …… 6 说明:
例如当按方向键上时 ①先判断是否在有效区域内(避免越界),然后把key_up的值减40,重绘,接着进入了绘图函数中。
②把四个方向的记录的移到值解析成水平方向和竖直方向的位置坐标值movex,movey,③接着在movex/40,movey/40是把实际的坐标转换成二维数组中的相应位置。
④状态的判断:
判断人前面(指的是各个方向的前方)的情况。
a.如果是路,就把前面的值换成人的值,当前人的位置就换成路,这个地方我用的是 movexold=movex;moveyold=movey;来实现的。
b.如果为箱子,就判断箱子前面的值,如果是路,就把路换成箱子,箱子处换成人,人换成路。
c.如果为位置就把位置换成完成状态,箱子换成人,人换成路。
d.如果人前面是完成状态,就判断完成状态前面的情况:
前面是路,把路换成箱子,完成状态换位置状态,人在位置上,这个地方用了一个peopleflag来表示。
如果完成状态前面是位置,就把前面的位置状态换成完成状态,完成状态换成,人在位置上的状态,当前人所在的位置状态换成之前movexold,moveyold所代表的状态。
(实现从一个位置上推到另外一个位置,即在地图设计中多个位置相邻的情况的解决) ⑤其他情况(前面是墙,前面是箱子而箱子的前面还是箱子,箱子的前面是墙,箱子的前面是完成状态,前面是完成状态而完成状态的前面是箱子,完成状态的前面是墙……)都是保持原地不动,实现的方法为:
key_up+=40,这是因为在键盘消息处理时key_up-=40,所以此处要还原,以实现保持原地不动。
4.绘图的操作 /*绘制此时二维数组中的数值所代表的含义*/ SelectObject(mDc,hPen);//选中灰色画笔进行描边for(i=0;i 7 for(j=0;j if(Map[i][j]==1){//墙} elseif(Map[i][j]==0){//路} SelectObject(mDc,roadbr); Rectangle(mDc,40+40*j,40+40*i,80+40*j,80+40*i);SelectObject(mDc,wallbr); Rectangle(mDc,40+40*j,40+40*i,80+40*j,80+40*i); elseif(Map[i][j]==3){//箱子 } elseif(Map[i][j]==2){//放置位置 SelectObject(mDc,positionbr); SelectObject(mDc,boxbr);SelectObject(mDc,yellowpen); Rectangle(mDc,40+40*j,40+40*i,80+40*j,80+40*i); MoveToEx(mDc,40+40*j,40+40*i,NULL);//绘制黄色方块中的\LineTo(mDc,80+40*j,80+40*i); MoveToEx(mDc,40+40*j,80+40*i,NULL);//LineTo(mDc,80+40*j,40+40*i);SelectObject(mDc,hPen); Rectangle(mDc,40+40*j,40+40*i,80+40*j,80+40*i);SetTextColor(mDc,Gray); TextOut(mDc,55+40*j,52+40*i,TEXT(\),1); if(peopleflag==1&&movexold/40==i&&moveyold/40==j){} SelectObject(mDc,popplebr); Ellipse(mDc,40+40*j,40+40*i,80+40*j,80+40*i); 8 } elseif(Map[i][j]==5){//放置完成 SelectObject(mDc,successbr); Rectangle(mDc,40+40*j,40+40*i,80+40*j,80+40*i);SelectObject(mDc,greenpen); Rectangle(mDc,40+40*j,40+40*i,80+40*j,80+40*i); MoveToEx(mDc,40+40*j,40+40*i,NULL);//绘制黄色方块中的\LineTo(mDc,80+40*j,80+40*i); MoveToEx(mDc,40+40*j,80+40*i,NULL);//LineTo(mDc,80+40*j,40+40*i);SelectObject(mDc,hPen);SetTextColor(mDc,white); TextOut(mDc,42+40*j,52+40*i,TEXT(\),4); } } } elseif(Map[i][j]==4){//\人\的位置 } SelectObject(mDc,roadbr); Rectangle(mDc,40+40*j,40+40*i,80+40*j,80+40*i);SelectObject(mDc,popplebr); Ellipse(mDc,40+40*j,40+40*i,80+40*j,80+40*i);SetTextColor(mDc,white); TextOut(mDc,53+40*j,52+40*i,TEXT(\♀\),2); 说明:
用各种填充矩形来把地图的二维数组中的各值含义绘制在界面上 9 5.游戏界面说明 :
箱子:
人:
位置:
完成:
障碍物:
路 :
表示过关,同时播放欢呼声:
表示当前的关数 10 6.游戏中使用的资源说明 四、总结 本次实验收获很大,掌握了二维数组的操作,比较完美的做出了推箱子游戏,更加熟悉了栈的使用,在本次实验中用链栈实现了回退机制。
在实验中也遇到各种问题:
在初始化栈时, headp->next=tailp; headp->before=NULL;tailp->before=headp;tailp->next=NULL; 我把这部分代码放到了WM_CREAT窗口创建消息中了,结果在回退时只能回退两步,在反复检查了几遍也没有发现问题,最后调试才发现根本就没有执行这段代码。
把这段代码放到WinMain函数中解决了问题。
在推箱子 的逻辑处理中因为有一段少写了 movexold=movex;moveyold=movey; 出现了莫名其妙的问题,分析查找了近半个小时才找到问题所在。
这次实验也锻炼了我的耐心和信心。
在选择用Win32SDK来设计推箱子时,我也不是很有把握的,先从在窗口上画个圆,画个矩形开始的。
程序设计中的太多问题让我几次不想采用Win32SDK了,但是我还是坚持了下来,仔细琢磨,分析问题,推断问题,到最后完美的解决了问题,还是很开心的。
在实现了推箱子的基本功能后,就是对代码的优化,美化界面,提高绘图效率。
这次的实验用DirectX来做可能会简单点。
11