啊哈c的推箱子游戏(更新附带失败判断!)

以下是原文,2020.6.28更新了推箱子失败判断,以及优化方向代码,还新加了博主的无情嘲讽 。

因为啊哈c后面推箱子游戏未附代码,而且说实话考虑很多种状况和之前走迷宫的思路还是有区别的。并且我在网上搜的时候没有相似的参考信息,大一这学期快结束了才准备搞这个。一早上的bug ,调试了很多次才好。

说实话,网上信息对新人极不友好,我查推箱子代码,很多csdn博客连界面都写好了,对刚刚学c的我们打击好大啊。总之,我觉得有必要像啊哈c的作者啊哈磊那样写点对新生友好的内容,不然书上一堆枯燥无味的语法真的难读下去。

进入正题。二维数组画出地图,其中s表示人,o表示箱子,*表示目的地,@把箱子推入目的地。如果想换地图,只需改写二维数组和初始位置(x,y)。由于精力有限单纯好玩,所以没写出箱子推入角落等失败条件判断。源代码如下:

经提醒源代码在啊哈c 3.0版本以上运行有错,因为getch()函数头文件conio.h未添加,另外getch()函数可移植性较差,所以还是报错的话就用getchar()替代,每次输入w,a,s,d后再输入回车即可。

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
int main()
{system("color f9");//我喜欢的言和蓝(ff9999)//#是墙;s是人;o是箱子;*是目的地;char a[12][12]={"##########","##     ###","##o###   #","# s o  o #","# **# o ##","##**#   ##","##########",};int x=3,y=2,i;//x,y是初始坐标;char direction;for(i=0;i<7;i++)puts(a[i]);while(a[4][2]!='@'||a[4][3]!='@'||a[5][2]!='@'||a[5][3]!='@')//所有箱子推入结束{direction=getch();switch(direction){//w s a d, 方向键case'w':if(a[x-1][y]!='#')/*给w附注释,下面类似检测前面(就是所对应方向,下同)是不是墙,可以不要但运算会变大*/{if(a[x-1][y]==' ')//空格直接走{a[x][y]=' ';x--;a[x][y]='s';/*我一开始写成a[x--][y]='s'结果不对,其实应该写成--x才能正常运行*/}else if(a[x-1][y]=='o'&&a[x-2][y]!='#')//如果是箱子,并且前面不是墙{if(a[x-2][y]==' ')//箱子前是空格推得动{a[x][y]=' ';x--;a[x][y]='s';a[x-1][y]='o';}else if(a[x-2][y]=='*')//必须有else,否则可能多运行一步。//箱子前是目的地就换成@。{a[x][y]=' ';x--;a[x][y]='s';a[x-1][y]='@';}}else if(a[x-1][y]=='*')//s人想进入目的地{a[x][y]=' ';//空格不要紧,不会洗掉原有目的地。//后面有代码防止目的缺失x--;a[x][y]='s';}else if(a[x-1][y]=='@')//想在目的地范围内移箱子{if(a[x-2][y]=='*'){a[x][y]=' ';x--;a[x][y]='*';a[x-1][y]='@';}else if(a[x-2][y]==' '){a[x][y]=' ';x--;a[x][y]='*';a[x-1][y]='o';}}}break;//下面方向键类似case's':if(a[x+1][y]!='#'){if(a[x+1][y]==' '){a[x][y]=' ';x++;a[x][y]='s';}else if(a[x+1][y]=='o'&&a[x+2][y]!='#'){if(a[x+2][y]==' '){a[x][y]=' ';x++;a[x][y]='s';a[x+1][y]='o';}else if(a[x+2][y]=='*'){a[x][y]=' ';x++;a[x][y]='s';a[x+1][y]='@';}}else if(a[x+1][y]=='*'){a[x][y]=' ';x++;a[x][y]='s';}else if(a[x+1][y]=='@'){if(a[x+2][y]=='*'){a[x][y]=' ';x++;a[x][y]='*';a[x+1][y]='@';}else if(a[x+2][y]==' '){a[x][y]=' ';x++;a[x][y]='*';a[x+1][y]='o';}}}break;case'a':if(a[x][y-1]!='#'){if(a[x][y-1]==' '){a[x][y]=' ';y--;a[x][y]='s';}else if(a[x][y-1]=='o'&&a[x][y-2]!='#'){if(a[x][y-2]==' '){a[x][y]=' ';y--;a[x][y]='s';a[x][y-1]='o';}else if(a[x][y-2]=='*'){a[x][y]=' ';y--;a[x][y]='s';a[x][y-1]='@';}}else if(a[x][y-1]=='*'){a[x][y]=' ';y--;a[x][y]='s';}else if(a[x][y-1]=='@'){if(a[x][y-2]=='*'){a[x][y]=' ';y--;a[x][y]='*';a[x][y-1]='@';}else if(a[x][y-2]==' '){a[x][y]=' ';y--;a[x][y]='*';a[x][y-1]='o';}}}break;case'd':if(a[x][y+1]!='#'){if(a[x][y+1]==' '){a[x][y]=' ';y++;a[x][y]='s';}else if(a[x][y+1]=='o'&&a[x][y+2]!='#'){if(a[x][y+2]==' '){a[x][y]=' ';y++;a[x][y]='s';a[x][y+1]='o';}else if(a[x][y+2]=='*'){a[x][y]=' ';y++;a[x][y]='s';a[x][y+1]='@';}}else if(a[x][y+1]=='*'){a[x][y]=' ';y++;a[x][y]='s';}else if(a[x][y+1]=='@'){if(a[x][y+2]=='*'){a[x][y]=' ';y++;a[x][y]='*';a[x][y+1]='@';}else if(a[x][y+2]==' '){a[x][y]=' ';y++;a[x][y]='*';a[x][y+1]='o';}}}break;}if(a[4][2]!='s'&&a[4][2]!='@')a[4][2]='*';if(a[4][3]!='s'&&a[4][3]!='@')a[4][3]='*';if(a[5][2]!='s'&&a[5][2]!='@')a[5][2]='*';if(a[5][3]!='s'&&a[5][3]!='@')a[5][3]='*';/*我觉得我做的最好的一步,检测目的地是不是人或者箱子,再加载目的地,克服换位置时目的地*号丢失*/system("cls");//清屏for(i=0;i<7;i++)puts(a[i]);//重新打印}system("cls");printf("you win!\n");Sleep(5000);return 0;
}

