和贪吃蛇在同一时期写的,私以为比我在网上找到的那些其他的控制台版的俄罗斯方块更精致
成品地址:链接: http://pan.baidu.com/s/1jIo9Ovs 密码: 7k8j
当时初学编程,废寝忘食地写着玩的,现在看看优化余地很大。
与之前的贪吃蛇一样R键刷新界面显示,空格暂停,“暂停”两字写在游戏右侧。这次没做花哨的开始界面,也是Visual studio2015写的,一样会生成一个保存分数的文件
上:翻转;下:瞬间下落;左右:就是左右 ESC:退出游戏(退出游戏时做了一个略花哨的动画)
//俄罗斯方块
#include
#include
#include
#include
using namespace std;
/**********************************/
//根据小键盘,将8、2、4、6定义为上下左右,5为默认,0为退出游戏
#define Sb 16//Screen的宽度
#define Sh 21//Screen的高度
bool Screen[Sh + 3][Sb + 2] = { 0 };
unsigned Speed_mulriple_limit = 2;
unsigned Speed_mulriple = 8;
unsigned SleepTime = 100;
unsigned Score = 0;
unsigned Max=0;
struct Tetris {
bool shape[4][4];
unsigned type;
unsigned x, y;
}Tnow;
/**********************************/
void Start();
void Game();
void End();
void Interface();
void ScreenPrint();
void ScreenClear();
void NextShow(unsigned);
void Pause();
void TBuild(Tetris&, unsigned);
void TRotate(Tetris&);
void TMove(Tetris&, int);
void TDown(Tetris&);
void TCopy(Tetris&, const Tetris&);
void TShow(const Tetris&);
void TClear(const Tetris&);
int Judge_down(const Tetris&);
int Judge_key();
int Judge_eliminate(const Tetris&);
int Judge_gameover(const Tetris&);
void Pos(unsigned, unsigned);
void PosScreen(unsigned, unsigned);
void Swap(bool&, bool&);
/**********************************/
void Start() {
system("mode con cols=80 lines=25");
const CONSOLE_CURSOR_INFO cursor{ (DWORD)100,FALSE };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor);
srand((unsigned)time(0));
ifstream i("tetris_data.dat", ios_base::binary);
if (!i) i.close();
else {
unsigned s;
i >> s;
Max = s;
i.close();
}
for (int i = 0;i < Sb + 2;++i)Screen[Sh + 2][i] = Screen[Sh + 1][i] = 1;
for (int i = 0;i < Sh + 2;++i)Screen[i][0] = Screen[i][Sb + 1] = 1;
Pos(12, 16);cout << "要开始游戏,请先关闭输入法,再";system("pause");system("cls");
Interface();
}
void Game() {
unsigned type_now = rand() % 7;
unsigned type_next = rand() % 7;
TBuild(Tnow, type_now);
NextShow(type_next);
Tetris Tp;//记录前面一步以方便删除轨迹
TCopy(Tp, Tnow);
int count = 1;
int speed_count = 1;
while (++count) {
if (Judge_down(Tnow)) {
Tp.type = 233;
ScreenPrint();
if (int lines=Judge_eliminate(Tnow)) {
Score += 15*lines-5;
if (Score > Max)Max = Score;
++speed_count;
speed_count %= 6;
if (!speed_count&&Speed_mulriple>Speed_mulriple_limit)Speed_mulriple -= 1;
Pos(14, 56);cout << Score;
Pos(15, 56);cout << SleepTime*Speed_mulriple << 's';
Pos(16, 58);cout << Max;
ScreenClear();
ScreenPrint();
Sleep(10);
}
type_now = type_next;
type_next = rand() % 7;
TBuild(Tnow, type_now);
Judge_gameover(Tnow);
NextShow(type_next);
}
switch (Judge_key()) {
case 8:TRotate(Tnow);break;
case 4:TMove(Tnow, 4);break;
case 6:TMove(Tnow, 6);break;
case 2:TDown(Tnow);break;
case 0:PosScreen(10, 4);cout << "Escape from Tetris!";End();
}
TClear(Tp);
TShow(Tnow);
TCopy(Tp, Tnow);
if (!(count %= Speed_mulriple)) { count = 1;++Tnow.x; }
Sleep(SleepTime);
}
}
void End() {
ofstream o("tetris_data.dat", ios_base::binary);
if (!o) o.close();
else {
o << Max;
o.close();
}
PosScreen(1, 1);
int num = 0;
int times = 0;
int sl = 3;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 119);
while (num < 336) {
int i, j;
PosScreen(times + 1, times + 1);
for (i = times + 1;i < Sb - times;++i) {
cout << "■";
++num;
Sleep(sl);
}
for (j = times + 1;j < Sh - times;++j) {
PosScreen(j, i);
cout << "■";
++num;
Sleep(sl);
}
for (;i > times + 1;--i) {
PosScreen(j, i);
cout << "■";
++num;
Sleep(sl);
}
for (;j > times + 1;--j) {
PosScreen(j, i);
cout << "■";
++num;
Sleep(sl);
}
++times;
}
exit(0);
}
void Interface() {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 8);
Pos(2, 3);cout << "■■■■■■■■■■■■■■■■■■\n";//18x
for (int i = 3;i < 24;++i)cout << " ■\n";
cout << " ■■■■■■■■■■■■■■■■■■\n";
for (int i = 3;i < 24;++i) {
Pos(i, 37); cout << "■";
if (i <= 8 || i >= 12) {
Pos(i, 47); cout << "■";
Pos(i, 69); cout << "■";
}
}
Pos(2, 47); cout << "■■■■■■■■■■■■";//12x
Pos(8, 47); cout << "■■■■■■■■■■■■";
Pos(12, 47); cout << "■■■■■■■■■■■■";
Pos(24, 47); cout << "■■■■■■■■■■■■";
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
Pos(9, 53);cout << "下一个 方块";
Pos(14, 51);cout << "得分:" << Score;
Pos(15, 51);cout << "速度:" << SleepTime*Speed_mulriple << 's';
Pos(16, 51);cout << "最高分:" << Max;
Pos(17, 51);cout << "按R键图像复位";
Pos(18, 54);cout << "用于输入法导";
Pos(19, 54);cout << "致的显示错误";
Pos(20, 51);cout << "上下左右操控";
Pos(21, 51);cout << "按空格键暂停";
Pos(22, 51);cout << "按ESC结束游戏";
}
void ScreenPrint() {
for (int i = 1;i <= Sh;++i) {
for (int j = 1;j <= Sb;++j) {
if (Screen[i][j]) {
PosScreen(i, j);
cout << "■";
}
}
}
}
void ScreenClear() {
for (int i = 1;i <= Sh;++i)
for (int j = 1;j <= Sb;++j) {
PosScreen(i, j);cout << " ";
}
}
void NextShow(unsigned t) {
Pos(3, 49);cout << " ";
Pos(4, 49);cout << " ";
Pos(5, 49);cout << " ";
Pos(6, 49);cout << " ";
Pos(7, 49);cout << " ";
if (t == 0) { Pos(5, 55);cout << "■■■■"; }
else if (t == 1) { Pos(4, 57);cout << "■■";Pos(5, 57);cout << "■■"; }
else if (t == 2) { Pos(4, 59);cout << "■";Pos(5, 55);cout << "■■■"; }
else if (t == 3) { Pos(4, 57);cout << "■";Pos(5, 55);cout << "■■■"; }
else if (t == 4) { Pos(4, 55);cout << "■";Pos(5, 55);cout << "■■■"; }
else if (t == 5) { Pos(4, 57);cout << "■■";Pos(5, 55);cout << "■■"; }
else { Pos(4, 55);cout << "■■";Pos(5, 57);cout << "■■"; }
}
void Pause() {
Pos(11, 55);cout << "暂 停";
do {
Sleep(200);
} while (!GetAsyncKeyState(VK_SPACE));
Pos(11, 55);cout << " ";
}
void TBuild(Tetris& t, unsigned sh) {
t.x = 0;
t.type = sh;
switch (sh)
{
case 0: {
t.shape[0][0] = 0;t.shape[0][1] = 0;t.shape[0][2] = 0;t.shape[0][3] = 0;//
t.shape[1][0] = 1;t.shape[1][1] = 1;t.shape[1][2] = 1;t.shape[1][3] = 1;//■■■■
t.shape[2][0] = 0;t.shape[2][1] = 0;t.shape[2][2] = 0;t.shape[2][3] = 0;//
t.shape[3][0] = 0;t.shape[3][1] = 0;t.shape[3][2] = 0;t.shape[3][3] = 0;//青色
t.y = 7;
break;
}
case 1: {
t.shape[0][0] = 1;t.shape[0][1] = 1;t.shape[0][2] = 0;t.shape[0][3] = 0;//■■
t.shape[1][0] = 1;t.shape[1][1] = 1;t.shape[1][2] = 0;t.shape[1][3] = 0;//■■
t.shape[2][0] = 0;t.shape[2][1] = 0;t.shape[2][2] = 0;t.shape[2][3] = 0;//
t.shape[3][0] = 0;t.shape[3][1] = 0;t.shape[3][2] = 0;t.shape[3][3] = 0;//蓝
t.y = 8;
break;
}
case 2: {
t.shape[0][0] = 0;t.shape[0][1] = 0;t.shape[0][2] = 1;t.shape[0][3] = 0;// ■
t.shape[1][0] = 1;t.shape[1][1] = 1;t.shape[1][2] = 1;t.shape[1][3] = 0;//■■■
t.shape[2][0] = 0;t.shape[2][1] = 0;t.shape[2][2] = 0;t.shape[2][3] = 0;//
t.shape[3][0] = 0;t.shape[3][1] = 0;t.shape[3][2] = 0;t.shape[3][3] = 0;//紫
t.y = 7;
break;
}
case 3: {
t.shape[0][0] = 0;t.shape[0][1] = 1;t.shape[0][2] = 0;t.shape[0][3] = 0;// ■
t.shape[1][0] = 1;t.shape[1][1] = 1;t.shape[1][2] = 1;t.shape[1][3] = 0;//■■■
t.shape[2][0] = 0;t.shape[2][1] = 0;t.shape[2][2] = 0;t.shape[2][3] = 0;//
t.shape[3][0] = 0;t.shape[3][1] = 0;t.shape[3][2] = 0;t.shape[3][3] = 0;//绿
t.y = 7;
break;
}
case 4: {
t.shape[0][0] = 1;t.shape[0][1] = 0;t.shape[0][2] = 0;t.shape[0][3] = 0;//■
t.shape[1][0] = 1;t.shape[1][1] = 1;t.shape[1][2] = 1;t.shape[1][3] = 0;//■■■
t.shape[2][0] = 0;t.shape[2][1] = 0;t.shape[2][2] = 0;t.shape[2][3] = 0;//
t.shape[3][0] = 0;t.shape[3][1] = 0;t.shape[3][2] = 0;t.shape[3][3] = 0;//红
t.y = 7;
break;
}
case 5: {
t.shape[0][0] = 0;t.shape[0][1] = 1;t.shape[0][2] = 1;t.shape[0][3] = 0;// ■■
t.shape[1][0] = 1;t.shape[1][1] = 1;t.shape[1][2] = 0;t.shape[1][3] = 0;//■■
t.shape[2][0] = 0;t.shape[2][1] = 0;t.shape[2][2] = 0;t.shape[2][3] = 0;//
t.shape[3][0] = 0;t.shape[3][1] = 0;t.shape[3][2] = 0;t.shape[3][3] = 0;//橙色
t.y = 7;
break;
}
case 6: {
t.shape[0][0] = 1;t.shape[0][1] = 1;t.shape[0][2] = 0;t.shape[0][3] = 0;//■■
t.shape[1][0] = 0;t.shape[1][1] = 1;t.shape[1][2] = 1;t.shape[1][3] = 0;// ■■
t.shape[2][0] = 0;t.shape[2][1] = 0;t.shape[2][2] = 0;t.shape[2][3] = 0;//
t.shape[3][0] = 0;t.shape[3][1] = 0;t.shape[3][2] = 0;t.shape[3][3] = 0;//黄色
t.y = 7;
break;
}
default: {Pos(1, 1);cerr << "Error 2:方块种类出错!";exit(1);}
}
}
void TRotate(Tetris& t) {
if (t.type == 0) {
Swap(t.shape[0][1], t.shape[1][0]);
Swap(t.shape[2][1], t.shape[1][2]);
Swap(t.shape[3][1], t.shape[1][3]);
for (int i = 0;i < 4;++i)
for (int j = 0;j < 4;++j)
if (t.shape[i][j])
if (i + t.x > Sh || j + t.y>Sb || Screen[t.x + i][t.y + j]) {
Swap(t.shape[0][1], t.shape[1][0]);
Swap(t.shape[2][1], t.shape[1][2]);
Swap(t.shape[3][1], t.shape[1][3]);
}
}
else if (t.type == 1);
else {
bool tmp[3][3];
for (int i = 0;i < 3;++i)
for (int j = 0;j < 3;++j)
tmp[i][j] = t.shape[i][j];
t.shape[0][0] = tmp[2][0];
t.shape[0][1] = tmp[1][0];
t.shape[0][2] = tmp[0][0];
t.shape[1][0] = tmp[2][1];
t.shape[1][2] = tmp[0][1];
t.shape[2][0] = tmp[2][2];
t.shape[2][1] = tmp[1][2];
t.shape[2][2] = tmp[0][2];
for (int i = 0;i < 3;++i)
for (int j = 0;j < 3;++j)
if (t.shape[i][j])
if (i + t.x > Sh || j + t.y>Sb || Screen[t.x + i][t.y + j]) {
for (int i = 0;i < 3;++i)
for (int j = 0;j < 3;++j)
t.shape[i][j] = tmp[i][j];
}
TShow(t);
}
}
void TMove(Tetris& t, int d) {
d -= 5;
for (int i = 0;i < 4;++i)
for (int j = 0;j < 4;++j)
if (t.shape[i][j] && Screen[t.x + i][t.y + j + d])
return;
t.y += d;
}
void TDown(Tetris& t) {
TClear(t);
int l = 0, i = 0, j = 0;
while (1) {
for (i = 0;i < 4;++i)
for (j = 0;j < 4;++j)
if (t.shape[i][j] && Screen[t.x + i + 1][t.y + j]) {
TShow(t);
return;
}
++t.x;
}
Sleep(20);
}
void TCopy(Tetris& tt, const Tetris& t) {
tt.type = t.type;
tt.x = t.x, tt.y = t.y;
for (int i = 0;i < 4;++i)
for (int j = 0;j < 4;++j)
tt.shape[i][j] = t.shape[i][j];
}
void TShow(const Tetris& t) {
for (int i = 0;i < 4;++i)
for (int j = 0;j < 4;++j)
if (t.shape[i][j] && (t.x + i != 0)) {
PosScreen(t.x + i, t.y + j);
cout << "■";
}
}
void TClear(const Tetris& t) {
if (t.type == 233)return;
for (int i = 0;i < 4;++i)
for (int j = 0;j < 4;++j)
if (t.shape[i][j] && (t.x + i != 0)) {
PosScreen(t.x + i, t.y + j);
cout << " ";
}
}
int Judge_down(const Tetris& t) {
for (int i = 0;i < 4;++i)
for (int j = 0;j < 4;++j)
if (t.shape[i][j] && Screen[t.x + i][t.y + j]) {
for (int i = 0;i < 4;++i)
for (int j = 0;j < 4;++j)
if (t.shape[i][j])
Screen[t.x + i - 1][t.y + j] = 1;
return 1;
}
return 0;
}
int Judge_key() {
unsigned d = 5;
if (GetAsyncKeyState(VK_UP)) d = 8;
else if (GetAsyncKeyState(VK_DOWN)) d = 2;
else if (GetAsyncKeyState(VK_LEFT)) d = 4;
else if (GetAsyncKeyState(VK_RIGHT)) d = 6;
else if (GetAsyncKeyState(VK_SPACE)) Pause();
else if (GetAsyncKeyState(VK_ESCAPE)) d = 0;
else if (GetAsyncKeyState(0x52)) {
system("cls");
Interface();
ScreenPrint();
Pos(4, 49);cout << "R键图像复位导致下一";
Pos(5, 49);cout << "个方块的显示失效BUG";
Pos(6, 49);cout << "不高兴修复了";
}
return d;
}
int Judge_eliminate(const Tetris& t) {
int judge = 0;
for (int i = 0;i < 4;++i) {
for (int j = 0;j < 4;++j)
if (t.shape[i][j]) {
int k;
unsigned xx = t.x - 1;
for (k = 1;k <= Sb&&Screen[xx + i][k];++k);
if (k > Sb) {
++judge;
int blank = 0;
if (xx == 1) {
for (int l = 1;l <= Sb;++l)
Screen[1][l] = 0;
break;
}
while (blank != Sb) {
blank = 0;
for (int l = 1;l <= Sb;++l) {
Screen[xx + i][l] = Screen[xx + i - 1][l];
if (!Screen[xx + i - 1][l])++blank;
}
--xx;
}
}
break;
}
}
return judge;
}
int Judge_gameover(const Tetris& t) {
for (int i = 0;i < 4;++i)
if (t.shape[1][i] && Screen[1][t.y + i]) {
PosScreen(10, 6);cout << "Game Over!";
End();
}
return 0;
}
void Pos(unsigned x, unsigned y) {
COORD p;
try { if (x < 1 || y < 1) throw 1; }//测试代码,记得删除
catch (int) { Pos(1, 1);cerr << "Error 1:坐标出错!";exit(1); }//测试代码,记得删除
p.X = y - 1;p.Y = x - 1;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), p);
}
void PosScreen(unsigned x, unsigned y)
{
Pos(x + 2, 2 * y + 3);
}
void Swap(bool& a, bool& b) {
bool t = a;
a = b;b = t;
}
int main()
{
Start();
Game();
Pos(11, 50);
return 0;
}
截图: