文章目录

  • 俄罗斯方块Tetris(C基础,Linux终端)
    • 前言
    • 游戏说明
    • 游戏效果展示
    • 游戏程序实现步骤
      • 一.准备工作
        • 1.非阻塞型输入
        • 2.在屏幕上打印一个方块
      • 二.头文件、宏定义、全局变量、声明及主函数
        • 7种基本形状,以 L 型为例
      • 三.创建游戏界面
      • 四.打印整个界面
      • 五.随机出新的图形并打印
      • 六.方块的下降、左右移动及旋转
        • 旋转算法示意:
      • 七.用户输入及控制
      • 八.方块触底
      • 九.方块触顶(结束游戏)
      • 十.完结撒花
    • 完整代码

俄罗斯方块Tetris(C基础,Linux终端)

前言

学完了C语言基础后想写个经典游戏俄罗斯方块Tetris练练手吗?今天它来啦!代码量少,逻辑清晰,简单易懂,山顶洞人表示一眼就能学会! (结尾附完整代码)

游戏说明

1.按键 W :方块变形
2.按键 S :方块加速下落
3.按键 A :方块向左移动
4.按键 D :方块向右移动
5.按键:ctrl + C :结束运行
6.游戏区右侧信息区可显示下一个方块的形状,以及当前得分
7.快动手去拓展更多功能吧!!

游戏效果展示

游戏程序实现步骤

一.准备工作

1.非阻塞型输入

首先来了解一下什么是非阻塞型输入,非阻塞型输入跟操作系统有关。linux下C语言常用输入函数 scanf 、getchar 和 gets 通常都是阻塞式的,如果用户没有输入,程序就一直停在那儿。输入内容后,还需要用户点回车,同时,用户输入的信息,会在屏幕上回显出来。写俄罗斯方块的时候,我们不期望这种阻塞发生,我们希望按键后程序立刻响应,而不需要输入回车和屏幕回显。这不是我们编写程序的重点,只需了解即可。来看非阻塞型输入实验完整代码:(可直接复制尝试)
此段程序仅供做理解与测试用,ctrl+c结束运行:

#include<stdio.h>
#include <stdlib.h>
#define TTY_PATH    "/dev/tty"
#define STTY_US     "stty raw -echo -F "
#define STTY_DEF    "stty -raw echo -F "
int get_char();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;
}int main()
{int ch = 0;system(STTY_US TTY_PATH);                  //开启非阻塞输入while(1){ch = get_char();if (ch==3)                             //ctrl+c{system(STTY_DEF TTY_PATH);            //关闭非阻塞输入return 0;}printf("key = %d(%c)\n\r", ch, ch);usleep(1000*1000);                 //微秒数     }
}
2.在屏幕上打印一个方块

Linux控制台特殊效果 linux下printf的特殊用法

void drawPoint(int x, int y,int mode,int color)
{ printf("\033[%d;%dH", y+1, x*2+1);//x,y参数为方块的位置 printf("\033[%d;%dm■ \033[0m",mode,color);//打印一个方块
}
(1) 通用格式控制:mode (2) 前景色:color
0 重置所有属性 30 黑色
1 高亮/加粗 31 红色
2 暗淡 33 黄色
4 下划线 34 蓝色
5 闪烁 35 品红
7 反转 36 青色
8 隐藏 37 白色

二.头文件、宏定义、全局变量、声明及主函数