——————————————————假装更新线————————————————
2020.6.28 更新
如果搜到这片文章,说明你还是一个在用啊哈c学c语言的小白,而博主据写这篇文章已经有两年多更新了,快大三了,从小白变成了蒟蒻都不如的菜鸡(连萌新都不敢当,群里巨佬都在装萌新怎么办 )。

不过都是这么一步一步走过来的,我走了很多弯路,我想对曾经的那个小白说很多,这样我可能现在不会这么急。实在建议计算机小白们一开始就去打acm比赛,那怕最后放弃了也无所谓,只要入门了都能随便切那些一般工作的面试题(比如力扣,笑)。不知道怎么入门的可以看看我的这个回答:acm入门
直接正文吧,两年了,啊哈c2013年出版,到现在2020年了,仍然只有我在第一手更新,说多了都是泪。
上面代码200多行,而且wsad方向键其实功能差不多我硬是整了4的case然后if else套if else,哈哈哈,不愧是小白的我。
如果和我一样从啊哈c只是初学c语言,请听我唠叨这一段。对于相同的功能,比如方向键这种,只有很小的代码差别,如果只是四个方向还能多敲一下搞出来,如果要再来几个不是得重复劳动,这就叫造轮子,就是已有的东西不去用反而还要自己再设计,众所周知轮子已经是圆的了,不可能还有其他形状了(说莱洛三角形的,亲亲这边建议你去清华读数学系呢 ),你不去用还要造个方的吗?所以,把这个东西封装起来。简单在此处来说就是把这个功能变成一个函数去调用,多次调用即可,不用我们一个一个方向去再打一遍相同的内容。
下面就封装了移动函数,xx,yy表示移动距离,比如向右时xx=-1,yy=0;表示x+xx,y+yy,这样就成了原来点的(x-1,y)。有了这个函数你甚至可以定义自己的移动方向,比如用q键表示放大招把箱子斜着推,只需要让xx=1,yy=1即可,就朝右下方向推箱子了,甚至可以用e键调用dir(2,2),你可以斜着把箱子推两格
#是墙;s是人;o是箱子;米字号是目的地,对了,居然有人怀疑我这个推箱子没法过???你自己试试,我用了239步就过了(如果有更短的步数过图,请务必回复我)

