#include<iostream>
#include<Windows.h>
#include<string>
#include<vector>
#include<ctime>
#include<conio.h>
using namespace std;
static const int LEVEL = 10;//最高等级
const int LEFT = 15;//游戏界面的左边界
const int RIGHT = 29;//游戏界面的右边界
const int TOP = 5;//游戏界面的上边界
const int BOTTOM = 20;//游戏界面的下边界
class Position {
public:
Position() {}
~Position() {}
void locateXy(int x, int y);
};
void Position::locateXy(int x, int y) {
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}//定位到X,Y,左上角为(0,0)
//游戏界面框架 Framework
class Framework {
public:
Framework() {
}
~Framework() {
}
void printFrame();
void printScore(int score);
void printLevel(int level);
};
//Frame类函数实现
void Framework::printFrame() {
Position p;
for (int i = LEFT; i < RIGHT+1; i++) {
p.locateXy(i, TOP);
cout << "*";
}
for (int i = LEFT; i < RIGHT+1; i++) {
p.locateXy(i, BOTTOM);
cout << "*";
}
for (int j = TOP + 1; j < BOTTOM; j++) {
p.locateXy(LEFT, j);
cout << "*";
}
for (int j = TOP + 1; j < BOTTOM; j++) {
p.locateXy(RIGHT, j);
cout << "*";
}
p.locateXy(0, 0);//重置
}
void Framework::printScore(int score) {
cout << "Now your score is " << score << endl;
}
void Framework::printLevel(int level) {
cout << "Now your level is " << level << ".(Attenton:Speed increases with level.)" << endl;
}
//方块构成 Formation
class Formation {
public:
Formation(int x, int y) {
this->x = x;
this->y = y;
}
int getX() {
return x;
}
int getY() {
return y;
}
void setX(int x) {
this->x = x;
}
void setY(int y) {
this->y = y;
}
private:
int x;
int y;
};
//Block 方块
class Block : {
public:
Block();
~Block() {}
int getLevel() {
return level;
};
void create();
void rotate();//方块旋转
void printBlock();//显示方块
void fall();//方块下落
void setSpeed(int speed);
bool isDead();//判断游戏是否结束
int eliminate();//实现方块消除
bool stop();//方块碰到底部或者下一行有方块时停止下落
void shift();//左移,右移,速降
void play();//控制游戏进程
void replay();
private:
int level = 0;
int score = 0;
int Speed[LEVEL] = { 700,650,600,550,500,450,400,400,400,400 };//用时间度量速度
bool isoccupied[25][20];//二维数组,当有方块时值为1,25与20防止越界
int speed = 800;// 初始速度
vector<Formation>arr;// 对象数组,记录组成方块的xy值
};
Block::Block() {
for (int i = 0; i <= RIGHT - LEFT - 2; i++) {
for (int j = 0; j <= BOTTOM - TOP - 2; j++) {
isoccupied[i][j] = 0;//游戏界面内的所有格子初始化为没有方块占据
}
}
}
void Block::create() {
int shape;//方块形状对应的数字
int rotation;//旋转状态对应的数字
int midpoint = (RIGHT - LEFT) / 2;
//这里利用系统时间生成随机数初始化shape和rotation,以实现方块形状和旋转方向的丰富性
srand(time(NULL));
shape = rand() % 9;
//基本方块有5种,但为将游戏难度降低,多分配了四种情况,提高了四连正方形,城墙形,正方形的出现概率
rotation = rand() % 5;
//四种旋转状态
arr.clear();//需要多次调用该函数,每次调用时清零arr
Position p;
switch (shape)
{
case 0:case 5:
arr.clear();
for (int i = 0; i < 4; ++i)
{
Formation formation(i + LEFT + midpoint + 1, TOP + 1);
arr.push_back(formation);
}//四连长方形
for (int i = 0; i < rotation; ++i)
{
rotate();//rotate函数实现方块旋转;
}
break;
case 1:case 6:case 7:
arr.clear();
for (int i = 0; i < 2; ++i)
{
for (int j = 0; j < 2; ++j)
{
Formation formation(i + LEFT + midpoint + 1, TOP + 1 + j);
arr.push_back(formation);
}
} //正方形
break;//正方形旋转还是正方形,所以不必旋转
case 2:
arr.clear();
arr.push_back(Formation(LEFT + midpoint + 1, TOP + 1));
arr.push_back(Formation(LEFT + midpoint + 2, TOP + 1));
arr.push_back(Formation(LEFT + midpoint + 3, TOP + 1));
arr.push_back(Formation(LEFT + midpoint + 3, TOP + 2));
for (int i = 0; i < rotation; ++i)
{
rotate();
}//枪形
break;
case 3:
arr.clear();
arr.push_back(Formation(LEFT + midpoint + 1, TOP + 1));
arr.push_back(Formation(LEFT + midpoint + 1, TOP + 2));
arr.push_back(Formation(LEFT + midpoint + 2, TOP + 2));
arr.push_back(Formation(LEFT + midpoint + 2, TOP + 3));
for (int i = 0; i < rotation; ++i)
{
rotate();
} //梯形
break;
case 4: case 8:
arr.clear();
arr.push_back(Formation(LEFT + midpoint + 1, TOP + 1));
arr.push_back(Formation(LEFT + midpoint + 2, TOP + 1));
arr.push_back(Formation(LEFT + midpoint + 3, TOP + 1));
arr.push_back(Formation(LEFT + midpoint + 2, TOP + 2));
for (int i = 0; i < rotation; ++i)
{
rotate();
}//城墙形
break;
}
for (int i = 0; i < 4; ++i)
{
isoccupied[arr[i].getX() - 1 - LEFT][arr[i].getY() - 1 - TOP] = true;
}//方块创建之后,将方块所在的格子全部赋值为1,其余保持为0
}
//旋转方块,rotate相当于create的一个子函数;左上角方块位置不变,其余方块以左上角方块为轴逆时针旋转90度
void Block::rotate() {
for (int i = 0; i < 4; ++i)
{
isoccupied[arr[i].getX() - 1 - LEFT][arr[i].getY() - TOP - 1] = false;
}// 旋转后方块位置变化,先将旋转前的值清零;旋转后再在create之中赋1
for (int i = 1; i <= 3; ++i)
{//i从1开始,左上角不动
int distanceOfX = arr[i].getX() - arr[0].getX();
int distanceOfY = arr[i].getY() - arr[0].getY();
arr[i].setX(arr[0].getX() - distanceOfY);
arr[i].setY(arr[0].getY() + distanceOfX);
}
}
//显示方块
void Block::printBlock() {
//遍历整个棋盘,有方块的地方显示方块,没有方块的地方打上空格
Position p;
char sym = '#';
for (int i = LEFT + 1; i < RIGHT; ++i)
{
for (int j = TOP + 1; j < BOTTOM; ++j)
{
if (isoccupied[i - LEFT - 1][j - TOP - 1] == true)
{
p.locateXy(i, j);
cout << sym;
}
else
{
p.locateXy(i, j);
cout << " ";
}
}
}
return;
}
void Block::fall() {//方块下落,Y坐标加1
for (int i = 0; i < 4; ++i)
{
isoccupied[arr[i].getX() - 1 - LEFT][arr[i].getY() - TOP - 1] = false;
}//先清零,下落后重新赋值为1
for (int i = 0; i < 4; ++i)
{
arr[i].setY(arr[i].getY() + 1);
}//方块下落一格
for (int i = 0; i < 4; ++i)
{
isoccupied[arr[i].getX() - 1 - LEFT][arr[i].getY() - TOP - 1] = true;
}
}
void Block::setSpeed(int speed) {
this->speed = speed;
}
//检测游戏是否输了,直接检测最上面一排即可
bool Block::isDead() {//检测棋盘最顶层有无方块,若有,返回1
for (int i = LEFT; i < RIGHT - 1; ++i) {
if (isoccupied[i - LEFT][0]== true){
return 1;
}
}
return 0;
}
//实现方块的消除
int Block::eliminate() {
{
int level = 0;
int i = 0;
for (i = BOTTOM - TOP - 2; i >= 0; --i)
{//从最下面一行开始检测,遍历所有行
bool temp = true;
for (int j = 0; j < RIGHT - LEFT - 1; ++j)
{// 对单独每一行进行检测
if (isoccupied[j][i] == false)
temp = false;
}//只有当该行全部有方格时才能使得temp=1;满足消除条件
if (temp == true)
{
level++;//消除一行,返回1;消除n行,返回n
for (int k = 0; k < RIGHT - LEFT - 1; ++k)
{
for (int t = i; t > 0; --t)
{
isoccupied[k][t] = isoccupied[k][t - 1];
}
}//消除的行的上面依次下落一行,直到最上面一行
i++; //检测刚刚替补的一行
}
temp = true;
}
return level;
}
}
bool Block::stop()
{
bool flag = false;
for (int i = 0; i < 4; ++i)
{
isoccupied[arr[i].getX() - LEFT - 1][arr[i].getY() - TOP - 1] = false;
//先清零,后重新赋值
}
for (int i = 0; i < 4; ++i)
{
if (arr[i].getY() == BOTTOM - 1)
flag = true;
//第一种情况,方块已经到了最下面一行
if (isoccupied[arr[i].getX() - LEFT - 1][arr[i].getY() + 1 - TOP - 1] == true)
flag = true;
//第二种情况,方块所在行下面一行已经有了方块
}
for (int i = 0; i < 4; ++i)
{
isoccupied[arr[i].getX() - LEFT - 1][arr[i].getY() - TOP - 1] = true;
}
return flag;
//以上两种情况,返回值为1
}
void Block::shift()
{
vector<Formation> arr2;
for (int i = 0; i < 4; ++i)
{
arr2.push_back(arr[i]);
//用arr2记录下arr原本的位置, 如果arr的方块撞到了左右墙壁,则用arr2重新初始化arr
isoccupied[arr[i].getX() - 1 - LEFT][arr[i].getY() - TOP - 1] = false;
}
while (_kbhit())//检测是否由键盘输入
{
switch (_getch())//获取键盘输入的字符
{
case 97: case 65: //左移 A,a对应的ASIC码
for (int i = 0; i < 4; ++i)
{
int m = arr[i].getX();
arr[i].setX(m - 1);
}
break;
case 100:case 68: //右移 D,d对应的ASIC码
for (int i = 0; i < 4; ++i)
{
int m = arr[i].getX();
arr[i].setX(m + 1);
}
break;
case 82:case 114: //旋转 R,r对应的ASIC码
rotate();
break;
case 83:case 115:
setSpeed(10); //速降 S,s对应的ASIC码
default:
break;
}
//防止碰壁的代码如下:
bool flag = 0;
for (int i = 0; i < 4; ++i)
{
if (arr[i].getX() <= LEFT || arr[i].getX() >= RIGHT)//方块越左右界
flag = true;
}
if (flag == true) //如果相撞,用arr2初始化arr
{
arr.clear();
for (int i = 0; i < 4; ++i)
{
arr.push_back(arr2[i]);
}
}
for (int i = 0; i < 4; ++i)
{
isoccupied[arr[i].getX() - 1 - LEFT][arr[i].getY() - 1 - TOP] = true;
}
return;
}
}
void Block::play() {
while (isDead() == false)
{//如果还没输
create();//产生随机方块
printBlock();//显示方块
while (!stop())
{//方块没到底
shift();//左右速降
fall();//降落一格
printBlock();//显示降落后的方块
Sleep(speed);//延时speed时间,进入下一循环
}
//方块落到地后更新分数,等级,判断是否达到最大速度
score += eliminate();
level = score / 3;
if (level == LEVEL)
{
break;
}
speed = Speed[level];
cout << endl << endl;
printLevel(level + 1);
printScore(score);
Sleep(speed);
}
}
int main() {
Framework f;
Position p;
char choice;
f.printFrame();//打印游戏界面
bool flag = true;
while (flag) {
Block b;
b.play();
if (1)
{
p.locateXy(0, 0);
cout << "你这盘达到的等级是" << b.getLevel()+1 << endl;
cout << "是否重新开始?,如果重新开始,请输入Y" << endl;
cin >> choice;
if (choice == 'Y')
{
flag = true;
}
else flag = false;
}
}
return 0;
}
s