#include<stdio.h>
#include <stdlib.h>
#include <time.h>
#define TTY_PATH  "/dev/tty"
#define STTY_US  "stty raw -echo -F "
#define STTY_DEF  "stty -raw echo -F "
#define SCREEN_WIDTH 18
#define SCREEN_HEIGHT 20
#define INFO_AREA 6
#define SPEED 8int map[SCREEN_HEIGHT][SCREEN_WIDTH] = {0};//定义二维数组作为平面直角坐标系,向右x增向下y增
struct Point_Delta          //中心点的偏移量,中心点以此延伸获得各形状点的坐标
{int delta_x;int delta_y;
};
struct Point_Delta shapes[7][4] = //7种基本方块形状
{{{0,0},{-1,0},{1,0},{0,1}},//T{{0,0},{0,-1},{0,1},{1,1}},//L{{0,0},{0,-1},{0,1},{-1,1}},//反L{{0,0},{0,-1},{-1,-1},{1,0}},//Z{{0,0},{-1,0},{0,-1},{1,-1}},//反Z{{0,0},{1,0},{0,1},{1,1}},//田{{0,0},{0,-1},{0,1},{0,2}},//|
};
int x,y,x_next,y_next,shapeIndex,shapeIndex_temp,shapeIndex_next;
int score,moveDown_count;
void showPoint(int x, int y,int bright,int color);
void showMap();
void setFrame();
void creatNewShape();
void showShape();
int moveDown();
void addToStatic();
void clearLines();
int isFullLine(int line);
void copyLine(int dst,int src);
void supplyLines(int line);
void userControl(char input);
void moveRight();
void moveLeft();
int overCheak();
void userControl(char input);
void moveRight();
void moveLeft();
int get_char();int main()
{system(STTY_US TTY_PATH);//开启非阻塞输入setFrame();//初始化边框srand(time(0));//随机种子shapeIndex = rand()%7;//初始化一个形状的编号shapeIndex_next = rand()%7;//初始化下一个形状的编号creatNewShape();//创建新图形,重置定位点while(1){system("clear");//清屏showShape();//打印当前的图形以及信息区下一个形状if(moveDown())//控制下降函数,触底判断为真{addToStatic();//把触底的图形添加至静态部分clearLines();//如果有一行满了则消除并加相应的分数shapeIndex = shapeIndex_next;//下一个图形的编号为信息区所显示的creatNewShape();shapeIndex_next = shapeIndex_temp;//新随机的下一个图形编号}showMap();//打印整个游戏界面if(overCheak())//检测方块触顶的函数,触顶判断为真,跳出循环break;fflush(stdout);//清理缓存,让终端立刻显示usleep(1000*40);//系统等待的微秒数,控制帧率char input = get_char();//获取按键输入userControl(input);//控制方块的左右移动,变形,加速下降if(input == 3){system(STTY_DEF TTY_PATH);//关闭非阻塞输入return 0;}}return 0;
}
7种基本形状,以 L 型为例

三.创建游戏界面

