#ifndef _BLOCK_H_ #define _BLOCK_H_ #include <stdbool.h> #define SIZE 26 #define SLEN 14 //游戏池占有状态 static int mblock[SIZE][SLEN] = { { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,1,1,1,1,1,1,1,1,1,1,1,1,1 } }; //保存每个位置方块颜色 static int colour[SIZE][SLEN]= { { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 7,7,7,7,7,7,7,7,7,7,7,7,7,7 } }; //方块类型 static int block[7][4] = { { 0x0660, 0x0660, 0x0660, 0x0660 }, // 方块 { 0x0072, 0x0262, 0x0270, 0x0232 }, // T { 0x0223, 0x0074, 0x0622, 0x0170 }, // L { 0x0226, 0x0470, 0x0322, 0x0071 }, // J { 0x0063, 0x0264, 0x0063, 0x0264 }, // Z { 0x006C, 0x0462, 0x006C, 0x0462 }, // S { 0x00F0, 0x2222, 0x00F0, 0x2222 }, // I }; //游戏历史排行榜 typedef struct fraction { int one; int two; int three; } Fraction; //游戏当前统计 typedef struct nowfraction { int score; int grade; int difficulty; } NowFraction; //保存当前方块和下一个方块 typedef struct random { int a; int b; } Random; //游戏暂停 static int PauseGame = 0; //指定坐标打印 void gotoxy(int x, int y); //初始化地图 void MapBlock(); //随机生成方块 void rollblock(Random *temp); //打印下一个方块 void ShowBlock(int n, int m); //移动方块 void MoveBlock(int n, int m, const NowFraction *pst); //检测顶部满池 bool GameOver(); //游戏说明 void Explain(const NowFraction *pst1, const Fraction *pst2); //满行消除 void CleanBlock(NowFraction *pst); //写入分数 bool WriteScore(const NowFraction *pst1, Fraction *pst2); #endif
#include <stdio.h> #include <Windows.h> #include <string.h> #include "block.h" void gotoxy(int x, int y) { COORD pos = { x,y }; HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);// 获取标准输出设备句柄 SetConsoleCursorPosition(hOut, pos);//两个参数分别是指定哪个窗体,具体位置 } //游戏说明 void Explain(const NowFraction *pst1, const Fraction *pst2) { gotoxy(40, 0); printf("历史排行榜:"); gotoxy(44, 2); printf("第1名: %d", pst2->one); gotoxy(44, 4); printf("第2名: %d", pst2->two); gotoxy(44, 6); printf("第3名: %d", pst2->three); gotoxy(40, 8); printf("游戏说明:"); gotoxy(44, 10); printf("控制: ↑ ↓ ← → 空格"); gotoxy(40, 12); printf("游戏统计:"); gotoxy(44, 14); printf("得分: %d", pst1->score); gotoxy(44, 16); printf("等级: %d", pst1->grade); gotoxy(44, 18); printf("难度: %d", pst1->difficulty); gotoxy(40, 20); printf("游戏状态: "); gotoxy(40, 24); printf("By: Mr. Lei"); } //初始化地图 void MapBlock() { int i; for (i = 0; i < SIZE; i++) { gotoxy(0, i); printf("■"); gotoxy(26, i); printf("■"); } for (i = 2; i < 26; i += 2) { gotoxy(i, 25); printf("■"); } for (i = 30; i < 38; i += 2) { gotoxy(i, 0); printf("─"); gotoxy(i, 6); printf("─"); } gotoxy(28, 0); printf("┌"); gotoxy(38, 0); printf("┐"); gotoxy(28, 6); printf("└"); gotoxy(38, 6); printf("┘"); for (i = 1; i < 6; i++) { gotoxy(28, i); printf("│"); gotoxy(38, i); printf("│"); } gotoxy(0, SIZE); } //随机生成方块 void rollblock(Random *temp) { static int count = 0; if (count == 0) { temp[0].a = rand() % 7; temp[0].b = rand() % 4; temp[1].a = rand() % 7; temp[1].b = rand() % 4; count++; } else { temp[0].a = temp[1].a; temp[0].b = temp[1].b; temp[1].a = rand() % 7; temp[1].b = rand() % 4; } } //打印下一个方块 void ShowBlock(int n, int m) { int i, j; int x, y; int t; static int a, b; t = 0; for (i = 0, y = 0; i < 4; i++) { for (j = 0, x = 0; j < 4; j++) { gotoxy(36 - x, 4 - y); printf(" "); t++; x += 2; } y++; } t = 0; for (i = 0, y = 0; i < 4; i++) { for (j = 0, x = 0; j < 4; j++) { if (((block[n][m] >> t) & 01) == 1) { gotoxy(36 - x, 4 - y); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), n + 1); printf("■"); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7); } x += 2; t++; } y++; } } //移动方块 void MoveBlock(int n, int m, const NowFraction *pst) { int i, j; int x, y; int t; int Y; int count; int counttemp; int countline = 0; int countY = 0; int num = m; int line; line = 0; int speed = 400 - (pst->difficulty - 1) * 20; int templine = 0; //保存左右移动用来检测是否可以移动 int tempnum = m; for (Y = 0; Y < SIZE; Y++) { //清空上一行打印方块 for (i = 0, y = 0, t = 0; i < 4; i++) { for (j = 0, x = 0; j < 4; j++) { if (Y - 1 - y < 0) break; if (((block[n][num] >> t) & 01) == 1) { gotoxy(16 + templine - x, Y - 1 - y); printf(" "); } t++; x += 2; } y++; } //按键检测 if (GetAsyncKeyState(VK_UP)) { tempnum = (tempnum + 1) % 4; } else if (GetAsyncKeyState(VK_LEFT) && Y >= 2) { line -= 2; } else if (GetAsyncKeyState(VK_RIGHT) && Y >= 2) { line += 2; } else if (GetAsyncKeyState(VK_SPACE)) { speed = 10; } else if (GetAsyncKeyState(VK_RETURN) && PauseGame == 1) { PauseGame = 2; } //角度旋转碰撞检测 if (tempnum != num) { for (i = 0, count = 0, y = 0, t = 0; i < 4; i++) { for (j = 0, x = 0; j < 4; j++) { if (Y - y < 0) break; if (((block[n][tempnum] >> t) & 01) == 1) { if (mblock[Y - y][(16 + templine - x) / 2] == 1) count++; } t++; x += 2; } y++; } if (count > 0) { tempnum = num; } else num = tempnum; } //平移碰撞检测 if (templine != line) { Y--; if (countY == 0 || countline == 0) countY = Y; for (i = 0, count = 0, y = 0, t = 0; i < 4; i++) { for (j = 0, x = 0; j < 4; j++) { if (Y - y < 0) break; if (((block[n][num] >> t) & 01) == 1) { if (mblock[Y - y][(16 + line - x) / 2] == 1) count++; if ((16 + line - x) <= 0 || (16 + line - x) / 2 >= 13) count++; } t++; x += 2; } y++; } if (count > 0) { Y++; templine = templine; line = templine; } else { countline++; if (countline >= 1 && countY == Y) { speed = 50; countline = 0; } templine = line; } } //连续平移加速后恢复 if (countY != Y && speed != 10) speed = 400 - (pst->difficulty - 1) * 20; //下一行检测碰撞如果检测到那么本行即为最后一行 for (i = 0, count = 0, y = 0, t = 0; i < 4; i++) { for (j = 0, x = 0; j < 4; j++) { if (Y - y < 0) break; if (((block[n][num] >> t) & 01) == 1) { if (mblock[Y + 1 - y][(16 + templine - x) / 2] == 1) count++; } t++; x += 2; } y++; } //检测碰撞前的平移 if (count > 0) { if (GetAsyncKeyState(VK_LEFT) && Y >= 2) { line -= 2; } else if (GetAsyncKeyState(VK_RIGHT) && Y >= 2) { line += 2; } if (templine != line) { for (i = 0, counttemp = 0, y = 0, t = 0; i < 4; i++) { for (j = 0, x = 0; j < 4; j++) { if (Y - y < 0) break; if (((block[n][num] >> t) & 01) == 1) { if (mblock[Y - y][(16 + line - x) / 2] == 1) counttemp++; if ((16 + line - x) <= 0 || (16 + line - x) / 2 >= 13) counttemp++; } t++; x += 2; } y++; } if (counttemp > 0) { templine = templine; line = templine; } else { templine = line; } } } //打印方块 for (i = 0, y = 0, t = 0; i < 4; i++) { for (j = 0, x = 0; j < 4; j++) { if (Y - y < 0) break; if (((block[n][num] >> t) & 01) == 1) { if (count > 0) { if (Y - y >= 0) { mblock[Y - y][(16 + templine - x) / 2] = 1; colour[Y - y][(16 + templine - x) / 2] = n + 1; } } gotoxy(16 + templine - x, Y - y); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), n + 1); printf("■"); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7); } t++; x += 2; } y++; } //检测到下一行有碰撞直接结束循环 if (count > 0) return; //游戏状态 if (PauseGame == 0) { gotoxy(52, 20); printf("请按Enter键开始"); while (1) { if (GetAsyncKeyState(VK_RETURN) && PauseGame == 0) { PauseGame = 1; break; } } gotoxy(0, SIZE); printf(" "); PauseGame = 1; } else if (PauseGame == 1) { gotoxy(52, 20); printf("游戏运行中 "); gotoxy(52, 22); printf("Enter键暂停游戏"); gotoxy(0, SIZE); } else if (PauseGame == 2) { gotoxy(52, 20); printf("游戏暂停中 "); gotoxy(52, 22); printf("Enter键开始游戏"); while (1) { if (GetAsyncKeyState(VK_RETURN) && PauseGame == 2) { PauseGame = 1; break; } } gotoxy(0, SIZE); printf(" "); PauseGame = 1; } if (GetAsyncKeyState(VK_DOWN)) { Sleep(80); } else Sleep(speed); gotoxy(0, SIZE); } } //检测顶部满池 bool GameOver() { int i; for (i = 1; i < 13; i++) { if (mblock[0][i] == 1) return false; } return true; } //满行消除 void CleanBlock(NowFraction *pst) { int i, j; int Count; int tot; int Line[SIZE - 1]; int x; int z; for (i = SIZE - 2, Count = 0; i >= 0; i--) { for (j = 1, tot = 0; j < 13; j++) { if (mblock[i][j] == 1) tot++; } if (tot == 12) { Line[Count] = i; Count++; } } if (Count > 0) { if (Count == 4 || Count == 1) { memmove(mblock[Count], mblock[0], (Line[0] + 1 - Count)*SLEN * sizeof(int)); memmove(colour[Count], colour[0], (Line[0] + 1 - Count)*SLEN * sizeof(int)); for (i = Count - 1; i >= 0; i--) { for (j = 1; j < 13; j++) { mblock[i][j] = 0; colour[i][j] = 7; } } } else if (Count == 2) { if (Line[0] - 1 == Line[1]) { memmove(mblock[Count], mblock[0], (Line[0] + 1 - Count)*SLEN * sizeof(int)); memmove(colour[Count], colour[0], (Line[0] + 1 - Count)*SLEN * sizeof(int)); for (i = Count - 1; i >= 0; i--) { for (j = 1; j < 13; j++) { mblock[i][j] = 0; colour[i][j] = 7; } } } else { for (z = 0; z < Count; z++) { memmove(mblock[1], mblock[0], (Line[z] + 1 - 1)*SLEN * sizeof(int)); memmove(colour[1], colour[0], (Line[z] + 1 - 1)*SLEN * sizeof(int)); for (j = 1; j < 13; j++) { mblock[0][j] = 0; colour[0][j] = 7; } } } } else { if (Line[0] - 1 == Line[1] && Line[1] - 1 == Line[2]) { memmove(mblock[Count], mblock[0], (Line[0] + 1 - Count)*SLEN * sizeof(int)); memmove(colour[Count], colour[0], (Line[0] + 1 - Count)*SLEN * sizeof(int)); for (i = Count - 1; i >= 0; i--) { for (j = 1; j < 13; j++) { mblock[i][j] = 0; colour[i][j] = 7; } } } else if (Line[0] - 1 == Line[1] && Line[1] - 1 != Line[2]) { memmove(mblock[2], mblock[0], (Line[0] + 1 - 2)*SLEN * sizeof(int)); memmove(colour[2], colour[0], (Line[0] + 1 - 2)*SLEN * sizeof(int)); for (i = 1; i >= 0; i--) { for (j = 1; j < 13; j++) { mblock[i][j] = 0; colour[i][j] = 7; } } memmove(mblock[1], mblock[0], (Line[2] + 1 - 1)*SLEN * sizeof(int)); memmove(colour[1], colour[0], (Line[2] + 1 - 1)*SLEN * sizeof(int)); for (i = Line[2]; i >= 0; i--) { for (j = 1; j < 13; j++) { if (i - 1 < 0) break; mblock[i][j] = mblock[i - 1][j]; colour[i][j] = colour[i - 1][j]; } } for (j = 1; j < 13; j++) { mblock[0][j] = 0; colour[0][j] = 7; } } else if (Line[0] - 1 != Line[1] && Line[1] - 1 == Line[2]) { memmove(mblock[1], mblock[0], (Line[0] + 1 - 1)*SLEN * sizeof(int)); memmove(colour[1], colour[0], (Line[0] + 1 - 1)*SLEN * sizeof(int)); for (j = 1; j < 13; j++) { mblock[0][j] = 0; colour[0][j] = 7; } memmove(mblock[2], mblock[0], (Line[1] + 1 - 2)*SLEN * sizeof(int)); memmove(colour[2], colour[0], (Line[1] + 1 - 2)*SLEN * sizeof(int)); for (i = 1; i >= 0; i--) { for (j = 1; j < 13; j++) { mblock[i][j] = 0; colour[i][j] = 7; } } } } for (i = Line[0]; i >= 0; i--) { for (j = 1, x = 2; j < 13; j++) { if (mblock[i][j] == 1) { gotoxy(x, i); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colour[i][j]); printf("■"); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); } else { gotoxy(x, i); printf(" "); } x += 2; } } pst->score += Count * 10; pst->grade = pst->score / 100 + 1; pst->difficulty = pst->score / 150 + 1; } } //写入分数 bool WriteScore(const NowFraction *pst1, Fraction *pst2) { bool judge; if (pst1->score > pst2->one&&pst1->score > pst2->two&&pst1->score > pst2->three) { pst2->three = pst2->two; pst2->two = pst2->one; pst2->one = pst1->score; judge = true; } else if (pst1->score <= pst2->one&&pst1->score > pst2->two&&pst1->score > pst2->three) { pst2->three = pst2->two; pst2->two = pst1->score; judge = true; } else if (pst1->score <= pst2->one&&pst1->score <= pst2->two&&pst1->score > pst2->three) { pst2->three = pst1->score; judge = true; } else judge = false; return judge; }
#include <stdio.h> #include <stdlib.h> #include <time.h> #include "block.h" int main() { Random roll[2]; NowFraction last1 = { 0,1,1 }; Fraction last2; errno_t err; FILE *fp; //如果没有数据文件,则创建新文件并初始化结构数据写入文件 while ((err = fopen_s(&fp, "data.dat", "rb")) != 0) { if ((err = fopen_s(&fp, "data.dat", "wb")) != 0) { fputs("错误: 创建数据文件失败\n", stderr); exit(EXIT_FAILURE); } last2.one = last2.two = last2.three = 0; fwrite(&last2, sizeof(Fraction), 1, fp); fclose(fp); } rewind(fp); //设置文件开头 fread(&last2, sizeof(Fraction), 1, fp); //读取文件数据 srand((unsigned int)time(0)); //随机种子 //地图初始化 MapBlock(); while (1) { Explain(&last1, &last2); rollblock(roll); ShowBlock(roll[1].a, roll[1].b); MoveBlock(roll[0].a, roll[0].b, &last1); CleanBlock(&last1); if (!GameOver()) { if (WriteScore(&last1, &last2)) { fclose(fp); if ((err = fopen_s(&fp, "data.dat", "wb")) != 0) { fputs("错误: 创建数据文件失败\n", stderr); exit(EXIT_FAILURE); } fwrite(&last2, sizeof(Fraction), 1, fp); } gotoxy(52, 20); printf("游戏结束, 按任意键退出游戏"); gotoxy(0, 27); break; } } //关闭文件 fclose(fp); system("pause"); return 0; }