#include<iostream>
#include<cstdlib>
#include<vector>
#include <chrono>
#include <future>
#include<conio.h>
#include <fstream>
#include <algorithm>
const int MAP_W = 10;
const int MAP_H = 24;
int gameend_flag = 0;
int GameScore = 0;
/*std::vector<std::vector<bool>>*/bool GAME_MAP[MAP_W] /*std::vector<bool>(*/[MAP_H];
//方块类型
enum class TetroType {
I,
J,
L,
O,
S,
T,
Z
};
struct Tetromino {
int x, y; //中心块坐标
int Side_Block [3][2]; //边缘方块相对坐标
};
class Block {
public:
Block() //随机形状,方块初始化
{
TetroType TypeList[7] = { TetroType::I,TetroType::J,TetroType::L,TetroType::O,TetroType::S,TetroType::T,TetroType::Z };
int i = rand() % 7;
MyTetroType = TypeList[i];
switch (MyTetroType) {
case TetroType::I:
MyTrtro.x = 3;
MyTrtro.y = 3;
MyTrtro.Side_Block[0][0] = MyTrtro.x - 1;
MyTrtro.Side_Block[0][1] = MyTrtro.y;
MyTrtro.Side_Block[1][0] = MyTrtro.x + 1;
MyTrtro.Side_Block[1][1] = MyTrtro.y;
MyTrtro.Side_Block[2][0] = MyTrtro.x + 2;
MyTrtro.Side_Block[2][1] = MyTrtro.y;
break;
case TetroType::J:
MyTrtro.x = 5;
MyTrtro.y = 2;
MyTrtro.Side_Block[0][0] = MyTrtro.x;
MyTrtro.Side_Block[0][1] = MyTrtro.y - 1;
MyTrtro.Side_Block[1][0] = MyTrtro.x;
MyTrtro.Side_Block[1][1] = MyTrtro.y + 1;
MyTrtro.Side_Block[2][0] = MyTrtro.x - 1;
MyTrtro.Side_Block[2][1] = MyTrtro.y + 1;
break;
case TetroType::L:
MyTrtro.x = 4;
MyTrtro.y = 2;
MyTrtro.Side_Block[0][0] = MyTrtro.x;
MyTrtro.Side_Block[0][1] = MyTrtro.y - 1;
MyTrtro.Side_Block[1][0] = MyTrtro.x;
MyTrtro.Side_Block[1][1] = MyTrtro.y + 1;
MyTrtro.Side_Block[2][0] = MyTrtro.x + 1;
MyTrtro.Side_Block[2][1] = MyTrtro.y + 1;
break;
case TetroType::O:
MyTrtro.x = 4;
MyTrtro.y = 3;
MyTrtro.Side_Block[0][0] = MyTrtro.x + 1;
MyTrtro.Side_Block[0][1] = MyTrtro.y;
MyTrtro.Side_Block[1][0] = MyTrtro.x + 1;
MyTrtro.Side_Block[1][1] = MyTrtro.y - 1;
MyTrtro.Side_Block[2][0] = MyTrtro.x;
MyTrtro.Side_Block[2][1] = MyTrtro.y - 1;
break;
case TetroType::S:
MyTrtro.x = 5;
MyTrtro.y = 2;
MyTrtro.Side_Block[0][0] = MyTrtro.x - 1;
MyTrtro.Side_Block[0][1] = MyTrtro.y + 1;
MyTrtro.Side_Block[1][0] = MyTrtro.x;
MyTrtro.Side_Block[1][1] = MyTrtro.y + 1;
MyTrtro.Side_Block[2][0] = MyTrtro.x + 1;
MyTrtro.Side_Block[2][1] = MyTrtro.y;
break;
case TetroType::T:
MyTrtro.x = 4;
MyTrtro.y = 3;
MyTrtro.Side_Block[0][0] = MyTrtro.x - 1;
MyTrtro.Side_Block[0][1] = MyTrtro.y;
MyTrtro.Side_Block[1][0] = MyTrtro.x;
MyTrtro.Side_Block[1][1] = MyTrtro.y - 1;
MyTrtro.Side_Block[2][0] = MyTrtro.x + 1;
MyTrtro.Side_Block[2][1] = MyTrtro.y;
break;
case TetroType::Z:
MyTrtro.x = 4;
MyTrtro.y = 2;
MyTrtro.Side_Block[0][0] = MyTrtro.x - 1;
MyTrtro.Side_Block[0][1] = MyTrtro.y - 1;
MyTrtro.Side_Block[1][0] = MyTrtro.x;
MyTrtro.Side_Block[1][1] = MyTrtro.y - 1;
MyTrtro.Side_Block[2][0] = MyTrtro.x + 1;
MyTrtro.Side_Block[2][1] = MyTrtro.y;
break;
}
ContrlDraw();
}
bool Delete_Flag = false;
void KeyInput(char ch); //对键盘输入的识别,以及对应操作的总函数
void Move_Down(); //每秒一次,自动执行的下移函数,每次下移前执行固化函数
void ContrlDraw(); //屏幕更新的绘画
enum class TetroType MyTetroType; //方块形状的枚举变量
// int state = 0;
struct Tetromino MyTrtro; //方块结构体变量
void Anticlock_whirl(); //逆时针旋转
void Clock_whirl(); //顺时针旋转
void Pan_Left(); //左平移
void Pan_Right(); //右平移
};
void Block::Anticlock_whirl() {
int Side_Block_imme[3][2];
bool False_Flag = false;
for (int i = 0; i < 3; i++) {
Side_Block_imme[i][1] = MyTrtro.y+( MyTrtro.Side_Block[i][0] - MyTrtro.x);
Side_Block_imme[i][0] = MyTrtro.x-(MyTrtro.Side_Block[i][1] - MyTrtro.y);
if(Side_Block_imme[i][1] >= MAP_H || Side_Block_imme[i][1] < 0 ||
Side_Block_imme[i][0] >= MAP_W || Side_Block_imme[i][0] < 0 ||
GAME_MAP[Side_Block_imme[i][0]][Side_Block_imme[i][1]]==true)
False_Flag = true;
}
if (False_Flag == false)
for (int i = 0; i < 3; i++)
for (int j = 0; j < 2; j++)
MyTrtro.Side_Block[i][j] = Side_Block_imme[i][j];
}
void Block::Clock_whirl() {
int Side_Block_imme[3][2];
bool False_Flag = false;
for (int i = 0; i < 3; i++) {
Side_Block_imme[i][1] = MyTrtro.y-( MyTrtro.Side_Block[i][0] - MyTrtro.x);
Side_Block_imme[i][0] = MyTrtro.x+(MyTrtro.Side_Block[i][1] - MyTrtro.y);
if (Side_Block_imme[i][1] >= MAP_H || Side_Block_imme[i][1] < 0 ||
Side_Block_imme[i][0] >= MAP_W || Side_Block_imme[i][0] < 0 ||
GAME_MAP[Side_Block_imme[i][0]][Side_Block_imme[i][1]] == true) {
False_Flag = true;
break;
}
}
if (False_Flag == false)
for (int i = 0; i < 3; i++)
for (int j = 0; j < 2; j++)
MyTrtro.Side_Block[i][j] = Side_Block_imme[i][j];
}
void Block::ContrlDraw() {
system("cls");
bool GAME_MAP_imme[MAP_W][MAP_H] ;
for (int i = 0; i < MAP_W; i++)
for (int j = 0; j < MAP_H; j++)
GAME_MAP_imme[i][j] = GAME_MAP[i][j];
GAME_MAP_imme[MyTrtro.x][MyTrtro.y] = true;
for (int i = 0; i < 3; i++)
GAME_MAP_imme[MyTrtro.Side_Block[i][0]][MyTrtro.Side_Block[i][1]] = true;
std::cout << " ---------- " << std::endl;
for (int i = 4; i < MAP_H; i++) {
std::cout << "|";
for (int j = 0; j < MAP_W; j++) {
if (GAME_MAP_imme[j][i] == true)
std::cout << "*";
else
std::cout << " ";
}
std::cout <<"|"<< std::endl;
}
std::cout << " ---------- " << std::endl;
}
void Block::Move_Down() {
bool Flag = false; //固定标志位判断,为真则固定
if (MyTrtro.y + 1 >= 24 || GAME_MAP[MyTrtro.x][MyTrtro.y + 1] == true)
Flag = true;
for (int i = 0; i < 3; i++) {
if (MyTrtro.Side_Block[i][1] + 1 >= MAP_H || GAME_MAP[MyTrtro.Side_Block[i][0]][MyTrtro.Side_Block[i][1] + 1] == true)
Flag = true;
}
if (Flag == true) {
GAME_MAP[MyTrtro.x][MyTrtro.y ] = true;
for (int i = 0; i < 3; i++)
GAME_MAP[MyTrtro.Side_Block[i][0]][MyTrtro.Side_Block[i][1]] = true;
Delete_Flag = true;
}
else {
MyTrtro.y = MyTrtro.y + 1;
for (int i = 0; i < 3; i++)
MyTrtro.Side_Block[i][1] += 1;
}
ContrlDraw();
}
void Block::Pan_Left() {
if (MyTrtro.x - 1 < 0 || GAME_MAP[MyTrtro.x - 1][MyTrtro.y] == true)
return ;
for (int i = 0; i < 3; i++) {
if (MyTrtro.Side_Block[i][0] - 1 < 0 || GAME_MAP[MyTrtro.Side_Block[i][0] - 1][MyTrtro.Side_Block[i][1]] == true)
return ;
}
MyTrtro.x = MyTrtro.x - 1;
for (int i = 0; i < 3; i++)
MyTrtro.Side_Block[i][0] -= 1;
}
void Block::Pan_Right() {
if (MyTrtro.x + 1 >=10 || GAME_MAP[MyTrtro.x +1][MyTrtro.y] == true)
return;
for (int i = 0; i < 3; i++) {
if (MyTrtro.Side_Block[i][0] + 1 >=MAP_W || GAME_MAP[MyTrtro.Side_Block[i][0] + 1][MyTrtro.Side_Block[i][1]] == true)
return;
}
MyTrtro.x = MyTrtro.x + 1;
for (int i = 0; i < 3; i++)
MyTrtro.Side_Block[i][0] += 1;
}
void Block::KeyInput(char ch) {
if (ch == 'A' || ch == 'a')
Pan_Left();
else if (ch == 'D' || ch == 'd')
Pan_Right();
else if (ch == 'W' || ch == 'w')
Clock_whirl();
else if (ch == 'S' || ch == 's')
Anticlock_whirl();
ContrlDraw();
}
void Delay_1s() {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
void Update(Block** pt) {
(*pt)->Move_Down();
if ((*pt)->Delete_Flag == true) {
delete *pt;
for(int i=0;i<MAP_W;i++)
if (GAME_MAP[i][4] == true) {
gameend_flag = 1;
return;
}
*pt = new Block;
}
//遍历整个地图展示的数组,检测是否有整行填满,有则清除加下移
else {
for (int i = 0; i < MAP_H; i++) {
bool flag = true;
for (int j = 0; j < MAP_W; j++)
if (GAME_MAP[j][i] == false)
flag = false;
if (flag == true) {
GameScore++;
for (int n = i; n >= 5; n--)
for (int j = 0; j < MAP_W; j++)
GAME_MAP[j][n] = GAME_MAP[j][n - 1];
}
}
}
(*pt)->ContrlDraw();
}
void GAME_MAP_Init()
{
gameend_flag = 0;
GameScore = 0;
for (int i = 0; i < MAP_W; i++)
{
for (int j = 0; j < MAP_H; j++)
GAME_MAP[i][j] = false;
}
}
// 函数用来读取高分榜
std::vector<int> readHighScores(const std::string& filename) {
std::vector<int> scores;
std::ifstream infile(filename);
int score;
while (infile >> score) { // 读取分数
scores.push_back(score);
}
std::sort(scores.begin(), scores.end(), std::greater<int>()); // 排序
return scores;
}
// 函数用来写入高分榜
void writeHighScores(const std::vector<int>& scores, const std::string& filename) {
std::ofstream outfile(filename);
for (const auto& score : scores) { // 将分数写入文件
outfile << score << std::endl;
}
}
// 检查并更新高分榜
void updateHighScores(int newScore, std::vector<int>& scores) {
scores.push_back(newScore);
std::sort(scores.begin(), scores.end(), std::greater<int>());
if (scores.size() > 3) {
scores.pop_back(); // 保持前3名
}
}
void state_UI(int state) {
system("cls");
if (state == 1)
std::cout << "开始游戏\t<-" << std::endl << "高分排行" << std::endl << "结束游戏" << std::endl;
else if(state==2)
std::cout << "开始游戏" << std::endl << "高分排行\t<-" << std::endl << "结束游戏" << std::endl;
else if(state==3)
std::cout << "开始游戏" << std::endl << "高分排行" << std::endl << "结束游戏\t<-" << std::endl;
}
Block* pt;
int main()
{
srand((unsigned int)time(NULL)); //随机数种子
int state = 0;
while (1) {//选择UI界面
if (state == 0) {
int state_imme = 1;
state_UI(state_imme);
while (1) {
if (_kbhit()) {
char input = _getch();
if (input == '\r') {
state = state_imme;
break;
}
else if (input == 'w' || input == 'W')
{
if (state_imme == 1)
state_imme = 3;
else
state_imme--;
state_UI(state_imme);
}
else if (input == 's' || input == 'S')
{
if (state_imme == 3)
state_imme = 1;
else
state_imme++;
state_UI(state_imme);
}
}
}
}
else if (state == 1) {
GAME_MAP_Init(); //初始化游戏地图
pt = new Block; //新的方块
auto Delay = std::async(std::launch::async, Delay_1s); //一秒的记时
char ch;
while (gameend_flag != 1) {
//检测键盘输入,有则捕获且开启输入判断
if (_kbhit()) {
ch = _getch();
pt->KeyInput(ch);
}
//如果一秒延时已完成,更新方块+开启新一秒的计时
if (Delay.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
Update(&pt);
Delay = std::async(std::launch::async, Delay_1s);
}
}
system("cls");
std::cout << "GAME OVER" << std::endl << "YOUR SCORES:" << GameScore << std::endl;
std::string highScoresFile = "highscores.txt"; // 高分榜文件
// 读取高分榜
std::vector<int> highScores = readHighScores(highScoresFile);
// 检查是否需要更新高分榜
updateHighScores(GameScore, highScores);
// 保存更新后的高分榜
writeHighScores(highScores, highScoresFile);
}
else if (state == 2) {
std::string highScoresFile = "highscores.txt"; // 高分榜文件
// 读取高分榜
std::vector<int> highScores = readHighScores(highScoresFile);
// 显示高分榜
system("cls");
std::cout << "High Scores:" << std::endl;
for (const auto& score : highScores) {
std::cout << score << std::endl;
}
std::cout << "请按Q以退出" << std::endl;
while (1) {
if (_kbhit()) {
char input = _getch();
if (input == 'q' || input == 'Q')
break;
}
}
state = 0;
}
else if (state == 3)
return 0;
}
}
当时写的时候没注意,就成了现在这种没注释也没分文件的蠢模样,懒得弄了,遂鸽。
其实原理还挺简单的,暴力枚举的初始化,确定中心方块后一个个写变换函数 然后异步检测键盘输入和计时每一秒,用一个指针指向最新的活的方块.
其他还有没有主动下移,没有用EasyX画出来等小毛病,但懒得改了,鸽