C/C++——控制台俄罗斯方块的实现以及自动操作

游戏附件

链接: https://pan.baidu.com/s/1KMBav6Uy9OyyUE3BnRfJGw
提取码: d9tb

游戏截图:

游戏截图

头文件、全局变量以及函数声明

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>
#include <process.h>
#include <math.h>
// 七种方块类型IJLOSTZ
#define I 0
#define J 1
#define L 2
#define O 3
#define S 4
#define T 5
#define Z 6
COORD block[4],nblock[4],blockchange[4];
int tank[12][24]={0};
int type,ntype,typechange,speed;
int cheatopen=0,score,over=0,best=0;
int blockcolor[7]={11,9,5,14,10,13,12};
int blocktypenum[7]={2,4,4,1,2,4,2};
COORD blocktype[7][4];
COORD changeI[2][4],changeJ[4][4],changeL[4][4],changeS[2][4],changeT[4][4],changeZ[2][4];
HANDLE handle,mutex;
void gotoxy(int x, int y);	//移动光标
void color(int b);			//设置颜色
void initialize();			//初始化各方块的形状和旋转样式
void drawboard();			//绘制界面
void newblock();			//创建新方块
void blocktwist();			//方块旋转
void cheat();				//方块收缩
bool checkbottom();			//检查是否触底
bool checkright();			//检查是否可右移
bool checkleft();			//检查是否可左移
bool checktwist();			//检查是否可旋转
bool checkdie();			//检查是否游戏结束
void checkclear();			//检查是否有可清楚行
void autoplay();			//单步自动操作
void Sautoplay();			//全自动操作
int checkbest(int x,int typechange);	//计算最好的方块位置
void blockmove(int dir);				//方块移动
unsigned int __stdcall Fun(void *pPM);	//子线程控制方块自动下落
void start();							//游戏流程控制和交互

主要函数:

void start()
{
	for(int i=0;i<11;i++)
	for(int j=0;j<24;j++)
	tank[i][j]=0;
	for(int j=0;j<24;j++)
	tank[0][j]=1,tank[11][j]=1;
	//
	drawboard();newblock();char ch;score=0;over=0;
	speed=(int)(1000/log((double)score+7.38));
	color(15);gotoxy(13,8);printf("SCORE:%d",score);
	gotoxy(13,9);printf("INTERVAL:%dms",speed);
	mutex=CreateMutex(NULL,FALSE,NULL);
	handle=(HANDLE)_beginthreadex(NULL,0,Fun,NULL,0,NULL);   
	while(1)
	{
		if (kbhit())
        {	
			ch=getch();
			WaitForSingleObject(mutex,INFINITE);
			switch(ch)
			{
				case 'R':if(cheatopen)cheat();break;
				case 'E':if(cheatopen)autoplay();break;
				case 'a':case 'A':if(checkleft())blockmove(2);break;
				case 'w':case 'W':if(checktwist())blocktwist();break;
				case 'd':case 'D':if(checkright())blockmove(1);break;
				case 's':case 'S':
				while(!checkbottom()){Sleep(25);blockmove(0);}break;
				case 0x1B:over=1;
			}
			ReleaseMutex(mutex);
			if(cheatopen&&ch=='O')Sautoplay();
		}
		if(over)break;
	}
	WaitForSingleObject(handle,INFINITE);
	CloseHandle(handle);CloseHandle(mutex);
	color(15);gotoxy(0,22);printf("GAME OVER!");
	if(score>best)best=score,printf("NEW RECORD!");
	system("pause");
}
void blockmove(int d)
{
	for(int i=0;i<4;i++)
	{
		gotoxy(block[i].X,block[i].Y);
		if(block[i].X>0&&block[i].Y>0)
		printf("  ");
	}
	switch(d)
	{
		case 0:for(int i=0;i<4;i++)block[i].Y++;break;
		case 1:for(int i=0;i<4;i++)block[i].X++;break;
		case 2:for(int i=0;i<4;i++)block[i].X--;break;
	}
	color(blockcolor[type]);
	for(int i=0;i<4;i++)
	{
		gotoxy(block[i].X,block[i].Y);
		if(block[i].Y>0)printf("■");
	}
}
void checkclear()
{
	int i,j,k,num=0,times=0;
	for(i=0;i<=20;i++)
	{
		num=0;
		for(j=1;j<=10;j++)if(tank[j][i+3])num++;
		if(num==10)
		{
			times+=1;Sleep(100);
			for(k=i;k>0;k--)
			{
				gotoxy(1,k);
				for(j=1;j<=10;j++)
				{
					tank[j][k+3]=tank[j][k+2];
					if(tank[j][k+3]){color(tank[j][k+3]);printf("■");}
					else printf("  ");
				}
			}
			printf("\a");
		}
	}
	score+=(times*times);
	speed=(int)(1000/log((double)score+7.38));
	color(15);gotoxy(13,8);printf("SCORE:%d",score);
	gotoxy(13,9);printf("INTERVAL:%dms",speed);
}

有关自动操作:

思路,遍历当前下落方块的所有位置,所有旋转方向下落后的位置并用checkbest函数对该位置打分,选择打分最高的位置和旋转方向操作。

