提交源码

编译环境 MinGW gcc 7.2.0
This commit is contained in:
筱傑 2018-09-24 13:05:24 +08:00 committed by GitHub
parent 3ae470b557
commit 30fd245e7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 393 additions and 0 deletions

287
Tetris.cpp Normal file
View File

@ -0,0 +1,287 @@
/* Tetris.cpp -- file */
#include "Tetris.h"
bool printNextBoxVal = true; // 是否更新下一个方块的输出区
bool printMapVal = true; // 是否更新地图的输出区
bool isGameOver = false; // 是否游戏失败
char Map[mapWidth][mapHeight] = {0};
int speed = 400;
HANDLE hStdOut;
Box thisBox, nextBox;
// 检查该方块在地图上是否可行
bool isFeasible(const Box &target)
{
for(int YOffset = 0; YOffset < 4; ++YOffset)
{
for(int XOffset = 0; XOffset < 4; ++XOffset)
{
if(target.getShape() & (0x8000 >> (YOffset*4 + XOffset)))
{
// 如果该位置越界 返回false
if(target.x + XOffset < 0 || target.x + XOffset >= mapWidth
|| target.y + YOffset < 0 || target.y + YOffset >= mapHeight)
return false;
// 如果该位置上已经有方块
if(Map[target.x + XOffset][target.y + YOffset])
return false;
}
}
}
return true;
}
// 将方块固定在地图上
void fixedPos(const Box &target)
{
for(int YOffset = 0; YOffset < 4; ++YOffset)
{
for(int XOffset = 0; XOffset < 4; ++XOffset)
{
// 如果判断的位置越界
if(target.x + XOffset < 0 || target.x + XOffset >= mapWidth
|| target.y + YOffset < 0 || target.y + YOffset >= mapHeight)
continue;
if(target.getShape() & (0x8000 >> (YOffset*4 + XOffset)))
{
Map[target.x + XOffset][target.y + YOffset] = 1;
clearCompleted();
}
}
}
}
bool move(Box &A, char XOffset, char YOffset)
{
char oldX = A.x, oldY = A.y;
printBox(A, " ");
A.x += XOffset, A.y += YOffset;
if(!isFeasible(A))
{
A.x = oldX, A.y = oldY;
printBox(A, "");
if(YOffset > 0){ // 方块落下
fixedPos(A);
A = nextBox;
printNextBoxVal = true; // 通知 下一个方块显示区域更新
if(!isFeasible(A)) // 如果生成的方块的位置上已经有方块,判断游戏失败
{
isGameOver = true;
}
}
return false;
}
printBox(A, "");
return true;
}
bool rotate(Box &A)
{
char oldDir = A.dir;
A.dir = (A.dir + 1) % 4;
if(!isFeasible(A))
{
A.dir = oldDir;
return false;
}
A.dir = oldDir;
printBox(A, " ");
A.dir = (A.dir + 1) % 4;
printBox(A, "");
return true;
}
void clearCompleted()
{
for(int y = mapHeight-1, x = 0; y >= 0; )
{
for(x = 0; x < mapWidth; ++x)
{
if(!Map[x][y])
break;
}
// 达成条件
if(x == mapWidth)
{
// 把该层以上的所有方块往下移动一格
for(int j = y; j > 0; --j)
{
for(int i = 0; i < mapWidth; ++i)
{
Map[i][j] = Map[i][j-1];
}
}
// 清空顶层
for(int i = 0; i < mapWidth; ++i)
Map[i][0] = 0;
if(speed > 200)
speed -= 10;
printMapVal = true; // 通知更新地图
}else{ //未达成条件就接着往上检查
--y;
}
}
}
void restart()
{
for(int i = 0; i < mapWidth; ++i)
for(int j = 0; j < mapHeight; ++j)
Map[i][j] = 0;
printMapVal = true;
thisBox.randGenerateNewBox();
printNextBoxVal = true;
speed = 400;
isGameOver = false;
}
void printXY(COORD coord, std::string str)
{
SetConsoleCursorPosition(hStdOut, coord);
WriteConsole(hStdOut, str.c_str(), str.length(), NULL, NULL);
}
// 在指定位置输出方块x,y缺省为0如果为0则按照Box坐标输出
void printBox(const Box &target, std::string printChar, short x, short y)
{
short posX = x?x:target.x * 2 + 2; // +2是因为边框占了2格宽
short posY = y?y:target.y;
for(int YOffset = 0; YOffset < 4; ++YOffset)
{
for(int XOffset = 0; XOffset < 4; ++XOffset)
{
// 如果输出的位置不合法
if(posX + XOffset < 0 || posY + YOffset < 0)
continue;
if(target.getShape() & (0x8000 >> (YOffset*4 + XOffset)))
printXY({posX + XOffset*2, posY + YOffset}, printChar);
}
}
}
void showMap(short _x, short _y)
{
for(short x = 0; x <= mapWidth+1; ++x)
{
printXY({_x + x*2, _y + mapHeight}, "");
}
for(short y = 0; y < mapHeight; ++y)
{
printXY({_x, _y + y}, "");
printXY({_x + mapWidth * 2 + 2, _y + y}, "");
for(short x = 0; x < mapWidth; ++x)
{
printXY({_x + 2 + x*2, _y + y}, (Map[x][y] ? "" : " "));
}
}
}
void input()
{
char tempPos = 0;
switch(getch())
{
case 'w':
case 'W':
rotate(thisBox);
break;
case 'a':
case 'A':
move(thisBox, -1, 0);
break;
case 'd':
case 'D':
move(thisBox, 1, 0);
break;
case 's':
case 'S':
move(thisBox, 0, 1);
break;
case ' ':
while(move(thisBox, 0, 1));
break;
case 'z':
case 'Z':
for(int i = 0; i < mapWidth; ++i)
Map[i][mapHeight-1] = 1;
clearCompleted();
break;
case 'r':
case 'R':
restart();
break;
case '\n':
case '\r':
printXY({30, 14}, "暂停中...");
printXY({30, 15}, "按任意键继续");
getch();
printXY({30, 14}, " ");
printXY({30, 15}, " ");
break;
case 'q':
case 'Q':
exit(1);
break;
}
}
void GameLoop()
{
thisBox.randGenerateNewBox();
nextBox.randGenerateNewBox();
system("cls");
printXY({30, 5}, "w 旋转");
printXY({30, 6}, "s 下落一格");
printXY({30, 7}, "a 左移 d 右移");
printXY({30, 8}, "空格 直接落下");
printXY({30, 9}, "r 重新开始");
printXY({30, 10}, "回车键暂停");
printXY({30, 11}, "q 退出");
while(!isGameOver)
{
if(printMapVal)
{
showMap(0, 0);
printMapVal = false;
}
if(printNextBoxVal)
{
printXY({30, 0}, "next:");
printBox(nextBox, " ", 30, 1);
nextBox.randGenerateNewBox();
printBox(nextBox, "", 30, 1);
printNextBoxVal = false;
}
printBox(thisBox, "");
move(thisBox, 0, 1);
while(kbhit())
input();
if(isGameOver)
{
printXY({6, 10}, "游戏结束!");
printXY({4, 11}, "重新开始请按R");
char ch = getch();
if(ch == 'r' || ch == 'R')
restart();
}
Sleep(speed);
}
}
int main()
{
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
srand(std::time(NULL));
GameLoop();
return 0;
}