void dir(int xx, int yy) {//从主函数开始读是好习惯(*^▽^*)if (a[x +xx][y+yy] != '#')/*给w附注释,下面类似检测前面(就是所对应方向,下同)是不是墙,可以不要但运算会变大*/{if (a[x +xx][y+yy] == ' ')//空格直接走{a[x][y] = ' ';x+=xx;y += yy;a[x][y] = 's';}else if (a[x +xx][y+yy] == 'o'&&a[x+xx+xx][y+yy+yy] != '#')//如果是箱子,并且箱子前面不是墙{if (a[x+xx+xx][y+yy+yy] == ' ')//箱子前是空格推得动{a[x][y] = ' ';//清除原位置的人x+=xx;y += yy;a[x][y] = 's';a[x +xx][y+yy] = 'o';}else if (a[x +xx+xx][y+yy+yy] == '*')//必须有else if,否则可能多运行一步。//箱子前是目的地就换成@。{a[x][y] = ' ';x+=xx;y += yy;a[x][y] = 's';a[x +xx][y+yy] = '@';}}else if (a[x+xx][y+yy] == '*')//s人想进入目的地{a[x][y] = ' ';//空格不要紧,不会洗掉原有目的地。//后面有代码防止目的缺失x+=xx;y += yy;a[x][y] = 's';}else if (a[x +xx][y+yy] == '@')//想在目的地范围内移箱子{if (a[x +xx+xx][y+yy+yy] == '*'){a[x][y] = ' ';x+=xx;y += yy;a[x][y] = '*';a[x +xx][y+yy] = '@';}else if (a[x+xx+xx][y+yy+yy] == ' '){a[x][y] = ' ';x+=xx;y += yy;a[x][y] = '*';a[x +xx][y+yy] = 'o';}}}
}

然后就是判断失败函数,说实话,写的很简单,判断箱子有没有进死角,进死角就说明gme over。
有一个箱子两面相邻贴墙的话肯定没法推了,推箱子不是拉箱子,你难道把他挤出来到目的地吗?(笑)

//类似这种
#########
#      o#
# *     #
#########

代码如下:

