为了方便在其它程序中测试,将方块的功能包装成了一个类,下面是头文件Tetris.h的内容

欢迎测试并提出宝贵意见,其中有个bug不知到怎么回事,有时落下的方块没显示

//俄罗斯方块C++语言源代码,vs2019编译通过
#pragma once
#include <stdio.h>
#include <Windows.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <string.h>
#include <math.h>
//游戏区大小
#define ROW 29 //游戏区行数,建议不小于29,否则乱屏
#define COL 20 //游戏区列数
//键码
#define SPACE 32 //空格键
#define ESC 27 //Esc键
//四个方向键控制方块姿态,方便习惯右手操作的用户
#define LEFT 75
#define RIGHT 77
#define DOWN 80
#define UP 72 //用于旋转方块
//其它
#define LenofName 11
struct Face
{int data[ROW][COL + 20] = { 0 }; //用于标记指定位置是否有方块(1为有,0为无)int color[ROW][COL + 20] = { 0 }; //用于记录指定位置的方块颜色编码
};struct Block//用于存储7种基本形状方块的各自的4种形态的信息,共28种
{int space[4][4] = { 0 };
};
//游戏得分数据
typedef struct Data {char user[LenofName];int hisScore;int hisGrade;//写完了发现这个数没意义,因为可以通过hisScore计算得到int max;Face history;
}DATA;
class Tetris {
private:int lines;//记录消去的行数,控制得分权值int disScore;//屏显分数int forceGrade;//强制等级int grade;//等级int difficulty;//下落刷新时间,单位msFace face;Block block[7][4];DATA data;//设置方块大小void SetFont(int size = 20);//重新开始的清理工作void Restart();//配置运行环境void ConfigEnvironment();//光标跳转void CursorJump(int x, int y);//初始化界面void InitInterface();//初始化方块信息void InitBlockInfo();//颜色设置void color(int num);//画出方块void DrawBlock(int shape, int form, int x, int y);//空格覆盖void DrawSpace(int shape, int form, int x, int y);//合法性判断int IsLegal(int shape, int form, int x, int y);//判断得分与结束int JudeFunc();//游戏记录DATA ReadGrade();//更新最高分到文件int WriteGrade(DATA);//根据得分调整下落速度int AdjustDifficulty();//刷新游戏灯牌void Display();
public:Tetris();int StartGame();
};

类中函数的实现部分,文件名Tetris.app

