C++ 150行代码实现俄罗斯方块
震惊!C++全程不压缩代码、包括注释实现俄罗斯方块竟只需要150行!
该程序思路和步骤均参考自b站 up主:你已经是大佬了快和萌新们聊天吧 大佬的视频。
在此向大佬表示诚挚的敬意与感谢。
视频传送门
由于被参考源代码的特殊原因和其他原因,本人硬是研究了将近11个小时才算基本了解了该程序的原理!
之后我又用C++根据理解重新写了这个程序,并添加了详细的注释。
这个程序让我深刻认识到了在数据结构和算法上,我还有多么长的路要走…
如果大家急于学习,请忽略以下内容并移步技术环节。
反思:
对于人们平时写程序而言,基本上只需要了解了程序的原理,即可动手写出一个具有这些功能的程序。
我认为,不论这个程序本身是多么的复杂,如果写出来的程序包含有大量重复、冗余代码、极高的时空复杂度以及很多的bug,那么这个程序依旧是一个糟糕的程序。
以我之前写的几个小程序为例,动辄上千行的代码看起来很多,但,我自己知道这里面大多数代码都没有什么技术含量,因为在写程序的过程中,我均采取了最暴力也是傻的解决办法,如,for循环上千次只为寻找到一个值、用很多不符合规范的代码去堵上一个bug等等。
虽然我是因为当时没有更好的解决方案才会去这么写,但我们必须要认识到,这种写法不过只是最低级的程序,如果把这种程序真正当作问题的解决方案来看的话,无疑是错误的。
其实在参考其他人的代码写这个程序之前,我用常规暴力写法几乎已经完成了一个俄罗斯方块程序,但是到最后又需要写一个常规写法需要很多lj代码才能实现的功能的时候,我便放弃了,因为我突然意识到:写简单的程序是没有出路的!
技术环节:
编译环境:Windows Visual Studio 2019
需求:
俄罗斯方块所有基本功能,包括:
7种不同的方块组合自动下落
方块旋转(一个键)
方块组合按键下落
方块组合左右移
一行全部为方块时消行
等
思路:
通过将node二维数组各方块位置组成不同方块组合(形状)与一维map数组的位置对应,且map数组下标加上方块组合距左、上墙的距离,其中距上墙距离用Y*10在一维数组中表示,通过Y每次循环+1即可得到方块组合自动下落,通过接收按键ad,修改X实现左移右移。
通过node数组排成特定规律,再将方块组合编号(形状)与特定相加数字传入move函数,即可与左右移功能使用同一个函数更改得到当前方块组合旋转后的形状,并限制旋转后的碰撞情况。
注意:
文中的“方块组”,是指小方块组成的,所有形状、方向的方块组合。
node数组将所有不同的方块组分别列出。
由于编译器原因,代码中_kbhit()和_getch()函数可能在其他编译器上编译会出现错误,解决办法是去掉函数前面的“_”。
运行效果:
代码:
#include <iostream>
#include <conio.h>
#include <windows.h>
#include <ctime>
using namespace std;int map[250]; //地图数组
int X = 4, Y = 1; //方块组分别距左墙、上墙的距离class Square //方块组类
{private:int node[28][4] = //节点数组,规律存储各方块组的形状{//每四个数存储一个形状的方块组在地图中对应的信息//其含义可以看作在平面直角坐标系中,但不存在可以随机访问的y轴,而最大X轴为10//要访问特定y轴的数,就需要对x轴进行加减,x+n大于10的部分会在y+1轴重新计算,反之在y-1{ -1,0,1,-11 },{ 10,0,-10,-9 },{ 11,-1,0,1 },{ 9,10,0,-10 }, { -1,0,1,-9 },{ 10,11,0,-10 },{ 9,-1,0,1 },{ 0,10,-10,-11 }, { 9,10,0,1 },{ 11,0,1,-10 },{ 9,10,0,1 },{ 11,0,1,-10 }, { 10,11,-1,0 },{ 10,0,1,-9 },{ 10,11,-1,0 },{ 10,0,1,-9 },{ -1,0,1,-10 },{ 10,0,1,-10 },{ 10,-1,0,1 },{ 10,-1,0,-10 },{ 20,10,0,-10 },{ -1,0,1,2 }, { 20,10,0,-10 }, { -1,0,1,2 }, { 10,11,0,1 }, { 10,11,0,1 }, { 10,11,0,1 }, { 10,11,0,1 }}; //方块组形状,循环int form = rand() % 1;bool sign = false; //判断是否执行了方块组下方为边界或其他方块的标记public:int& getform() //获取和修改当前方块组的形状编号{return form;}bool move(int& Z, int L){Z += L; //形参1 += 形参2for (int i = 0; i < 4; i++){int j = (node[form][i] + 11) % 10 - 1 + X; //计算出小方块所在地图的列数//如果当前方块组修改之后有方块的x轴小于0或x轴大于9//或有方块的列数大于24//或更改方块组Y坐标后方块所在的位置上已经有其他方块//则撤回移动并返回1if (j < 0 || j > 9 || ((Y * 10 + X +node[form][i]) / 10) > 24 || map[Y * 10 + X +node[form][i]]){//如果方块组移动后纵坐标>24或下方有其他方块为真,则设置标记为true,否则标记为false(((Y * 10 + X +node[form][i]) / 10) > 24 || map[Y * 10 + X +node[form][i]])?sign = true : sign = false;Z -= L; //因为撤回方块组移动会更改方块组的数值,//而判断方块组下方边界和其他方块需要的时方块组移动之后的数据//所以撤回撤回移动写在标记赋值下边return false;}}//i从后向前遍历地图数组,k用来累加地图一行中为1值的个数,为10则执行消行for (int i = 249, k = 1; i > 9; i--) {if (i % 10 == 0)k = 0;if (map[i] == 1)k++;if (k == 10)for (int j = i / 10 * 10 + 9; j >= 0; j--)j - 10 >= 0 ? map[j] = map[j - 10] : map[j] = 0;}return true; //正常移动返回true}void setmap() //将方块组对应的地图位置赋值为-1{for (int i = 0; i < 4; i++)map[Y * 10 + X +node[form][i]] = -1;}void drop() //下落{if (move(Y, 1)||(!sign)) //正常下落或方块组碰左右墙直接返回return;//方块组成功落地,执行地图对应位置赋值并重置下落方块组的操作for (int i = 0; i < 4; i++) //将当前方块组在地图中对应的位置赋为1map[Y * 10 + X + node[form][i]] = 1;X = 4, Y = 1, form = rand() % 28; //将方块组的位置和形状编号进行重置for (int i = 0; i < 4; i++)map[Y * 10 + X + node[form][i]] = -1;}
};void HideCursor() //光标隐藏
{CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}int main()
{system("mode con:cols=20 lines=25"); //设置控制台宽高,且因为需要用到控制台自动换行,控制台必为10宽,且因为map原因必为25高HideCursor(); //光标隐藏srand((unsigned)time(NULL)); //随鸡种子Square square; //方块组类//游戏循环while (true){if (_kbhit()) //键盘按下时{char key = _getch();switch (key){case 'a': //左移square.move(X,-1); break;case 'd': //右移square.move(X, 1); break;case 's': //下落if (Y < 2) break; //方块重置时不可连按下落,否则有时会出现bug,原因不明square.drop(); break;case ' ': //暂停_getch(); break;case 'w': //旋转//旋转的本质是改变方块组的形状,将方块组编号传入move中修改,可对修改后的方块组进行越界检测//修改后方块组如果与方块1、下、左、右墙重合则会被取消改变int &tempf = square.getform();square.move(tempf, (tempf % 4) < 3 ? 1 : -3);//将(form % 4) < 3 ? 1 : -3)与form相加即可得到节点数组中与形状相对应的旋转形状,其中玄机,还请自悟}}square.setmap(); //将方块组对应在地图中的位置修改为-1//遍历地图数组,非0的位置输出■代表方块for (auto i = 0; i < 250; i++){cout << (map[i] ? "■" : " ");if(map[i] == -1) //必须加if(map[i]==-1)的原因为:在方块组成功下落后,//地图对应位置会变为1来表示已经下落的方块,如果不加判断会将已经下落的方块重新置为0map[i] = 0; //输出完方块后将当前地图值重新赋值为0}square.drop(); //方块组下落Sleep(150);}return 0;
}
由于目前本人对该程序还不深,不规范之处还请多多包含。
欢迎大家提出批评和建议。
感谢大家的支持。
C++ 150行代码实现俄罗斯方块相关推荐
- python编程小游戏代码-Python小游戏之300行代码实现俄罗斯方块
前言 本文代码基于 python3.6 和 pygame1.9.4. 俄罗斯方块是儿时最经典的游戏之一,刚开始接触 pygame 的时候就想写一个俄罗斯方块.但是想到旋转,停靠,消除等操作,感觉好像很 ...
- python小游戏源码-Python小游戏之300行代码实现俄罗斯方块
Python小游戏之300行代码实现俄罗斯方块 来源:中文源码网 浏览: 次 日期:2019年11月5日 [下载文档: Python小游戏之300行代码实现俄罗斯方块.txt ] (友情提示:右键点上 ...
- android 用代码模拟滑动,Android开发之使用150行代码实现滑动返回效果
今天带大家实现滑动返回效果.,具体内容如下所示: 先看看效果图: 因为没有具体内容,也没有简书的图片资源,所以稍微简陋了点. 但是依然不妨碍我们的效果展示~ OK,接下来惯例,通过阅读本文你能学习到: ...
- hash签名 java_java开发区块链只需150行代码
原标题:java开发区块链只需150行代码 本文帮助你理解什么是区块链.将通过java开发区块链的实战学习方式,用 Java创建开发一个基本的区块链,实现简单的工作量证明系统.Java开发区块链的源代 ...
- python编写小游戏代码_Python小游戏之300行代码实现俄罗斯方块
Python小游戏之300行代码实现俄罗斯方块 来源:中文源码网 浏览: 次 日期:2019年11月5日 [下载文档: Python小游戏之300行代码实现俄罗斯方块.txt ] (友情提示:右键点上 ...
- 【线程池】自行准备linux环境,带你手写线程池,只需仅仅150行代码|内存池|API|连接池|应用协议丨C/C++Linux服务器开发
[线程池]自行准备linux环境,带你手写线程池,只需仅仅150行代码 视频讲解如下,点击观看: [线程池]自行准备linux环境,带你手写线程池,只需仅仅150行代码|内存池|API|连接池|应用协 ...
- 【线程池】自行准备linux环境,带你手写线程池,只需仅仅150行代码
[线程池]自行准备linux环境,带你手写线程池,只需仅仅150行代码 视频讲解如下,点击观看: [线程池]自行准备linux环境,带你手写线程池,只需仅仅150行代码|内存池|API|连接池|应用协 ...
- C++ 中的多线程的使用和线程池建设。150行代码,手写线程池
C++ 11 引入了 std::thread 标准库,方便了多线程相关的开发工作. 说到多线程开发,可不仅仅是创建一个新线程就好了,不可避免的要涉及到线程同步的问题. 而保证线程同步,实现线程安全,就 ...
- python小游戏代码大全-Python小游戏之300行代码实现俄罗斯方块
前言 本文代码基于 python3.6 和 pygame1.9.4. 俄罗斯方块是儿时最经典的游戏之一,刚开始接触 pygame 的时候就想写一个俄罗斯方块.但是想到旋转,停靠,消除等操作,感觉好像很 ...
最新文章
- 关于Hibernate中No row with the given identifier exists问题的原因及解决
- elasticsearch创建mysql索引_ElasticSearch快速使用,基本索引创建-增加type-mapping-插入数据...
- python语言有什么用-Python到底有什么用?为什么那么多人都在学Python?
- 排错之网络映射缓存凭证记录导致备份计划任务失败
- Lodash常用用法总结
- 95-160-024-源码-DataStream-ConnectedStreams与union合并流
- deeply understanding Binary tree--二叉树
- linux ^H^H^
- 80sec被黑原因分析
- 利用matlab编程实现主成分分析,利用Matlab编程进行主成分分析
- PS计算机字体Q,PS q萌字体教程
- 复杂性思维第二版 一、复杂性科学
- 在vue里使用codemirror
- 笔记本无线上网卡怎么用?
- 关于安装SQLServer2012时遇到1402错误,未能打开注册表项的解决方法
- 前端页面局部(全局)刷新方法
- 好书收藏:读书知多少
- Mac端口5000被ControlCe占用问题解决方法
- moonseo小夜:作为一个seo伴随着技术的学习与提升
- 关于旋转(Rotation)