bool fail() {int i, j;for (i = 0; i < 7; i++) {for (j= 0; j < 10; j++) {if (a[i][j] == 'o') {//遇到箱子判断一下if (a[i + 1][j] == '#' && (a[i][j + 1] == '#' || a[i][j-1] == '#')) {//下面是墙,如果左右有墙就卡死return false;}if (a[i -1][j] == '#' && (a[i][j + 1] == '#' || a[i][j-1] == '#')) {//上面是墙,如果左右有墙就卡死return false;}}}}return true;
}

可以看出来非常粗糙,两个for循环判断,时间复杂度O(n2),还好地图小,实际上应该用四个点来记录箱子位置,这样就不用每次都去两个for循环找这个箱子在哪了。不过这样就是代码将变得完全不一样了。而实际上这种判断失败条件太简单了,漏了很多条件,比如下面这种,只有一面贴墙却失败了:

#######
#     #####
##    o   #
#  *   ####
############

可以看出了虽然只有上面贴墙,人在外面的话但是没法从o的右边推箱子,因为右边那三个空格人是进不去的。我百度了下没有代码来专门判断推箱子失败条件的,我一向讨厌造轮子,不过这次搜不出来,就和我写这个推箱子一样,之前从没有人发过思路或者代码。
实际上我的思路很简单,就是先用二维数组记录箱子坐标,通过深度搜索或者广度搜索来判断那些空格可以到达,能到达标1,不能标为0,然后枚举所有箱子是否进“死角”。

下面是精简后代码,当然没有实现上面说的判断方法,因为答主太懒了 。这个版本方向可以随便修改,步数也能修改,你想让这个人走“日”字步(比如一次操作向左走三步,向下走两步)也是可以的,只需要调用函数dir(2,3)即可。
另外添加了失败判断条件,game over.,最后,如果你的步数超过239步以上,还会遭到博主的无情嘲笑,如果你过这个图少于239步请务必私聊或者评论我,答主应该是最少步数了。
代码如下:

#include<conio.h>//getch()函数头文件
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int x = 3, y = 2;//x,y是初始坐标;
char a[12][12] = { "##########",//存图,注意人不能推动一个以上的箱子"##     ###","##o###   #","# s o  o #","# **# o ##","##**#   ##","##########",
};
void dir(int xx, int yy) {//从主函数开始读是好习惯(*^▽^*)if (a[x +xx][y+yy] != '#')/*给w附注释,下面类似检测前面(就是所对应方向,下同)是不是墙,可以不要但运算会变大*/{if (a[x +xx][y+yy] == ' ')//空格直接走{a[x][y] = ' ';x+=xx;y += yy;a[x][y] = 's';}else if (a[x +xx][y+yy] == 'o'&&a[x+xx+xx][y+yy+yy] != '#')//如果是箱子,并且箱子前面不是墙{if (a[x+xx+xx][y+yy+yy] == ' ')//箱子前是空格推得动{a[x][y] = ' ';//清除原位置的人x+=xx;y += yy;a[x][y] = 's';a[x +xx][y+yy] = 'o';}else if (a[x +xx+xx][y+yy+yy] == '*')//必须有else if,否则可能多运行一步。//箱子前是目的地就换成@。{a[x][y] = ' ';x+=xx;y += yy;a[x][y] = 's';a[x +xx][y+yy] = '@';}}else if (a[x+xx][y+yy] == '*')//s人想进入目的地{a[x][y] = ' ';//空格不要紧,不会洗掉原有目的地。//后面有代码防止目的缺失x+=xx;y += yy;a[x][y] = 's';}else if (a[x +xx][y+yy] == '@')//想在目的地范围内移箱子{if (a[x +xx+xx][y+yy+yy] == '*'){a[x][y] = ' ';x+=xx;y += yy;a[x][y] = '*';a[x +xx][y+yy] = '@';}else if (a[x+xx+xx][y+yy+yy] == ' '){a[x][y] = ' ';x+=xx;y += yy;a[x][y] = '*';a[x +xx][y+yy] = 'o';}}}
}
bool fail() {int i, j;for (i = 0; i < 7; i++) {for (j= 0; j < 10; j++) {if (a[i][j] == 'o') {//遇到箱子判断一下if (a[i + 1][j] == '#' && (a[i][j + 1] == '#' || a[i][j-1] == '#')) {//下面是墙,如果左右有墙就卡死return false;}if (a[i -1][j] == '#' && (a[i][j + 1] == '#' || a[i][j-1] == '#')) {//上面是墙,如果左右有墙就卡死return false;}}}}return true;
}
int main()
{system("color f9");//我喜欢的言和蓝(ff9999)//#是墙;s是人;o是箱子;*是目的地;int i,cnt=0;//cnt统计步数char direction;for (i = 0; i < 7; i++)puts(a[i]);while (a[4][2] != '@' || a[4][3] != '@' || a[5][2] != '@' || a[5][3] != '@')//所有箱子推入结束{cnt++;//操作一次步数加一次撞墙了也算哦!direction = getch();//w s a d, 方向键//注意啊哈c下载的编译器支持getch(),如果vs想运行尽量用getchar()函数if (direction == 'w'||direction == 'W')//大小写都支持dir(-1, 0);//相比之前是不是好了很多,只需要行函数调用即可else if (direction == 's' || direction == 'S')dir(1, 0);else if (direction == 'a' || direction == 'A')dir(0, -1);else if (direction == 'd' || direction == 'D')dir(0, 1);if (a[4][2] != 's'&&a[4][2] != '@')a[4][2] = '*';if (a[4][3] != 's'&&a[4][3] != '@')a[4][3] = '*';if (a[5][2] != 's'&&a[5][2] != '@')a[5][2] = '*';if (a[5][3] != 's'&&a[5][3] != '@')a[5][3] = '*';/*我觉得我做的最好的一步,检测目的地是不是人或者箱子,再加载目的地,克服换位置时目的地*号丢失*/system("cls");//清屏for (i = 0; i < 7; i++)puts(a[i]);//重新打印if (!fail()) {//判断这个状态是否失败printf("you lose\n");for (i = 0; i <= 10; i++)printf("Game over!!!!\n");Sleep(5000);return 0;}}system("cls");if(cnt>239)printf("虽然你赢了但你用了%d步\n博主只用了239步",cnt);else printf("Congratulation!you win!\n");Sleep(5000);return 0;
}

啊哈c的推箱子游戏(C语言)相关推荐

  1. 推箱子游戏(C语言版)

    [C语言经典算法100道实战题]点击链接即可在线学习: https://edu.csdn.net/course/detail/37564 一.推箱子游戏C语言版[运行效果如下]** 二.安装图形库 我 ...

  2. EasyX实现推箱子游戏

    文章目录 1 项目需求 2 模块划分 3 项目实现 3.1 地图初始化 3.2 热键控制 3.3 推箱子控制 3.4 游戏结束 1 项目需求 实现一款推箱子游戏,效果如下图所示,具体规则: 箱子只能推 ...

  3. 项目: 推箱子游戏【c/c++】

    很早之前写的一个推箱子的游戏 目录 最终效果 代码 最终效果 代码 #include<stdio.h> #include<stdlib.h> #include<graph ...

  4. c语言多关卡推箱子程序,多关卡地图推箱子游戏

    多关卡地图推箱子游戏 # include # include # include //调出地图 void file(int map[14][16],int n,int flag) //n表示关卡数 , ...

  5. 推箱子java下载_Java实现简单推箱子游戏

    本文实例为大家分享了Java实现简单推箱子游戏的具体代码,供大家参考,具体内容如下 *编写一个简易的推箱子游戏,使用10*8的二维字符数据表示游戏画面,H表示墙壁; &表示玩家角色: o表示箱 ...

  6. 一文教你使用java开发一款推箱子游戏

    导读:社会在进步,人们生活质量也在日益提高.高强度的压力也接踵而来.社会中急需出现新的有效方式来缓解人们的压力.此次设计符合了社会需求,Java推箱子游戏可以让人们在闲暇之余,体验游戏的乐趣.具有操作 ...

  7. greenfoot推箱子游戏_推箱子小游戏V2.0更新

    小游戏实践 推箱子V2.0 大家好,我是努力学习争取成为优秀的Game Producer的路人猿,我们上期一起学习制作推箱子的简易V1.0版本,学习了如何响应用户的输入以及面对箱子的各种情况,今天我们 ...

  8. c语言语音控制游戏文献,C语言课程设计-基于C语言推箱子游戏设计-毕业论文文献.doc...

    gd工程职业技术学院毕业论文 基于C语言的推箱子游戏设计 Design of the push box Based on Combined Language 作者姓名: 学科专业: 应用电子技术 学院 ...

  9. c语言基于easyX樱花特效,C++基于easyx图形库实现推箱子游戏

    本文实例为大家分享了C++实现推箱子游戏的具体代码,供大家参考,具体内容如下 头文件: #include #include //#include #include #include #include ...

  10. 推箱子游戏的java设计思路_用JAVA实现一个推箱子游戏

    技术应用 TECHNOLOGY AND MARKET Vol. 26,No. 2,2019 用 JAVA 实现一个推箱子游戏 马寅璞1,孔阳坤2 ( 1. 南京信息工程大学计算机软件学院物联网工程 1 ...

最新文章

  1. 微博面试Java,微博java开发工程师面试题整理
  2. P2339 提交作业usaco
  3. 还在用 Dockerfile 部署 Spring Boot?out 啦!试试谷歌的大杀器 Jib
  4. 2 snippets vue 修改配置_VsCode从零开始配置一个属于自己的Vue开发环境
  5. grpc 客户端的context 服务端获取不到_MLamp;DEV[10] | gRPC的应用
  6. 去除tableView表头悬浮
  7. 人体姿态识别-左肩和左肘的定位识别
  8. 思科OSPF配置实例
  9. 苹果授权登录,后端校验(Sign in with Apple)
  10. 中国芯片的突破带来压力,美国芯片龙头将再度裁员,或已后悔不迭
  11. 洛谷 洛谷 P2708 硬币翻转(高端算法)
  12. JPS网页中文乱码解决方案
  13. 耳朵(一)Linux简述
  14. 7.Unity中c#代码学习(物理系统刚体+碰撞检测(爆炸效果实现))
  15. 测评5款电脑上可以用的epub阅读器
  16. 计算机二级报名安大,计算机二级考试PP--张辉老师(安大计协).ppt
  17. android .rar,手机压缩文档不用愁:RAR for Android
  18. 【深度学习笔记】循环神经网络和递归神经网络区别
  19. Word2010(详细布局解释)
  20. sql server 2382端口问题

热门文章

  1. idea 调用c#接口_c# api接口开发
  2. Flutter 自定义Widget 圆角矩形加三角指示器
  3. 360浏览器的js兼容与360拦截浮动广告
  4. Wex5访问自驾PhP服务,WeX5经过Baas服务访问数据库
  5. 机器视觉系统设计数字相机与模拟相机的优势比较
  6. 遵义微红科技私有化部署+直播打造社群直播分销增长双引擎
  7. UI设计是什么?主要学什么?
  8. React native ios长按显示粘贴,复制为英文改为中文
  9. OLSR协议详解(1)
  10. 从nginx“惊群”问题来看高并发锁的方案