void setFrame()//创建边框
{int i,j;for(j=0;j<SCREEN_WIDTH;j++){map[0][j] = 1;//第1行   给坐标上点赋值是为了显示特定的点,判断碰撞以及区分开不同意义的点集map[SCREEN_HEIGHT-1][j] = 1;//最后一行}for(i=1;i<SCREEN_HEIGHT-1;i++){map[i][0] = 1;//第一列map[i][SCREEN_WIDTH-INFO_AREA] = 1;//信息区map[i][SCREEN_WIDTH-1] = 1;//最后一列}
}

四.打印整个界面

void showPoint(int x, int y,int mode,int color)
{printf("\033[%d;%dH", y+1, x*2+1);printf("\033[%d;%dm■ \033[0m",mode,color);//打印一个方块
}
void showMap()//打印整个界面
{int i,j;for(i=0;i<SCREEN_HEIGHT;i++){for(j=0;j<SCREEN_WIDTH;j++){if(map[i][j] == 1)showPoint(j,i,1,30);//行标i,列表j与坐标系横纵坐标的值是相反的if(map[i][j] == 2)showPoint(j,i,1,33);if(j==SCREEN_WIDTH-INFO_AREA){if(i==1)printf("Next:");if(i==7)printf("Score:");if(i==8)printf("    %3d",score);}}}
}

五.随机出新的图形并打印

void creatNewShape()
{x = (SCREEN_WIDTH-INFO_AREA)/2;//新形状的定位点,游戏区的中间y = 2;//避免越界shapeIndex_temp = rand()%7;x_next = SCREEN_WIDTH-INFO_AREA/2;//信息区下一个形状的定位点y_next = 4;
}
void showShape()
{int i;for(i=0;i<4;i++)showPoint(x+shapes[shapeIndex][i].delta_x,//x,y分别加上4个点相应的偏移量y+shapes[shapeIndex][i].delta_y,1,31);for(i=0;i<4;i++){ showPoint(x_next+shapes[shapeIndex_next][i].delta_x,y_next+shapes[shapeIndex_next][i].delta_y,1,31);}
}

六.方块的下降、左右移动及旋转

int moveDown()
{int i;if(moveDown_count<SPEED)//函数被调用SPEED次才会执行一次,用来控制下降速度{moveDown_count++;return 0;}moveDown_count = 0;for(i=0;i<4;i++){int dx = x+shapes[shapeIndex][i].delta_x;int dy = y+shapes[shapeIndex][i].delta_y+1;//判断map[x][y]的下方是否已经有方块if(map[dy][dx] == 1||map[dy][dx] ==2)//如果有,不可移动return 1;}y++;return 0;
}
void moveRight()
{int i,rx,ry;//移动之前检测合法性,先判断移动后的点是否与边界或静态部分碰撞for(i=0;i<4;i++){rx = x+shapes[shapeIndex][i].delta_x+1;ry = y+shapes[shapeIndex][i].delta_y;if(map[ry][rx]==1||map[ry][rx]==2)//不能移动return;}x++;//合法,则移动
}
void moveLeft()
{int i,lx,ly;for(i=0;i<4;i++){lx = x+shapes[shapeIndex][i].delta_x-1;ly = y+shapes[shapeIndex][i].delta_y;if(map[ly][lx]==1||map[ly][lx]==2)//不能移动return;}x--;//合法,则移动
}
void chageShape()
{int i,newDelta_x[4],newDelta_y[4];if(shapeIndex==5)//田形状不需要旋转return;for(i=0;i<4;i++){newDelta_x[i] = shapes[shapeIndex][i].delta_y;newDelta_y[i] = -shapes[shapeIndex][i].delta_x;if(map[y+newDelta_y[i]][x+newDelta_x[i]] == 1//在旋转之前要做合法性判断,旋转后是否会发生碰撞||map[y+newDelta_y[i]][x+newDelta_x[i]] == 2)return;}for(i=0;i<4;i++)//合法,则赋值完成旋转{shapes[shapeIndex][i].delta_x = newDelta_x[i];shapes[shapeIndex][i].delta_y = newDelta_y[i];}
}
旋转算法示意:

七.用户输入及控制

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;
}
void userControl(char input)
{switch(input){case 'w':chageShape();break;case 'a':moveLeft();break;case 's':moveDown_count+=SPEED;//加速下降break;case 'd':moveRight();break;}
}

八.方块触底

每次方块触底后:
1.把它添加到静态部分,把所有已经落定的方块成为静态区域(坐标上的点赋值为2)
2.判断是否有满行,有则消除(包含满行判断,行覆盖,行添补)
3.创建一个新的图形继续下落

void addToStatic()//添加到静态区域,把所有已经落定的方块称为静态区域
{int i;for(i = 0;i<4;i++)map[y+shapes[shapeIndex][i].delta_y][x+shapes[shapeIndex][i].delta_x] = 2;//静态的点值为2
}
void clearLines()//消除已经满的行
{int i,count = 0;for(i=SCREEN_HEIGHT-2;i>0;i--)//从最后一行往上遍历{if(isFullLine(i)){count++;//此处算法可参考下方程序段continue;}copyLine(i+count,i);//上面覆盖到下面}for(i=1;i<count;i++)supplyLines(i);score += count;//计分
}
int isFullLine(int line)//判断此行是否满
{int i;for(i=1;i<SCREEN_WIDTH-INFO_AREA-1;i++)//只算游戏区域{if(map[line][i]!=2)//此行没有满return 0;}return 1;             //此行全部为2
}
void copyLine(int dst,int src)//目标行,源行
{int i;for(i=1;i<SCREEN_WIDTH-INFO_AREA-1;i++)map[dst][i] = map[src][i];
}
void supplyLines(int line)//给i行补0
{int i;for(i=1;i<SCREEN_WIDTH-INFO_AREA-1;i++)map[line][i] = 0;
}

消行算法的原理可参考下方程序,不要与游戏程序混淆:

#include<stdio.h>
int main()
{int a[6] = {0,2,3,1,4,1};//消除值为1的元素并在前面补0int i,count = 0;for(i=6-1;i>=0;i--){if(a[i]==1){count++;continue;}a[i+count] = a[i];}for(i=0;i<count;i++)a[i] = 0;for(i=0;i<6;i++)printf("%d ",a[i]);//运行程序输出结果为0 0 0 2 3 4printf("\n");return 0;
}

九.方块触顶(结束游戏)

int overCheak()//检测方块是否触顶
{int i,m,n;for(i=1;i<SCREEN_WIDTH-1;i++){if(map[1][i]==2){          system(STTY_DEF TTY_PATH);//关闭非阻塞输入return 1;}}return 0;
}

十.完结撒花

1.笔者因水平限制如有误导大家的地方非常抱歉哈
2.欢迎下方留言讨论
3.来“华清远见” http://www.hqyj.com/学习更多编程知识

完整代码

#include<stdio.h>
#include <stdlib.h>
#include <time.h>
#define TTY_PATH  "/dev/tty"
#define STTY_US  "stty raw -echo -F "
#define STTY_DEF  "stty -raw echo -F "
#define SCREEN_WIDTH 18
#define SCREEN_HEIGHT 20
#define INFO_AREA 6
#define SPEED 8int map[SCREEN_HEIGHT][SCREEN_WIDTH] = {0};//定义二维数组作为平面直角坐标系,向右x增向下y增
struct Point_Delta                          //中心点的偏移量,中心点以此延伸获得各形状点的坐标
{int delta_x;int delta_y;
};
struct Point_Delta shapes[7][4] =
{{{0,0},{-1,0},{1,0},{0,1}},//T{{0,0},{0,-1},{0,1},{1,1}},//L{{0,0},{0,-1},{0,1},{-1,1}},//反L{{0,0},{0,-1},{-1,-1},{1,0}},//Z{{0,0},{-1,0},{0,-1},{1,-1}},//反Z{{0,0},{1,0},{0,1},{1,1}},//田{{0,0},{0,-1},{0,1},{0,2}},//|
};
int x,y,x_next,y_next,shapeIndex,shapeIndex_temp,shapeIndex_next;
int score,moveDown_count;
void showPoint(int x, int y,int bright,int color);
void showMap();
void setFrame();
void creatNewShape();
void showShape();
int moveDown();
void addToStatic();
void clearLines();
int isFullLine(int line);
void copyLine(int dst,int src);
void supplyLines(int line);
void userControl(char input);
void moveRight();
void moveLeft();
int overCheak();
void userControl(char input);
void moveRight();
void moveLeft();
int get_char();
int main()
{system(STTY_US TTY_PATH);//开启非阻塞输入setFrame();srand(time(0));shapeIndex = rand()%7;shapeIndex_next = rand()%7;creatNewShape();while(1){system("clear");showShape();if(moveDown()){addToStatic();clearLines();shapeIndex = shapeIndex_next;creatNewShape();shapeIndex_next = shapeIndex_temp;}showMap();if(overCheak())break;fflush(stdout);//清理缓存,让终端立刻显示usleep(1000*40);//微秒数char input = get_char();userControl(input);if(input == 3){system(STTY_DEF TTY_PATH);//关闭非阻塞输入return 0;}}return 0;
}
void setFrame()//创建边框
{int i,j;for(j=0;j<SCREEN_WIDTH;j++){map[0][j] = 1;//第1行   给坐标上点赋值是为了显示特定的点,判断碰撞以及区分开不同意义的点集map[SCREEN_HEIGHT-1][j] = 1;//最后一行}for(i=1;i<SCREEN_HEIGHT-1;i++){map[i][0] = 1;//第一列map[i][SCREEN_WIDTH-INFO_AREA] = 1;//信息区map[i][SCREEN_WIDTH-1] = 1;//最后一列}
}void showPoint(int x, int y,int bright,int color)
{printf("\033[%d;%dH", y+1, x*2+1);printf("\033[%d;%dm■ \033[0m",bright,color);//打印一个方块
}
void showMap()
{int i,j;for(i=0;i<SCREEN_HEIGHT;i++){for(j=0;j<SCREEN_WIDTH;j++){if(map[i][j] == 1)showPoint(j,i,1,30);//行标i,列表j与坐标系横纵坐标的值是相反的if(map[i][j] == 2)showPoint(j,i,1,33);if(j==SCREEN_WIDTH-INFO_AREA){if(i==1)printf("Next:");if(i==7)printf("Score:");if(i==8)printf("    %3d",score);}}}
}
void creatNewShape()
{x = (SCREEN_WIDTH-INFO_AREA)/2;//新形状的定位点,游戏区的中间y = 2;//避免越界shapeIndex_temp = rand()%7;x_next = SCREEN_WIDTH-INFO_AREA/2;y_next = 4;
}
void showShape()
{int i;for(i=0;i<4;i++)showPoint(x+shapes[shapeIndex][i].delta_x,y+shapes[shapeIndex][i].delta_y,1,31);for(i=0;i<4;i++){ showPoint(x_next+shapes[shapeIndex_next][i].delta_x,y_next+shapes[shapeIndex_next][i].delta_y,1,31);}
}
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].delta_x;int dy = y+shapes[shapeIndex][i].delta_y+1;//原来位置的map[x][y]已经是1if(map[dy][dx] == 1||map[dy][dx] ==2)return 1;//不可移动}y++;return 0;
}
void moveRight()
{int i,rx,ry;for(i=0;i<4;i++){rx = x+shapes[shapeIndex][i].delta_x+1;ry = y+shapes[shapeIndex][i].delta_y;if(map[ry][rx]==1||map[ry][rx]==2)//不能移动return;}x++;
}
void moveLeft()
{int i,lx,ly;for(i=0;i<4;i++){lx = x+shapes[shapeIndex][i].delta_x-1;ly = y+shapes[shapeIndex][i].delta_y;if(map[ly][lx]==1||map[ly][lx]==2)//不能移动return;}x--;
}
void chageShape()
{int i,newDelta_x[4],newDelta_y[4];if(shapeIndex==5)return;for(i=0;i<4;i++){newDelta_x[i] = shapes[shapeIndex][i].delta_y;newDelta_y[i] = -shapes[shapeIndex][i].delta_x;if(map[y+newDelta_y[i]][x+newDelta_x[i]] == 1||map[y+newDelta_y[i]][x+newDelta_x[i]] == 2)return;}for(i=0;i<4;i++){shapes[shapeIndex][i].delta_x = newDelta_x[i];shapes[shapeIndex][i].delta_y = newDelta_y[i];}
}
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;
}
void userControl(char input)
{switch(input){case 'w':chageShape();break;case 'a':moveLeft();break;case 's':moveDown_count+=SPEED;break;case 'd':moveRight();break;}
}void addToStatic()//添加到静态区域,把所有已经落定的方块称为静态区域
{int i;for(i = 0;i<4;i++)map[y+shapes[shapeIndex][i].delta_y][x+shapes[shapeIndex][i].delta_x] = 2;//静态的点值为2
}
void clearLines()//消除已经满的行
{int i,count = 0;for(i=SCREEN_HEIGHT-2;i>0;i--)//从最后一行往上遍历{if(isFullLine(i)){count++;continue;}copyLine(i+count,i);//上面覆盖到下面}for(i=1;i<count;i++)supplyLines(i);score += count;
}
int isFullLine(int line)
{int i;for(i=1;i<SCREEN_WIDTH-INFO_AREA-1;i++)//只算游戏区域{if(map[line][i]!=2)//此行没有满return 0;}return 1;             //此行全部为2
}
void copyLine(int dst,int src)//目标行,源行
{int i;for(i=1;i<SCREEN_WIDTH-INFO_AREA-1;i++)map[dst][i] = map[src][i];
}
void supplyLines(int line)//给i行补0
{int i;for(i=1;i<SCREEN_WIDTH-INFO_AREA-1;i++)map[line][i] = 0;
}
int overCheak()//检测是否游戏结束
{int i,m,n;for(i=1;i<SCREEN_WIDTH-1;i++){if(map[1][i]==2){          system(STTY_DEF TTY_PATH);//关闭非阻塞输入return 1;}}return 0;
}

俄罗斯方块Tetris(C基础,Linux终端)相关推荐

  1. Linux基础 —— Linux终端命令格式

    01.终端命令格式 command [-options] [parameter] 说明: · command:命令名,相应功能的英文单词或单词的缩写 · [-options]:选项,可用来对命令进行控 ...

  2. 俄罗斯方块linux服务器,安装Tint以在Linux终端下玩俄罗斯方块

    如果你想在Linux终端(Linux命令行)下玩俄罗斯方块游戏,那就安装Tint,它可以满足你的需求.Tint尝试尽可能地转向原始游戏,但有一些显着的差异,例如下一个区块没有预览,并且暂停游戏没有选项 ...

  3. Linux 学习笔记之超详细基础linux命令 Part 3

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 2----------------- ...

  4. 成为 Linux 终端高手的七种武器

    成为 Linux 终端高手的七种武器 2017-03-23 17:34:31     来源:    点击:0 inux 终端不仅是一个键入命令的地方.如若你能熟谙这些基础技巧,那么你会在绝大多数 Li ...

  5. linux 下qt 终端隐藏在后台_20 个 Linux 终端下的生产力工具 | Linux 中国

    来试下这些开源工具.你的效率一定会提升. 来源:https://linux.cn/article-12274-1.html 作者:Alan Smithee 译者:Xiaobin.Liu 诚然,很多人使 ...

  6. linux 复制代码 多出了很多空格_最基础Linux(一)——简单命令行操作

    Linux终端的命令很多,但作为零基础的入门者而言,一开始了解一下几个操作就可以撑过好一阵子了,一下接触太多可能反而会比较头疼.而等回过神来想学更多的命令的时候,自己琢磨的能力也差不多了. 将介绍的命 ...

  7. linux执行shell过程日志,Android之在linux终端执行shell脚本直接打印当前运行app的日志...

    1.问题 我们一般很多时候会需要在ubuntu终端上打印当前运行app的日志,我们一般常见的做法是 1).获取包名 打开当前运行的app,然后输入如下命令,然后在第一行TASK后面的就可以看到包名 a ...

  8. 有趣!10个你不得不知的Linux终端游戏

    关注「实验楼」,每天分享一个项目教程 Linux 终端在多数人眼中,是一个非常单调和无聊的工作环境,一个纯黑色背景的输入框,一串串让人记哭的命令,仿佛这些就是它的全部.但是这篇文章可能会改变你的一些想 ...

  9. Linux简介,linux终端符号含义

    世界充满里假象,只有苦痛不会说谎.                           ------<摔跤吧,爸爸> 目前主要有三大系统1.Windows:2.Mac os:3.Linux ...

最新文章

  1. following symbols must have non local/private scope错误问题解决方法
  2. 你会先写PRD,还是先画原型?
  3. udp协议服务器客户端流程图,UDP 协议通信服务器端客户端.doc
  4. TokenInsight:反映区块链行业整体表现的TI指数较昨日同期上涨4.73%
  5. 面试准备——Java回顾:高级编程(多线程、常用类、集合、泛型、IO流、反射、动态代理、新特性)
  6. PHP面向对象构造函数,析构函数
  7. Mac笔记本查看端口
  8. MySQL学习之路(一):Windows平台下MySQL安装、启动、连接
  9. 【GIS导论】实验一 桌面GIS的功能与菜单操作
  10. 学计算机逻辑思维能力测试题,逻辑思维题(逻辑思维能力测试20题)
  11. 通过制作一个登录界面学习matlab app designer的基础使用方法
  12. JAVA-day18-Map集合遍历、HashMap、TreeMap、Collections、集合嵌套,模拟斗地主发牌
  13. mysql计算月初日期_mysql 获取上月、本月月初月末
  14. android游戏开发教程之基本概念
  15. java学习笔记 - 集合类综合案例 斗地主
  16. linux如何进入文件编辑,Linux 文件编辑工具
  17. Linux开机流程Systemdgrub
  18. 联想小新 Pad Plus 2023 款评测
  19. 如何在10分钟内开始使用MongoDB
  20. 失传万年的PS致富经典(三)

热门文章

  1. java 代码箭头代表什么_箭头运算符' - '在Java中做什么?
  2. 移动硬盘文件丢失如何找回?
  3. 移动硬盘数据丢失如何恢复
  4. 怎样给图片降噪?这几个图片降噪软件可以帮助你
  5. 计算机课说话检查200字,上课说话检讨书200字(精选10篇)
  6. 项目遇到的难点、印象深刻点总结
  7. 流畅安装、简单使用annie下载B站视频
  8. Kubernetes 健康状态检查(九)
  9. SpringMVC学习,总结
  10. 从现在开始探索工业元宇宙讲座发言稿 34500字