#include "Tetris.h"#pragma warning (disable:4996) //消除警告,兼容旧版本库文件Tetris::Tetris() {//通过构造函数完成初始化lines = 1;disScore =0;forceGrade = 0;data = ReadGrade();grade = data.hisGrade;//延续上次的等级difficulty = AdjustDifficulty();//重新计算下落时间ConfigEnvironment();SetFont();InitInterface();InitBlockInfo();}//配置运行窗口void Tetris:: ConfigEnvironment() {system("chcp 936");//设置utf-8字符集65001,GBK字符集936,如果乱码才需要更改//设置标题char cmd[60];sprintf(cmd, "title 俄罗斯方块:%s", data.user);//含变量的DOS命令,序列化到字符中再传递system(cmd);//设置cmd窗口的大小sprintf(cmd,"mode con lines=%d cols=%d" ,ROW, 2*COL+40);//改变ROW,COL时窗口自动调整大小system(cmd);//设置随机数起点,每次启动,游戏会有不同的开局srand((unsigned int)time(NULL));//隐藏光标CONSOLE_CURSOR_INFO curInfo; //光标结构体变量curInfo.dwSize = 1;  //如果没赋值的话,隐藏光标无效curInfo.bVisible = FALSE; //可见为TRUEHANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输出句柄   SetConsoleCursorInfo(handle, &curInfo); //设置光标信息//游戏界面最大化会破坏布局,禁用最大化HWND hwnd = GetConsoleWindow();HMENU hmenu = GetSystemMenu(hwnd, false);      // 复制或修改而访问窗口菜单RemoveMenu(hmenu, SC_MAXIMIZE, MF_BYCOMMAND);    // 从指定菜单删除一个菜单项或分离一个子菜单DrawMenuBar(hwnd);//去除最大化菜单}//设置字体,一是美观,二是控制方块大小,太小的方块玩起来太累//虽然可以游戏启动后手动调节字体,但是为了具有良好游戏体验,直接设好吧void Tetris::SetFont(int size) {//默认大小为20号字,传入参数可以改变字体及方块大小CONSOLE_FONT_INFOEX cfi;//控制台字体信息的结构体cfi.cbSize = sizeof(CONSOLE_FONT_INFOEX);cfi.nFont = 0;cfi.dwFontSize.X = 0;cfi.dwFontSize.Y = size;  //设置字体大小cfi.FontFamily = FF_DONTCARE;cfi.FontWeight = FW_NORMAL; //字体粗细 FW_BOLDwcscpy_s(cfi.FaceName, L"隶书");  //设置字体,必须是控制台已有的SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfi);//根据结构体内容改变字体}//重新开始void Tetris::Restart() {//清空游戏区方块for (int i = 0; i < ROW-1; i++) {for (int j = 2; j < 2*COL - 2; j+=2) {CursorJump(j, i);printf("  ");//两个空格填充一个方块}}//清除当前分数disScore = 0;forceGrade = 0;grade = 0;//游戏速度降到最低,不再延续以前的速度继续CursorJump(2 * COL + 22, 16);printf("                ");//这里可能写了字,清除掉Display();//刷新游戏灯牌//清除已落下的方块for (int i = 0; i < ROW-1; i++) {for (int j = 1; j < COL - 1; j++) {face.data[i][j] = 0;face.color[i][j] = 0;}}return;}
//光标跳转
void Tetris::CursorJump(int x, int y)
{COORD pos; //光标位置的结构体变量pos.X = x; //横坐标pos.Y = y; //纵坐标HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //获取控制台句柄SetConsoleCursorPosition(handle, pos); //设置光标位置
}
//刷新游戏灯牌
void Tetris:: Display() {color(7);//白色int g = grade < forceGrade ? forceGrade:grade ;//高等级优先CursorJump(2 * COL + 31, 6);//光标要跳到正确位置再修改相应内容printf("%d", g);CursorJump(2 * COL + 23, 8);int i=0;for (; i <= g; i++) {//显示一个看似酷炫的速度进度条color(0xae);//被景绿色,前景黄色printf(">");}for (; i <= 9; i++) {color(0x80);//灰色背景printf(" ");}color(7);//改回白色CursorJump(2 * COL + 31, 12);printf("%-5d", disScore);CursorJump(2 * COL + 31, 14);difficulty = AdjustDifficulty();printf("%-4dms", difficulty);
}
//初始化界面
void Tetris::InitInterface()
{color(0x38); //边框颜色for (int i = 0; i < ROW; i++){for (int j = 0; j < COL + 20; j++){if (j == 0 || j == COL - 1 || j == COL + 9||j==COL+19)//竖线位置{face.data[i][j] = 1; //标记该位置有方块CursorJump(2 * j, i);printf("◆");}else if (i == ROW - 1){face.data[i][j] = 1;printf("◆");}elseface.data[i][j] = 0;}}for (int i = COL; i < COL + 10; i++)//左栏横线{face.data[8][i] = 1; CursorJump(2 * i, 8);printf("◆");}for (int i = COL+10; i < COL + 20; i++)//右栏横线{face.data[18][i] = 1; CursorJump(2 * i, 18);printf("◆");}color(7);//操作说明文字设置为白色CursorJump(2 * COL+4, 1);printf("下一个方块");CursorJump(2 * COL + 4, ROW - 19);printf("左移:A←");CursorJump(2 * COL + 4, ROW - 17);printf("右移:F→");CursorJump(2 * COL + 4, ROW - 15);printf("加速:D ↓");CursorJump(2 * COL + 4, ROW - 13);printf("旋转:空格↑");CursorJump(2 * COL + 4, ROW - 11);printf("暂停: S");CursorJump(2 * COL + 4, ROW - 9);printf("退出: esc");CursorJump(2 * COL + 4, ROW - 7);printf("重新开始:R");CursorJump(2 * COL + 2, ROW-5);printf("继续上次游戏:C");CursorJump(2 * COL + 2, ROW-3);printf("更换新用户名:U");//游戏灯牌CursorJump(2 * COL + 22, 2);printf("直接跳级提速");CursorJump(2 * COL + 22, 4);printf("请选择:0--9");CursorJump(2 * COL + 22, 6);printf("当前等级:%d",grade);CursorJump(2 * COL + 22, 10);printf("最高纪录:%-5d", data.max);//估计玩到大于10万分就觉得没意思了,所以5位数宽度就够了CursorJump(2 * COL + 22, 12);printf("当前分数:%-5d", disScore);CursorJump(2 * COL + 22, 14);difficulty = AdjustDifficulty();printf("下落速度:%-4dms", difficulty);Display();//画一下进度条
//打印游戏说明CursorJump(2 * COL + 21, 20);printf("将方块垒整齐得分");CursorJump(2 * COL + 21, 21);printf("连续消多行多得分");CursorJump(2 * COL + 21, 23);printf("中途保存可按esc");CursorJump(2 * COL + 21, 24);printf("游戏结束不会保存");CursorJump(2 * COL + 21, 25);printf("根据你的分数速度");CursorJump(2 * COL + 21, 26);printf("只能提速不能降速");
}
//初始化方块信息
void Tetris::InitBlockInfo()//7种方块28种形态预先存入数组,供显示使用
{//“T”形for (int i = 0; i <= 2; i++)block[0][0].space[1][i] = 1;block[0][0].space[2][1] = 1;//“L”形for (int i = 1; i <= 3; i++)block[1][0].space[i][1] = 1;block[1][0].space[3][2] = 1;//“J”形for (int i = 1; i <= 3; i++)block[2][0].space[i][2] = 1;block[2][0].space[3][1] = 1;for (int i = 0; i <= 1; i++){//“Z”形block[3][0].space[1][i] = 1;block[3][0].space[2][i + 1] = 1;//“S”形block[4][0].space[1][i + 1] = 1;block[4][0].space[2][i] = 1;//“O”形block[5][0].space[1][i + 1] = 1;block[5][0].space[2][i + 1] = 1;}//“I”形for (int i = 0; i <= 3; i++)block[6][0].space[i][1] = 1;int temp[4][4];for (int shape = 0; shape < 7; shape++) //7种形状{for (int form = 0; form < 3; form++) //4种形态,已经有了一种,每个还需增加3种{//获取第form种形态for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){temp[i][j] = block[shape][form].space[i][j];}}//将第form种形态顺时针旋转,得到第form+1种形态for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){block[shape][form + 1].space[i][j] = temp[3 - j][i];}}}}
}
//颜色设置
void Tetris::color(int c)
{//c可以用两位十六进制数表示,高位为背景色,低位为前景色,也可以写转换后的10进制数switch (c){case 0:c = 13; //“T”形方块设置为紫色break;case 1:case 2:c = 12; //“L”形和“J”形方块设置为红色break;case 3:case 4:c = 10; //“Z”形和“S”形方块设置为绿色break;case 5:c = 14; //“O”形方块设置为黄色break;case 6:c = 11; //“I”形方块设置为浅蓝色break;case 7:c = 7; //文字设置为白色break;default:c=c;//默认根据色码设定}SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); //调用API设置颜色
}
//画出方块
void Tetris::DrawBlock(int shape, int form, int x, int y)
{for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){if (block[shape][form].space[i][j] == 1) //如果该位置有方块{CursorJump(2 * (x + j), y + i); //光标跳转到指定位置printf("■"); //输出方块}}}
}
//空格覆盖
void Tetris::DrawSpace(int shape, int form, int x, int y)
{for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){if (block[shape][form].space[i][j] == 1) //如果该位置有方块{CursorJump(2 * (x + j), y + i); printf("  "); //两个空格占用一个方块的位置}}}
}
//合法性判断
int Tetris::IsLegal(int shape, int form, int x, int y)
{for (int i = 3; i >=0; i--)//从方块下沿开始判断,可能少循环几次,提高一点点性能{for (int j = 0; j <4; j++){//如果方块落下的位置本来就已经有方块了,则不合法if ((block[shape][form].space[i][j] == 1) && (face.data[y + i][x + j] == 1))return 0; //不合法}}return 1; //合法
}
//调整游戏难度
int Tetris::AdjustDifficulty() {int t;//这里t越小,方块下落越快,根据得分调整游戏难度int score;if (forceGrade > grade) {//有强制提速score = disScore % 1000 + forceGrade * 1000;}else {//根据等级设置速度,防止速度正反馈score = disScore % 1000 + grade * 1000;}if (score < 9000) {t = 1000 - sqrt(score)*9.4;//非线性调整}else {t = 100;//极限挑战,只加分不提速,如果感觉难度不算极限,可以改小一点}return t;
}
//从文件读取数据
DATA Tetris::ReadGrade() {DATA d;FILE* pf = fopen("record.dat", "r"); //以只读方式打开文件if (pf == NULL) //第一次运行无此文件{//创建一个具有初始数据的新文件strcpy(d.user, "古老的经典\0");d.hisScore = 0;d.hisGrade = 0;d.max = 0;for (int i = 0; i < ROW; i++)//初始化face再保存{for (int j = 0; j < COL + 20; j++){if (j == 0 || j == COL - 1 || j == COL + 9 || j == COL + 19){face.data[i][j] = 1; //标记该位置有方块                    }else if (i == ROW - 1){face.data[i][j] = 1;//最下面一行全是方块 }elseface.data[i][j] = 0; //一个方块都没落下}}d.history = face;//防止第一次运行就试图继续上次游戏,会造成方块掉入无底深渊pf = fopen("record.dat", "w"); //自动创建该文件if (pf == NULL) {//创建文件失败CursorJump(COL, ROW / 2);printf("你的存储介质为只读类型,无法创建游戏数据文件");CursorJump(COL, ROW / 2+2);printf("按任意键继续进入游戏……");system("pause>nul");}else {fwrite(&d, sizeof(DATA), 1, pf);}}else {fseek(pf, 0, SEEK_SET); //使文件指针pf指向文件开头fread(&d, sizeof(DATA), 1, pf); //读取文件中的数据fclose(pf); //关闭文件pf = NULL; //防止内存泄露}return d;//读取失败游戏也可以玩,因为d被初始化了
}
//保存得分记录
int Tetris::WriteGrade(DATA d) {FILE* pf = fopen("record.dat", "w");if (pf == NULL) {CursorJump(COL, ROW / 2 + 4);printf("保存游戏数据失败,record.dat文件为只读或存储介质为只读");CursorJump(COL, ROW / 2 + 6);printf("按任意键直接退出……");system("pause>nul");return 1;}else{fwrite(&d, sizeof(DATA), 1, pf);fclose(pf); pf = NULL; }return 0;
}
//判断是否得分
int Tetris::JudeFunc()
{for (int i = ROW - 2; i > 4; i--)//最底层开始判断{int sum = 0; //记录第i行的方块个数for (int j = 1; j < COL - 1; j++){sum += face.data[i][j]; //统计第i行的方块个数}if (sum == 0) {break;//最后一行没有方块,无需再判断其上的层次}else if (sum == COL - 2) //该行全是方块,可得分{disScore += 10 * lines * lines; //根据一次性得分行数加分for (int j = 1; j < COL - 1; j++) //清除整行的方块{face.data[i][j] = 0; //标记为无方块既被清除}//把被清除行上面的行整体向下挪一格for (int m = i; m > 1; m--){sum = 0; //记录上一行的方块个数for (int n = 1; n < COL - 1; n++){sum += face.data[m - 1][n]; //统计上一行的方块个数face.data[m][n] = face.data[m - 1][n]; //将上一行方块的标识移到下一行face.color[m][n] = face.color[m - 1][n]; //将上一行方块的颜色编号移到下一行if (face.data[m][n] == 1) //上一行移下来的是方块,打印方块{CursorJump(2 * n, m); //光标跳转到该位置color(face.color[m][n]); //颜色设置为原方块的颜色printf("■"); //打印方块}else //上一行移下来的是空格,打印空格{CursorJump(2 * n, m); //光标跳转到该位置printf("  "); //打印空格(两个空格)}}//上一行移下来的全是空格,无需再将上层的方块向下移动(移动结束)if (sum == 0)return 1;  //移动下来的可能还有满行,还需调用该函数进行判断   }}}lines = 1;//重置连续消掉的行数return 0; //返回值用于结束调用者的死循环
}
//游戏主体逻辑函数
int Tetris::StartGame(){clock_t start, end=clock();//用于计时char ch;int gameover = 0;int nextShape,nextForm;int x, y;//方块坐标int shape = rand() % 7, form = rand() % 4; //随机获取方块的形状和形态while (1){//主循环,用于不断产生新的方块nextShape = rand() % 7, nextForm = rand() % 4; //随机获取下一个方块的形状和形态x = COL / 2 - 2,y = 0;//初始位置color(nextShape); //颜色设置为下一个方块的颜色DrawBlock(nextShape, nextForm, COL + 3, 3); //将下一个方块显示在右上角//下落循环,控制方块不断下落while (1){color(shape); //颜色设置为当前正在下落的方块DrawBlock(shape, form, x, y); //将该方块显示在初始下落位置start = clock();//计时开始while (kbhit()) {//下落过程中不断检测键盘是否有动作,用于控制方块ch = getch(); //读取keycodeswitch (ch){case 'd': case 'D':case DOWN://方向键:下if (IsLegal(shape, form, x, y + 1)==1) //判断方块向下移动一位后是否合法{DrawSpace(shape, form, x, y); //用空格覆盖当前方块所在位置y++; //下一次显示方块时就相当于下落了一格了DrawBlock(shape, form, x, y);//及时重画该方块}break;case 'a': //方便左手操作case 'A':case LEFT://方向键:左,方便右手操作if (IsLegal(shape, form, x - 1, y) == 1) {DrawSpace(shape, form, x, y); x--;DrawBlock(shape, form, x, y);}break;case 'f': case 'F':case RIGHT://方向键:右if (IsLegal(shape, form, x + 1, y) == 1) {DrawSpace(shape, form, x, y); x++; DrawBlock(shape, form, x, y);}break;case SPACE: //空格键case UP://方向,上if (IsLegal(shape, (form + 1) % 4, x, y) == 1){DrawSpace(shape, form, x, y); form = (form + 1) % 4;DrawBlock(shape, form, x, y);}break;case 's'://暂停case 'S':CursorJump(2 * COL + 4, ROW - 11);printf("%-10s", "任意键继续");//让用户知道自己暂停了system("pause>nul"); //按任意键继续color(7);CursorJump(2 * COL + 4, ROW - 11);printf("%-10s","暂停: S");//恢复运行后,将操作提示写回去break;case 'r'://重新开始case 'R':Restart();break;case ESC: //esc键system("cls"); //清空屏幕color(7);CursorJump(COL, ROW / 2);printf("确认要保存游戏并退出吗?(y/n):");CursorJump(COL, ROW / 2-4);printf("不想保存直接退出请再次按esc");while (1) {//必须做出正确选择ch = getch();if (ch == 'y' ||ch== 'Y') {//同意保存退出if (disScore > data.max) { data.max = disScore; }data.hisScore = disScore;data.hisGrade = grade;data.history = face;//保存现场WriteGrade(data);return 1;//结束所有循环,返回主程序}else if (ch == 'n' || ch == 'N') {system("cls");//保护现场Face tempFace=face;InitInterface();//重画界面会清除数据face = tempFace;//恢复现场for (int i = 1; i < ROW - 1; i++) {for (int j = 1; j < COL - 1; j++) {if (face.data[i][j] == 1) {CursorJump(2*j,i);color(face.color[i][j]); //颜色设置为原方块的颜色printf("■"); //打印方块}}}DrawBlock(nextShape, nextForm, COL + 3, 3);//画出下一个方块break;//结束读取循环}else if (ch == ESC) {return 1;//相当于双击esc直接退出游戏}else {Beep(500,500);//输入错误发出提示音}}break;case 'U'://改名操作case 'u': {CursorJump(2 * COL + 22, 16);printf("姓名:");CursorJump(2 * COL + 27, 16);color(8);printf("最多五个字");color(7);CursorJump(2 * COL + 27, 16);//显示光标CONSOLE_CURSOR_INFO curInfo; curInfo.dwSize = 1;curInfo.bVisible = true;HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);  SetConsoleCursorInfo(handle, &curInfo);char cmd[600];//如果非要输入大于这个数的字符串也溢出scanf("%s", cmd);if (strlen(cmd)<LenofName) {//处理一下用户名溢出strcpy(data.user, cmd);sprintf(cmd, "title 俄罗斯方块当前用户:%s", data.user);system(cmd);//把你的名字写在标题栏,装酷WriteGrade(data);}else {CursorJump(13, ROW/2);printf("你的名字太长了");}//隐藏光标curInfo.bVisible = false;SetConsoleCursorInfo(handle, &curInfo);CursorJump(2 * COL + 22, 16);//回到起始位置,擦掉刚才写的字printf("               ");break;}case 'C'://继续上次游戏case 'c':Face temFace=face;system("cls"); //清空屏幕CursorJump(COL, ROW / 2);color(7);printf("确认要恢复上次游戏继续玩吗?(y/任意键继续当前游戏):");ch = getch();if (ch == 'y' || ch == 'Y') {system("cls");data=ReadGrade();disScore = data.hisScore;grade = data.hisGrade;forceGrade = 0;//恢复时没有强制提速InitInterface();face = data.history;difficulty = AdjustDifficulty();//恢复游戏速度Display();}else {//误操作时继续system("cls");InitInterface();face = temFace;}//恢复现场for (int i = 1; i < ROW - 1; i++) {for (int j = 1; j < COL - 1; j++) {if (face.data[i][j] == 1) {CursorJump(2 * j, i);color(face.color[i][j]); //颜色设置为原方块的颜色printf("■"); //打印方块}}}DrawBlock(nextShape, nextForm, COL + 3, 3);//画出下一个方块break;}//越级调整游戏难度,既方块下落速度if (ch >= '0' && ch <= '9') {int g=ch-'0';//起步速度为上次最高得分的速度,想降速,根据本局得分确定可以将到的最低速度if (g>=grade) {//速度选择正确forceGrade = g;difficulty = AdjustDifficulty();Display();}else{//给点提示,为什么不让降速CursorJump(2 * COL + 22, 16);printf("坚持!别走回头路");Beep(500, 500);}}}if (start-end>=difficulty) //下落时间到达{if (IsLegal(shape, form, x, y + 1)==1) //可以下落{DrawSpace(shape, form, x, y); y++; DrawBlock(shape, form, x, y);}else if(IsLegal(shape, form, x, y + 1) == 0)//不再下落{//face:记录界面的每个位置是否有方块,若有方块还需记录该位置方块的颜色。for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){if (block[shape][form].space[i][j]==1){face.data[y + i][x + j] = 1; //将该位置标记为有方块face.color[y + i][x + j] = shape; //记录该方块的颜色数值}}}//判断此次方块下落是否得分while (JudeFunc()) {//有得分情况下lines++;//有连续满行//根据分数调整等级if (disScore / 1000 > 9) {//防止得分过万显示大于9的等级grade = 9;}else if (disScore / 1000 < data.hisGrade) {//延续历史速度grade = data.hisGrade; }else {grade = disScore / 1000;}difficulty = AdjustDifficulty();//重新计算下落时间Display();//擦掉试图降速时写的字CursorJump(2 * COL + 22, 16);//printf("坚持!别走回头路");printf("                ");}break; //跳出当前死循环,准备进行下一个方块的下落}end = start;//重新开始计时}Sleep(20);//休眠20ms,减少无用循环次数,降低CPU占用率,否则CPU30%消耗在这个死循环}//判断游戏是否结束for (int j = 1; j < COL - 1; j++){if (face.data[1][j] == 1) {//最上面一行有方块就OVERgameover = 1;//用于后面处理GAME OVER事项break;}}//游戏结束放在循环外面,这样方便退出死循环if (gameover){//弄点动静Beep(523, 400);//do  Beep(578, 400);//re  Beep(659, 400);//miSleep(1200);//等上面的doremiif (disScore / 1000 <= 9) { data.hisGrade = disScore / 1000; }//下次玩的初始速度else { data.hisGrade = 0; }//分数过万且创记录,相当于通过所有挑战而爆机,等级恢复最低system("cls"); color(7); CursorJump(2 * (COL / 3), ROW / 2 - 3);if (disScore > data.max){printf("恭喜你创造出新的世界记录%d,留给后人慢慢挑战吧!", disScore);data.max = disScore;}else if (disScore == data.max){printf("你已追平世界记录,离超越只差一点点");}else{printf("你与最高记录相差%d,请继续加油", data.max - disScore);}WriteGrade(data);//不管玩不玩,还是保存一下吧CursorJump(2 * (COL / 3), ROW / 2);printf("GAME OVER");CursorJump(2 * (COL / 3), ROW / 2 + 3);printf("再来一局?(y/n):");while (1)//要有明确选择才肯放过你{ch = getch();if (ch == 'y' || ch == 'Y'){gameover = 0;system("cls");InitInterface();Restart();break;//跳出本死循环,进入主死循环,就开始了新的一局}else if (ch == 'n' || ch == 'N'){return 1;//直接跳出死循环返回主程序}else//错误选择鸣笛{Beep(500, 500);}}}//准备下一个方块shape = nextShape, form = nextForm;DrawSpace(nextShape, nextForm, COL + 3, 3); //将右上角的方块信息用空格覆盖}
}

