玩家可以通过
按键 | 功能 |
---|---|
a | 向左一格 |
d | 向右一格 |
s | 顺时针旋转90度 |
w | 逆时针旋转90度 |
玩家根据消除的行列数量获取得分
数量 | 得分 |
---|---|
1行 | 10分 |
2行 | 30分 |
3行 | 60分 |
4行 | 100分 |
当玩家某一列触碰到屏幕顶端而无法被消除时游戏结束
编辑器: 小熊猫c++ ——1.1.2
第三方库: easyx ——graphics.h
考虑方块的大小不会超过4*4所以用整型变量进行状压储存更加方便
具体如下
int Blocklist[] = {
0b1000100010001000,
0b1100100010000000,
0b1100010001000000,
0b1000110001000000,
0b0100110010000000,
0b1100110000000000,
0b0100111000000000
};
// c++ 用0b表示二进制数
这里将所有的方块的摆放位置尽量靠左,为了使其刚刚出现时不需要进行坐标调整
从坐标转换到下标
int getIndex(int x, int y) {
return 16 - ((x - 1) * 4 + y);
}
这里只实现了顺时针旋转90度 其实只需要将行和列交换一下(注意每一列要从下往上顺着赋值)
int TurnRight(int Block) {
int newBlock = 0;
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int indexo = getIndex(i, j), indexn = getIndex(j, 4 - i + 1); // 4 - i + 1 即为从下往上
newBlock |= ((Block >> indexo) & 1) << indexn;
}
}
return newBlock;
}
考虑到格子较少采用暴力算法,从下往上一行一行的扫,每次让上面的行下落一行
void CheckHoleLine() {
int linecnt = 0;
for (int i = Boardcol; i >= 1; i --) {
int cnt = 0;
for (int j = 1; j <= Boardrow; j ++) {
if (BlockMp[i][j]) cnt ++;
}
if (cnt == Boardrow) {
linecnt ++;
i ++; // 注意因为少了一行所以i要回到上一行
for (int j = i; j >= 1; j --) {
for (int k = 1; k <= Boardrow; k ++) {
BlockMp[j][k] = BlockMp[j - 1][k];
}
}
}
}
if (linecnt == 1) Score += 10;
else if (linecnt == 2) Score += 30;
else if (linecnt == 3) Score += 60;
else if (linecnt == 4) Score += 100;
}
外面用一个长方形保住,里面用Boardcol * Boardrow个小方块填充,如下:
void InitGame() {
NextBlockT = rand() % 7;
setcolor(WHITE);
rectangle(BoardLeft - Boardedge, BoardTop - Boardedge, BoardRight + Boardedge, BoardBottom + Boardedge);
rectangle(ShowBoardLeft - Boardedge, ShowBoardTop - Boardedge, ShowBoardRight + Boardedge, ShowBoardBottom + Boardedge);
setcolor(BLACK);
for (int i = 1; i <= Boardcol; i ++) {
for (int j = 1; j <= Boardrow; j ++) {
int xpos = BoardLeft + (j - 1) * Squaresize, ypos = BoardTop + (i - 1) * Squaresize;
DisplayBlock(xpos, ypos, BlockMp[i][j] != 0);
}
}
for (int i = 1; i <= ShowBoardcol; i ++) {
for (int j = 1; j <= ShowBoardrow; j ++) {
int xpos = ShowBoardLeft + (j - 1) * Squaresize, ypos = ShowBoardTop + (i - 1) * Squaresize;
int index = getIndex(i, j);
DisplayBlock(xpos, ypos, (Blocklist[NextBlockT] >> index) & 1);
}
}
}
DisplayBlock 用于画每一个单元格,如下:
void DisplayBlock(int x, int y, bool show) {
if (show) setfillcolor(WHITE), setcolor(BLACK);
else setfillcolor(BLACK), setcolor(WHITE);
fillrect(x, y, x + Squaresize, y + Squaresize);
}
因为要响应鼠标消息,这里将一次下落一行拆分成Grades步 使用Grades方便调整速度
下落时要检测到底没有:
bool canDown(int x, int y, int Block) {
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int index = getIndex(i, j);
if ((Block >> index) & 1) {
if (x + i > Boardcol || BlockMp[x + i][y + j - 1] == 1) return false;
}
}
}
return true;
}
左右是否可以移动 (注意4*4的模型中空格不算)
bool canRight(int x, int y, int Block) {
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int index = getIndex(i, j);
if ((Block >> index) & 1) {
if (y + j > Boardrow || BlockMp[x + i - 1][y + j] == 1) return false;
}
}
}
return true;
}
bool canLeft(int x, int y, int Block) {
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int index = getIndex(i, j);
if ((Block >> index) & 1) {
if (y + j - 2 < 1 || BlockMp[x + i - 1][y + j - 2] == 1) return false;
}
}
}
return true;
}
int GetFirstBlock(int Block) {
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int index = getIndex(i, j);
if ((Block >> index) & 1) return i;
}
}
}
int GetLeftBlock(int Block) {
int ans = 1e9;
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int index = getIndex(i, j);
if ((Block >> index) & 1) {
ans = min(ans, j);
}
}
}
return ans;
}
移动后还要将左上角的空格处理掉 (直接做一个减法即可)
int oldc = GetFirstBlock(NowBlock), oldr = GetLeftBlock(NowBlock);
int oldBlock = NowBlock;
NowBlock = TurnRight(TurnRight(TurnRight(NowBlock)));
int nwc = GetFirstBlock(NowBlock), nwr = GetLeftBlock(NowBlock);
NowBlockx += oldc - nwc;
NowBlocky += oldr - nwr;
完整代码如下:
#include
#include
#include
#include
using namespace std;
const int WINDOWS_WIDTH = 500, WINDOWS_HEIGHT = 540;
const int Squaresize = 15;
const int BoardLeft = 30, BoardTop = 20, ShowBoardLeft = 350, ShowBoardTop = 20;
const int Boardcol = 30, Boardrow = 15, ShowBoardcol = 4, ShowBoardrow = 4;
const int BoardRight = BoardLeft + Boardrow * Squaresize, BoardBottom = BoardTop + Boardcol * Squaresize, ShowBoardRight = ShowBoardLeft + ShowBoardrow * Squaresize, ShowBoardBottom = ShowBoardTop + ShowBoardcol * Squaresize;
const int Boardedge = 10;
const int Grades = 300;
const int TEXT_X = 350, TEXT_Y = 150;
int Score;
bool GameRun = true;
int BlockMp[Boardcol + 5][Boardrow + 5];
/*
0 没有方块
1 有还没有到位的方块
2 当前方块
*/
int Blocklist[] = {
0b1000100010001000,
0b1100100010000000,
0b1100010001000000,
0b1000110001000000,
0b0100110010000000,
0b1100110000000000,
0b0100111000000000
};
int NowBlockx, NowBlocky, NowBlockT, NowBlock, NextBlockT;
int getIndex(int x, int y) {
return 16 - ((x - 1) * 4 + y);
}
void SetBlock(int x, int y, int Block, int status) {
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int index = getIndex(i, j);
if (Block & (1 << index)) {
BlockMp[x + i - 1][y + j - 1] = status;
}
}
}
}
void DisplayBlock(int x, int y, bool show) {
if (show) setfillcolor(WHITE), setcolor(BLACK);
else setfillcolor(BLACK), setcolor(WHITE);
fillrect(x, y, x + Squaresize, y + Squaresize);
}
void DrawGame() {
setcolor(WHITE);
for (int i = 1; i <= Boardcol; i ++) {
for (int j = 1; j <= Boardrow; j ++) {
int xpos = BoardLeft + (j - 1) * Squaresize, ypos = BoardTop + (i - 1) * Squaresize;
DisplayBlock(xpos, ypos, BlockMp[i][j] != 0);
}
}
}
void InitGame() {
NextBlockT = rand() % 7;
setcolor(WHITE);
rectangle(BoardLeft - Boardedge, BoardTop - Boardedge, BoardRight + Boardedge, BoardBottom + Boardedge);
rectangle(ShowBoardLeft - Boardedge, ShowBoardTop - Boardedge, ShowBoardRight + Boardedge, ShowBoardBottom + Boardedge);
setcolor(BLACK);
for (int i = 1; i <= Boardcol; i ++) {
for (int j = 1; j <= Boardrow; j ++) {
int xpos = BoardLeft + (j - 1) * Squaresize, ypos = BoardTop + (i - 1) * Squaresize;
DisplayBlock(xpos, ypos, BlockMp[i][j] != 0);
}
}
for (int i = 1; i <= ShowBoardcol; i ++) {
for (int j = 1; j <= ShowBoardrow; j ++) {
int xpos = ShowBoardLeft + (j - 1) * Squaresize, ypos = ShowBoardTop + (i - 1) * Squaresize;
int index = getIndex(i, j);
DisplayBlock(xpos, ypos, (Blocklist[NextBlockT] >> index) & 1);
}
}
}
void DrawNextBlock() {
setcolor(WHITE);
for (int i = 1; i <= ShowBoardcol; i ++) {
for (int j = 1; j <= ShowBoardrow; j ++) {
int xpos = ShowBoardLeft + (j - 1) * Squaresize, ypos = ShowBoardTop + (i - 1) * Squaresize;
int index = getIndex(i, j);
DisplayBlock(xpos, ypos, (Blocklist[NextBlockT] >> index) & 1);
}
}
}
int TurnRight(int Block) {
int newBlock = 0;
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int indexo = getIndex(i, j), indexn = getIndex(j, 4 - i + 1);
newBlock |= ((Block >> indexo) & 1) << indexn;
}
}
return newBlock;
}
bool canDown(int x, int y, int Block) {
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int index = getIndex(i, j);
if ((Block >> index) & 1) {
if (x + i > Boardcol || BlockMp[x + i][y + j - 1] == 1) return false;
}
}
}
return true;
}
bool canRight(int x, int y, int Block) {
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int index = getIndex(i, j);
if ((Block >> index) & 1) {
if (y + j > Boardrow || BlockMp[x + i - 1][y + j] == 1) return false;
}
}
}
return true;
}
bool canLeft(int x, int y, int Block) {
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int index = getIndex(i, j);
if ((Block >> index) & 1) {
if (y + j - 2 < 1 || BlockMp[x + i - 1][y + j - 2] == 1) return false;
}
}
}
return true;
}
int GetFirstBlock(int Block) {
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int index = getIndex(i, j);
if ((Block >> index) & 1) return i;
}
}
}
int GetLeftBlock(int Block) {
int ans = 1e9;
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
int index = getIndex(i, j);
if ((Block >> index) & 1) {
ans = min(ans, j);
}
}
}
return ans;
}
void DownNowBlock() {
NowBlockT = NextBlockT;
NextBlockT = rand() % 7;
DrawNextBlock();
NowBlockx = 1;
NowBlocky = 1;
NowBlock = Blocklist[NowBlockT];
SetBlock(NowBlockx, NowBlocky, NowBlock, 2);
DrawGame();
while (canDown(NowBlockx, NowBlocky, NowBlock)) {
SetBlock(NowBlockx, NowBlocky, NowBlock, 0);
NowBlockx += 1;
SetBlock(NowBlockx, NowBlocky, NowBlock, 2);
DrawGame();
for (int i = 1; i <= Grades; i ++) {
if (kbhit()) {
char op = getch();
if (op == 'w') { // 逆时针旋转
SetBlock(NowBlockx, NowBlocky, NowBlock, 0);
int oldc = GetFirstBlock(NowBlock), oldr = GetLeftBlock(NowBlock);
int oldBlock = NowBlock;
NowBlock = TurnRight(TurnRight(TurnRight(NowBlock)));
int nwc = GetFirstBlock(NowBlock), nwr = GetLeftBlock(NowBlock);
NowBlockx += oldc - nwc;
NowBlocky += oldr - nwr;
if (!canLeft(NowBlockx, NowBlocky + 1, NowBlock) || !canRight(NowBlockx, NowBlocky - 1, NowBlock)) {
NowBlock = oldBlock;
NowBlockx -= oldc - nwc;
NowBlocky -= oldr - nwr;
}
SetBlock(NowBlockx, NowBlocky, NowBlock, 2);
DrawGame();
} else if (op == 's') {
SetBlock(NowBlockx, NowBlocky, NowBlock, 0);
int oldc = GetFirstBlock(NowBlock), oldr = GetLeftBlock(NowBlock);
int oldBlock = NowBlock;
NowBlock = TurnRight(NowBlock);
int nwc = GetFirstBlock(NowBlock), nwr = GetLeftBlock(NowBlock);
NowBlockx += oldc - nwc;
NowBlocky += oldr - nwr;
if (!canLeft(NowBlockx, NowBlocky + 1, NowBlock) || !canRight(NowBlockx, NowBlocky - 1, NowBlock)) {
NowBlock = oldBlock;
NowBlockx -= oldc - nwc;
NowBlocky -= oldr - nwr;
}
SetBlock(NowBlockx, NowBlocky, NowBlock, 2);
DrawGame();
} else if (op == 'a') {
SetBlock(NowBlockx, NowBlocky, NowBlock, 0);
if (canLeft(NowBlockx, NowBlocky, NowBlock)) NowBlocky --;
SetBlock(NowBlockx, NowBlocky, NowBlock, 2);
DrawGame();
} else if (op == 'd') {
SetBlock(NowBlockx, NowBlocky, NowBlock, 0);
if (canRight(NowBlockx, NowBlocky, NowBlock)) NowBlocky ++;
SetBlock(NowBlockx, NowBlocky, NowBlock, 2);
DrawGame();
}
}
Sleep(1);
}
}
SetBlock(NowBlockx, NowBlocky, NowBlock, 0);
SetBlock(NowBlockx, NowBlocky, NowBlock, 1);
}
bool checkOver() {
for (int i = 1; i <= Boardrow; i ++) {
if (BlockMp[1][i]) return 1;
}
return 0;
}
void CheckHoleLine() {
int linecnt = 0;
for (int i = Boardcol; i >= 1; i --) {
int cnt = 0;
for (int j = 1; j <= Boardrow; j ++) {
if (BlockMp[i][j]) cnt ++;
}
if (cnt == Boardrow) {
linecnt ++;
i ++;
for (int j = i; j >= 1; j --) {
for (int k = 1; k <= Boardrow; k ++) {
BlockMp[j][k] = BlockMp[j - 1][k];
}
}
}
}
if (linecnt == 1) Score += 10;
else if (linecnt == 2) Score += 30;
else if (linecnt == 3) Score += 60;
else if (linecnt == 4) Score += 100;
}
void ShowScore() {
ostringstream output;
output << "得分: " << Score;
setcolor(RED);
setfont(25, 0, "黑体");
outtextxy(TEXT_X, TEXT_Y, output.str().c_str());
}
int main() {
srand(time(0));
initgraph(WINDOWS_WIDTH, WINDOWS_HEIGHT);
InitGame();
DrawGame();
ShowScore();
while (GameRun && is_run()) {
DownNowBlock(); // 控制当前方块落下
CheckHoleLine(); // 删除完整的行
ShowScore();
if (checkOver()) {
GameRun = false;
}
}
getch();
closegraph();
cleardevice();
return 0;
}