void autoplay()
{
	int k,x,bestnum=0,bestx=5,besttype=0,num=0;
	for(k=0;k<blocktypenum[type];k++)
	{
		for(x=1;x<=10;x++)
		{
			num=checkbest((x+3)%10+1,k);
			if(bestnum<num){bestnum=num;bestx=(x+3)%10+1;besttype=k;}
		}
	}
	//
	for(int i=0;i<4;i++)
	if(block[i].Y>0){gotoxy(block[i].X,block[i].Y);printf("  ");}
	//
	block[0].X=bestx;
	block[0].Y=block[0].Y;
	switch(type)
	{
		case I: for(int i=1;i<4;i++){
				block[i].X=block[0].X+changeI[besttype][i].X;
				block[i].Y=block[0].Y+changeI[besttype][i].Y;}
				break;
		case J: for(int i=1;i<4;i++){
				block[i].X=block[0].X+changeJ[besttype][i].X;
				block[i].Y=block[0].Y+changeJ[besttype][i].Y;}
				break;
		case L: for(int i=1;i<4;i++){
				block[i].X=block[0].X+changeL[besttype][i].X;
				block[i].Y=block[0].Y+changeL[besttype][i].Y;}
				break;
		case S: for(int i=1;i<4;i++){
				block[i].X=block[0].X+changeS[besttype][i].X;
				block[i].Y=block[0].Y+changeS[besttype][i].Y;}
				break;
		case T: for(int i=1;i<4;i++){
				block[i].X=block[0].X+changeT[besttype][i].X;
				block[i].Y=block[0].Y+changeT[besttype][i].Y;}
				break;
		case Z: for(int i=1;i<4;i++){
				block[i].X=block[0].X+changeZ[besttype][i].X;
				block[i].Y=block[0].Y+changeZ[besttype][i].Y;}
				break;
		case O: block[1].X=block[0].X+1;
				block[1].Y=block[0].Y;
				block[2].X=block[0].X;
				block[2].Y=block[0].Y-1;
				block[3].X=block[0].X+1;
				block[3].Y=block[0].Y-1;
				break;
	}
	//
	color(blockcolor[type]);
	for(int i=0;i<4;i++)
	{
		gotoxy(block[i].X,block[i].Y);
		if(block[i].Y>0)printf("■");
	}
	while(!checkbottom()){Sleep(25);blockmove(0);}
}
int checkbest(int x,int tpc)
{
	COORD temp[4];
	temp[0].X=x;
	temp[0].Y=block[0].Y;
	switch(type)
	{
		case I: for(int i=1;i<4;i++){
				temp[i].X=temp[0].X+changeI[tpc][i].X;
				temp[i].Y=temp[0].Y+changeI[tpc][i].Y;}
				break;
		case J: for(int i=1;i<4;i++){
				temp[i].X=temp[0].X+changeJ[tpc][i].X;
				temp[i].Y=temp[0].Y+changeJ[tpc][i].Y;}
				break;
		case L: for(int i=1;i<4;i++){
				temp[i].X=temp[0].X+changeL[tpc][i].X;
				temp[i].Y=temp[0].Y+changeL[tpc][i].Y;}
				break;
		case S: for(int i=1;i<4;i++){
				temp[i].X=temp[0].X+changeS[tpc][i].X;
				temp[i].Y=temp[0].Y+changeS[tpc][i].Y;}
				break;
		case T: for(int i=1;i<4;i++){
				temp[i].X=temp[0].X+changeT[tpc][i].X;
				temp[i].Y=temp[0].Y+changeT[tpc][i].Y;}
				break;
		case Z: for(int i=1;i<4;i++){
				temp[i].X=temp[0].X+changeZ[tpc][i].X;
				temp[i].Y=temp[0].Y+changeZ[tpc][i].Y;}
				break;
		case O: temp[1].X=temp[0].X+1;
				temp[1].Y=temp[0].Y;
				temp[2].X=temp[0].X;
				temp[2].Y=temp[0].Y-1;
				temp[3].X=temp[0].X+1;
				temp[3].Y=temp[0].Y-1;
				break;
	}
	for(int i=0;i<4;i++)
	{
		if(tank[temp[i].X][temp[i].Y+3])return -1;
		if(temp[i].X<1||temp[i].X>10||temp[i].Y>20)return -1;
	}
	int z=0;
	while(1)
	{
		for(int i=0;i<4;i++)if(temp[i].Y>=20||tank[temp[i].X][temp[i].Y+4])z=1;
		if(z)break;
		for(int k=0;k<4;k++)temp[k].Y++;
	}
	int num=0;
	for(int i=0;i<4;i++){tank[temp[i].X][temp[i].Y+3]=1;}
	for(int i=0;i<4;i++)
	{
	//打分区域开始
		if(tank[temp[i].X][temp[i].Y+4])num+=4;
		if((!tank[temp[i].X][temp[i].Y+4])&&(temp[i].Y!=20))num-=16;
		if((!tank[temp[i].X][temp[i].Y+4])&&(!tank[temp[i].X][temp[i].Y+5])&&(temp[i].Y!=20)&&(temp[i].Y!=19))num-=32;
		if(tank[temp[i].X+1][temp[i].Y+3])num+=4;
		if(tank[temp[i].X-1][temp[i].Y+3])num+=4;
		if(tank[temp[i].X+1][temp[i].Y+3]&&tank[temp[i].X-1][temp[i].Y+3])num+=4;
		if(temp[i].Y>=20)num+=6;
		if(temp[i].Y<=0)num-=1000;
		num+=temp[i].Y;
	//打分区域结束
	}
	int bnum;
	for(int k=0;k<=20;k++)
	{
		bnum=0;
		for(int j=1;j<=10;j++)if(tank[j][k+3])bnum++;
		if(bnum==10)num+=60;
	}
	for(int i=0;i<4;i++){tank[temp[i].X][temp[i].Y+3]=0;}
	return num;
}

注:checkbest打分标准直接决定了自动操作的技术!!!

猜你喜欢

转载自blog.csdn.net/Eyizoha/article/details/89388530