主程序,仅仅为了测试一下

#include "Tetris.h"
int main()
{Tetris t = Tetris();t.StartGame(); //开始游戏return 0;
}

错误之处敬请批评指正

俄罗斯方块,C语言源文件,带有详细的注释相关推荐

  1. 求10000里的阶乘C语言,最详细的注释,看不懂你来打我

    描述 求10000以内n的阶乘. 格式 输入格式 只有一行输入,整数n(0≤n≤10000). 输出格式 一行,即n!的值. 样例 输入样例 4 输出样例 24 代码 #include<stdi ...

  2. 机器翻译c语言,最详细的注释,看不懂你来打我

    描述 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章. 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换.对于每个英文单词,软件会先在内存中查找这 ...

  3. 二叉树的非递归遍历算法C语言实现(详细注释版)

    二叉树的非递归算法遍历分为:先序遍历,中序遍历,后序遍历. 此文章我会根据先.中.后的顺序为大家用C语言实现全部代码. 顾名思义先序遍历是先遍历根节点,随后是左孩子,右孩子 . 中序遍历与后序遍历可以 ...

  4. 俄罗斯方块-C语言-详注版

    代码地址如下: http://www.demodashi.com/demo/14818.html 俄罗斯方块-C语言-详注版 概述 本文详述了C语言版俄罗斯方块游戏的原理以及实现方法,对游戏代码进行了 ...

  5. 超详细中文注释的GPT2新闻标题生成项目

    超详细中文注释的GPT2新闻标题生成项目:https://zhuanlan.zhihu.com/p/338171330 笔者开源了一个带有超详细中文注释的GPT2新闻标题生成项目. 该项目参考了GPT ...

  6. Python编程 统计Java源文件代码行数,注释行数,空白行数

    每次学习新的语言,就想重新实现一遍做过的课设=,= 这里实现的是"综合性实验 Java源代码分析程序"的第三部分 第二部分见:[Python编程]统计目录下Java源文件的关键字出 ...

  7. c语言魔王语言上机报告,魔王语言报告(带有完整程序).doc

    魔王语言报告(带有完整程序) 西安郵電學院 目: 魔王语言 院系名称: 专业名称: 班 级: 学生姓名: 学号(8位): 指导教师: 设计起止时间: 一. 设计目的 以栈和队列为数据结构,使用文件读写 ...

  8. R语言曲面拟合代码详细分析(1)

    #代码参考<R语言数据可视化之美-专业图表绘制指南>例4.2.1,主要代码链接参见 #https://github.com/EasyChart/Beautiful-Visualizatio ...

  9. R语言ggplot2可视化数据点注释、标签显示不全、发生边界截断问题解决实战

    R语言ggplot2可视化数据点注释.标签显示不全.发生边界截断问题解决实战 目录 R语言ggplot2

  10. c语言关键字不做标识符,C语言标识符、关键字、注释、表达式和语句

    这一节主要讲解C语言中的几个基本概念. 标识符 定义变量时,我们使用了诸如 a.abc.mn123 这样的名字,它们都是标识符(Identifier). 标识符就是程序员自己起的名字,除了变量名,后面 ...