66
Tetris.h Normal file
View File

@ -0,0 +1,66 @@
/* Tetris.h -- file */
#ifndef _TETRIS_H_
#define _TETRIS_H_
#include <string>
#include <ctime>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
const char mapWidth = 10;
const char mapHeight = 20;
const char startX = mapWidth / 2 - 2;
const char startY = 0;
const char shapeListMax = 7;
const uint16_t shapeList[shapeListMax][4] = {
{0xcc00, 0xcc00, 0xcc00, 0xcc00}, // O
{0x4444, 0xf00, 0x4444, 0xf00 }, // I
{0x88c0, 0xe800, 0xc440, 0x2e00}, // L
{0x44c0, 0x8e00, 0xc880, 0xe200}, // J
{0x4c80, 0xc600, 0x4c80, 0xc600}, // Z
{0x8c40, 0x6c00, 0x8c40, 0x6c00}, // S
{0x4c40, 0x4e00, 0x8c80, 0xe400} // T
};
class Box {
public:
Box(char _index = 0, char _dir = 0, char _x = 0, char _y = 0)
:index(index), dir(_dir), x(_x), y(_y){};
uint16_t getShape() const {return shapeList[index][dir];};
void randGenerateNewBox()
{
index = rand() % shapeListMax;
dir = 1; // 起始方向
x = startX; // 起始x坐标
y = startY; // 起始y坐标
}
public:
char index;
char dir;
char x;
char y;
};
// 检查该方块在地图上是否可行
bool isFeasible(const Box &target);
// 将方块固定在地图上
void fixedPos(const Box &target);
// 移动方块到指定偏移量上
bool move(Box &A, char XOffset, char YOffset);
// 旋转方块
bool rotate(Box &A);
// 清除达成目标的方块
void clearCompleted();
// 在指定坐标上输出字符串
void printXY(COORD coord, std::string str);
// 在指定坐标上输出指定字符的方块
void printBox(const Box &target, std::string printChar, short x = 0, short y = 0);
// 展示地图
void showMap(COORD coord);
// 获取用户输入并判断
void input();
// 游戏循环
void GameLoop();
#endif

BIN
a.exe Normal file

Binary file not shown.

40
data.txt Normal file
View File

@ -0,0 +1,40 @@
1100110000000000
O = 0xcc00
0100 0000
0100 1111
0100 0000
0100 0000
I = 0x44 0xf00
1000 1110 1100 0010
1000 1000 0100 1110
1100 0000 0100 0000
0000 0000 0000 0000
L = 0x88c0 0xe800 0xc440 0x2e00
0100 1000 1100 1110
0100 1110 1000 0010
1100 0000 1000 0000
0000 0000 0000 0000
J = 0x44c0 0x8e00 0xc880 0xe200
1100 0100
0110 1100
0000 1000
0000 0000
Z = 0xc600 0x4c80
0110 1000
1100 1100
0000 0100
0000 0000
S = 0x6c00 0x8c40
1110 0100 0100 1000
0100 1100 1110 1100
0000 0100 0000 1000
0000 0000 0000 0000
T = 0xe400 0x4c40 0x4e00 0x8c80
¨ˆ¨ˆ¨€¨€

BIN
tetris.exe Normal file

Binary file not shown.