一、思路

1、创建界面map数组边界填充值 1。
2、rand生成随机数确定下移的图形。
3、界面显示,通过移动光标输出确定界面位置。

4、图形显示,通过光标移动输出图形,四个数据块每一块对应一个小方块。

下一个输出next为 反L3:{(0,0), (1,0), (0,1), (0,2)}。

5、图形下移,通过y变化改变位置下移。
6、下移完成,判断图形到界面边界,将图形到达位置写入map, map填充值2。
7、判断一行是否都填满,填满后忽略本行,将此行以上的拷贝下来,最上面一行不用拷贝(最上面一行如果有图形游戏已经结束了)。
8、判断结束,判断最上面那一行map中有 2 ,有则结束。  
9、每次输出完,清理输出界面system("clear"),是一帧一帧输出后形成流畅画面。
10、控制颜色输出详细内容:https://mrleef.blog.csdn.net/article/details/125542134?spm=1001.2014.3001.5506

二、其他

本次用的Linux版本为,ubuntu-18.04.6-desktop-amd64.ios,更新20的版本也不错,个人感觉这个版本的更好用,CentoS不太好用,软件安装也不方便。

编辑器是VSCode和vim,VSCode是开源的,没有版权问题。

运行是用终端运行的。编译命令:gcc game.c   -o game  运行:./game

三、代码

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<unistd.h>#define TTY_PATH  "/dev/tty"                      //系统指令
#define STTY_US  "stty raw -echo -F "      //系统指令
#define STTY_DEF  "stty -raw echo -F "    //系统指令#define WIDE 18
#define HEIGHT 20
#define INFO_AREA 6
#define SPEED 8
#define Y_NEXT 4                             // x_next, y_next下一个图形在方框的位置
#define X_NEXT WIDE - INFO_AREA / 2 - 1int score = 0;                                       //分数
int map[HEIGHT][WIDE] = { 0 };  //界面int x, y;                                                  // x, y 正在下降图形的位置
int moveDown_count = 0;
int shapeIndex, shapeIndex_next;  //shapeIndex:下移图形 shapeIndex_next:下一个图形struct Point {                                    //中心点的偏移量,中心点以此延伸获得各形状点的坐标int shape_x;int shape_y;
};struct Point shapes[19][4] = {{{0, 0},{-1, 0},{1, 0},{2, 0}},      //横条          通过光标移动输出图形{{0, 0},{0, -1},{0, 1},{0, 2}},      //竖条         每一个图形由四个方块组成{{0,0},{-1,-1},{-1,0},{0,-1}},     //方块        四组,每一组对应输出一个方块 {{0, 0},{0, -1},{0, -2},{1, 0}},    //正L1      0, 1...反映光标移动情况{{0,0},{0,1},{1,0},{2,0}},           //正L2   {{0,0},{-1,0},{0,1},{0,2}},         //正L3 {{0,0},{0,-1},{-1,0},{-2,0}},      //正L4  {{0,0},{-1,0},{0,-1},{0,-2}},      //反L1  {{0,0},{0,-1},{1,0},{2,0}},         //反L2 {{0,0},{1,0},{0,1},{0,2}},           //反L3    {{0,0},{-1,0},{-2,0},{0,1}},        //反L4 {{0,0},{-1,0},{1,0},{0,-1}},        //T1  {{0,0},{0,1},{0,-1},{1,0}},         //T 2   {{0,0},{-1,0},{1,0},{0,1}},         //T 3   {{0,0},{-1,0},{0,-1},{0,1}},        //T 4   {{0,0},{1,0},{0,-1},{-1,-1}},      //正 Z 1  {{0,0},{1,-1},{0,1},{1,0}},         //正Z2 {{0,0},{1,-1},{-1,0},{0,-1}},      //反z1  {{0,0},{-1,-1},{-1,0},{0,1}}       //反Z2
};void setFrame();              //构建边宽
void showMap();             //展示界面
void showPoint(int x, int y,int bright,int color);
void showShape();         //输出图形
void creatNewShape();//创建新的图形
int moveDown();             //图形下降,判断是否还可以移动
void addToMap();           //把确定位置的保存在map中
int overCheak();              //确定游戏是否结束
int get_char();                  //获取输入
void control(char str);  //控制移动
void chageShape();       //改变形状
void moveLeft();             //左移
void moveRight();          //右移
void clearLines();           //清除已满行int main()
{system(STTY_US TTY_PATH);  //输入阻塞setFrame();                                      //初始化mapshowMap();                                     //展示界面srand(time(0));shapeIndex = rand() % 19;creatNewShape();                        //创建下一个图形while(1) {system("clear");                        //清除界面显示内容showShape();                             //展示方块showMap();                                 //展示界面if (moveDown()) {                     //判断移动addToMap();                           //不可移动后,写入到mapif (overCheak()) {                   //检查是否游戏结束break;}clearLines();                            //判断一行是否满,并清理shapeIndex = shapeIndex_next;creatNewShape();                //创建下一个图形}char str = get_char();              //得到输入指令if (str == 3) {                                 //是否为ctrl+Cbreak;}control(str);                                 //控制移动usleep(1000*50);                       //阻碍运行速度}system(STTY_DEF TTY_PATH); //输入阻塞结束printf("\033[21;0H");
}/*** @brief Set the Frame object */
void setFrame()
{int i;for(i = 0; i < WIDE; i++) {              //界面两条横线map[0][i] = 1;map[HEIGHT - 1][i] = 1;}for(i = 0; i < HEIGHT; i++) {        //界面三条竖线map[i][0] = 1;map[i][WIDE - INFO_AREA - 1] = 1;map[i] [WIDE - 1] = 1;}
}/*** @brief 展示界面 */
void showMap()
{int i, j;for(i = 0; i < HEIGHT; i++) {for(j = 0;j < WIDE; j++) {if ( map[i][j] == 1 || map[i][j] == 2) {showPoint(j, i, 1, 32 + map[i][j]);   //行标i,列表j与坐标系横纵坐标的值是相反的}}} printf("\033[2;27H");          //   \033[X;XH  光标移动格式printf("\033[31mNext:"); printf("\033[11;27H"); printf("\033[32mScore:");   printf("\033[12;26H"); printf(" \033[32m%3d", score);   fflush(stdout);  //清理缓存,使画面动作流畅
}/*** @brief 输出一个方块* * @param x1 光标横轴位置* @param y1 光标纵轴位置* @param bright 颜色亮度* @param color   颜色种类*/
void showPoint(int x1, int y1, int bright, int color)
{printf("\033[%d;%dH", y1 + 1, x1 * 2 + 1);                   //光标位置printf("\033[%d;%dm■ \033[0m", bright, color);  //颜色深浅,颜色种类
}/*** @brief 创建下一个图形和重置光标位置*/
void creatNewShape()
{ y = 2;x = (WIDE - INFO_AREA) / 2;shapeIndex_next = rand() % 19;
}/*** @brief  显示正在下降的图形和显示下一个图形*/
void showShape()
{int i;for(i = 0; i < 4; i++) {     //显示正在下降的图形showPoint(x + shapes[shapeIndex][i].shape_x, y + shapes[shapeIndex][i].shape_y, 1, 31);}for(i = 0; i < 4; i++) {     //显示下一个图形showPoint(X_NEXT + shapes[shapeIndex_next][i].shape_x, Y_NEXT + shapes[shapeIndex_next][i].shape_y, 1, 31);}
}/*** @brief 图形下降和控制移速* * @return int 1为已经处地,0还可移动*/
int moveDown()
{int i;if (moveDown_count < SPEED) {   //控制移动速度moveDown_count++;                    //移动准确性return 0;                                               //也就是两次进入函数图形下移一格}moveDown_count = 0;for (i = 0; i < 4; i++) {int dx = x + shapes[shapeIndex][i].shape_x;int dy = y + shapes[shapeIndex][i].shape_y + 1;//原来位置的map[x][y]已经是1if (map[dy][dx] == 1 || map[dy][dx] == 2) {return 1;                     //不可移动}}y++;return 0;
}/*** @brief  把不能移动的方块保存到map中*/
void addToMap()
{int i;for(i = 0; i < 4; i++) {map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x] = 2;}
}/*** @brief 检测游戏是否结束* * @return int 0为结束,1还可继续*/
int overCheak()
{int i;for (i = 0; i < WIDE; i++) {if (map[1][i] == 2) {return 1;}}return 0;
}/*** @brief Get the char object* * @return int 返回输入的字符对应的ASCII值*/
int get_char()
{fd_set rfds;struct timeval tv;int ch = 0;FD_ZERO(&rfds);FD_SET(0, &rfds);tv.tv_sec = 0;tv.tv_usec = 10; if (select(1, &rfds, NULL, NULL, &tv) > 0) {ch = getchar(); }return ch;
}/*** @brief 判断输入,得出下一步移动* * @param str 输入的字符*/
void control(char str)
{switch (str) {case 'w':                          //变形chageShape();break;case 'a':                           //左移moveLeft();break;case 's':                            //下移moveDown_count = moveDown_count + SPEED;break;case 'd':                            //右移moveRight();break;}
}/*** @brief  改变形状* 原理:通过改变shapeIndex的值*/
void chageShape()
{int ts = shapeIndex;switch(ts) {case 0:ts++;break;case 1:   ts = 0;break;case 2:break;case 3:case 4:case 5:ts++;break;case 6:ts = 3;break;case 7:case 8:case 9:ts++;break;case 10:ts = 7;break;case 11:case 12:case 13:ts++;break;case 14:ts = 11;break;case 15:ts++;break;case 16:ts = 15;break;case 17:ts++;break;case 18:ts = 17;break;}//ts是假设变形后的图形值int i; //判断假设的图形是否发生碰撞for(i = 0;i < 4;i++) {int cx = x+shapes[ts][i].shape_x;int cy = y+shapes[ts][i].shape_y;if (map[cy][cx]==1 || map [cy][cx]==2) {return;}}shapeIndex = ts; //完成变形
}/*** @brief  左移*/
void moveLeft()
{int i;for (i = 0; i < 4; i++) {if(map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x - 1] == 1|| map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x - 1] == 2) {return;}}x--;
}/*** @brief 右移*/
void moveRight()
{int i;for(i = 0; i < 4; i++) {if (map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x + 1] == 1|| map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x + 1] == 2) {return;}}x++;
}/*** @brief  判断一行是否满,并清理,拷贝上面内容*/
void clearLines()
{int i, j, a;for (i = HEIGHT - 2; i > 0; i--) {a = 1;for(j = 1; j < WIDE - INFO_AREA - 1;  j++) {  //确定是否一行排满if (map[i][j] != 2) {a = 0;break;} }if (a == 1) {score++;int n;for(n = i; n > 1 ; n--) {   //把上面的拷贝下来for(j = 0; j < WIDE - INFO_AREA - 1;  j++) {map[n][j] = map[n- 1][j];}}i++;              //防止有多行一起排满}}fflush(stdout); //清理缓存,使画面动作流畅
}

有什么问题欢迎留言私信,必回!!!

去克制自己纠正别人的欲望,收起你改造他人的执着!人教人是教不会的。

Linux下C语言实现俄罗斯方块——详细版相关推荐

  1. Linux下SVN服务器迁移(详细版)

    最近因公司测试环境需要做迁移,除了应用需要迁移外,项目中平时用到的软件都得迁,涉及到nginx,redis , active MQ ,jenkins 以及SVN.SVN的迁移涉及到了代码的同步,在网上 ...

  2. GCC编译器简明教程(Linux下C语言开发环境的搭建)

    GCC编译器简明教程(Linux下C语言开发环境的搭建) 市面上常见的Linux都是发行版本,典型的Linux发行版包含了Linux内核.桌面环境(例如GNOME.KDE.Unity等)和各种常用的必 ...

  3. Linux下C语言编程

    第1章 Linux下C语言编程简介 本章将简要介绍一下什么是Linux,C语言的特点,程序开发的预备知识,Linux下C语言开发的环境,程序设计的特点和原则以及编码风格等.通过本章的学习,可以对在Li ...

  4. Linux下函数调用堆栈帧的详细解释【转】

    转自:http://blog.chinaunix.net/uid-30339363-id-5116170.html 原文地址: Linux下函数调用堆栈帧的详细解释 作者:cssjtuer http: ...

  5. 初识Linux下C语言编程

    本章将简要介绍一下什么是Linux,C语言的特点,程序开发的预备知识,Linux下C语言开发的环境,程序设计的特点和原则以及编码风格等.通过本章的学习,可以对在Linux下使用C语言编程有一个基本的了 ...

  6. Linux下使用中文、字体、版

    月20日 Unicode BOM 发现网上某广为流传的中文帖子将Unicode字节流的标识字节(BOM, byte order mark)弄错了,正确的应该是: 00 00 FE FF UTF-32, ...

  7. Linux安装Mysql(图文解说详细版)

    安装前必看 这篇文章是用yum安装的,如果是官网安装包tar包安装请移步 Linux安装Mysql(图文解说详细版,安装包tar包版) 文章目录 安装前必看 最近开个新坑,就是在linux环境中操作开 ...

  8. Linux 应用程序 嵌汇编,Linux下C语言嵌汇编

    Using Assembly Language in Linux. Intel和AT&T汇编语法差异: 1.前缀: Intel汇编寄存器和立即数无需前缀.后者寄存器前缀为%,立即数前缀为$. ...

  9. Linux下C语言编程-进程的创建

    Linux下C语言编程-进程的创建 作者:hoyt 1.进程的概念 Linux操作系统是面向多用户的.在同一时间可以有许多用户向操作系统发出各种命令.那么操作系统是怎么实现多用户的环境呢?在现代的操作 ...

  10. linux父进程中显示子进程pid,请教linux下c语言函数fork父进程打印子进程的PID

    请教linux下c语言函数fork父进程打印子进程的PID 关注:296  答案:2  信息版本:手机版 解决时间 2019-01-14 04:55 雨不眠的下 2019-01-13 12:23 用于 ...

最新文章

  1. Python培训教程分享:Python模块如何导入__all__属性?
  2. 【Joomla】TinyMCE - Add custom styles
  3. 并查集(压缩路径+按秩排序)
  4. 中国安防视频监控行业发展前景分析
  5. android9.0不能用4g定位,Android 9.0新特性:让用户认为4G信号更强
  6. php ascii hex编码
  7. Codeforces Round #497 (Div. 1)
  8. 正则表达式的环视实际应用案例
  9. 【动态规划】完全背包问题
  10. android的listview点击获取当前选项值的方法
  11. 嘿,我这里有一个 Survey!
  12. 30首优秀奥运歌曲获奖作品出炉
  13. 1. golang 接入Discord做消息推送
  14. 7个碎片的excel重组实验
  15. Use YSlow to know why your web Slow
  16. 运筹学及其matlab应用,运筹学基础及其MATLAB应用
  17. 4个方法:提升用户活跃度
  18. 【uniapp | 微信小程序】注册和开发环境搭建
  19. Android 5.x浏览器webView或者qqX5崩溃,Resources$NotFoundException:String resource ID #0x2040003
  20. 苹果7p最佳系统版本_苹果代码中发现, iPhone12 刘海没了!

热门文章

  1. 2.ansible中常用模块
  2. matlab实现信号与系统中卷积的计算的两种方法
  3. 产品经理三大证书,考哪个好
  4. TTL和CMOS解析
  5. 【CCF推荐专区】注意这些期刊提前截稿?计算机领域最快15天录用!
  6. awvs12 Server Exception_使用WebSocket搭建服务器server
  7. c语言中d1的分辨率是,C中的方法分辨率顺序
  8. GPS章节要义(补充计算题)
  9. android中edittext监听文字变化,使用TextWatcher监听EditText变化
  10. Excel单页导出以及多sheet导出