最新文章

  1. Oracle 10g如何对用户姓名,按首字母排序、查询
  2. Win32汇编数据对齐相关的伪指令(ALIGN、EVEN、ORG)
  3. linux系统修改系统时间
  4. FreeModbus移植到STM32F107(以太网传输方式)
  5. 信息学奥赛一本通(1233:接水问题)
  6. mysql中写锁定实例_MySQL中的锁
  7. unity Mirror使用笔记
  8. Java知多少(9) import及Java类的搜索路径
  9. IP通信基础 3.21
  10. linux查看网卡吞吐量和网卡流量用自带命令,iptraf查看。
  11. zabbix---agent安装
  12. java多线程 同一资源_同一资源多线程并发访问时的完整性
  13. java请假系统毕业设计_jsp企业员工考勤管理系统
  14. initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
  15. ping命令和查找计算机,ping命令查网速,电脑测网速ping命令
  16. 裸金属服务器能虚拟化吗,裸金属服务器虚拟化概述
  17. 关于一些Ubuntu网络问题的解决办法
  18. canvas学习笔记
  19. Win10微软补丁KB5018410致金蝶客户端无法连接中间件
  20. 专业流程拓扑软件IAuto3.1.1用户操作手册——赶紧收藏,功能比processon、visio、draw.io更强大!小巧易用!

热门文章

  1. linux文件管理器thunar,文件管理器:Nautilus,Thunar,PCManFM,Konqueror,Dolphin,Krusader
  2. USB VIDPID 表
  3. 2017 idea 代码字体加粗
  4. android 微信小程序 本地包,Android 7 以上版本微信小程序抓包方法
  5. retinex算法原理
  6. 华为第1书:《华为交换机学习指南》当当网预售中
  7. mysql字符串查询_mysql字符串查询常用命令
  8. 数据结构课程设计(已完结)
  9. 在线卡密销售系统之JAVA WEB学习之路
  10. css模糊遮罩效果_CSS 半透明遮罩层