控制台游戏 - 2048

158 阅读6分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

介绍

《2048》是一款比较流行的数字游戏,最早于2014年3月20日发行。原版2048首先在GitHub上发布,原作者是Gabriele Cirulli,后被移植到各个平台。这款游戏是基于《1024》和《小3传奇》的玩法开发而成的新型数字游戏。

image.png

游戏时,每次操作可以选择上下左右其中一个方向去滑动。每滑动一次,所有的数字方块都会往滑动的方向靠拢外,系统也会在空白的地方随机出现一个数字方块,保证出现的数字方块为 2 的正整数次幂,相同数字的方块在靠拢、相撞时会相加。不断的叠加最终拼凑出2048这个数字就算成功。但是,we never stop,我们可以继续进行游戏,来争取更大的胜利。

本文使用前文介绍的控制台小游戏编写思路和C语言、部分 C++ 函数以及 WindowsAPI 等知识,简单的编写了控制台版本的 2048 小游戏qwq

emmmmm……因为Ice的水平低下&编译器版本&笔记本自身问题&控制台游戏的表现形式……所以它的兼容性非常低……

根据自己的运行结果来调整界面和时间参数吧QAQ……

程序框图

image.png

思路

开始、初始化地图、获取用户输入等操作在其他文章中已经细说过,这里我们只着重介绍存储地图的信息该如何维护。

我们所有的操作都是对这个二维数组的数据的操作。分为上下左右四个方向。

由于数据量很小,我们可以每次操作都暴力模拟执行。

  • 上移 上移操作的是列,首选需要取出各列元素,每列自上而下取出各列元素。
    将 0 元素移到列的最后。
    若存在相邻相同的元素,将上方的格子置为两者之和,下方的格子置为 0。
    再次将 0 元素移到列的最后。
    重复上述操作,最后将移动后的各元素重新给 444*4 的二维数组赋值。

  • 下移 下移操作的是列,首选需要取出各列元素,每列自下而上取出元素。
    将 0 元素移到列的最前。
    若存在相邻相同的元素,将下方的格子置为两者之和,上方的格子置为 0。
    再次将 0 元素移到列的最前。
    重复上述操作,最后将移动后的各元素重新给 444*4 的二维数组赋值。

  • 左移 左移操作的是行,首选需要取出各行元素,每行自左而右取出元素。
    将 0 元素移到列的最右。
    若存在相邻相同的元素,将左方的格子置为两者之和,右方的格子置为 0。
    再次将 0 元素移到列的最右。
    重复上述操作,最后将移动后的各元素重新给 444*4 的二维数组赋值。

  • 右移 右移操作的是行,首选需要取出各行元素,每行自右而左取出元素。
    将 0 元素移到列的最左。
    若存在相邻相同的元素,将右方的格子置为两者之和,左方的格子置为 0。
    再次将0元素移到列的最左。
    重复上述操作,最后将移动后的各元素重新给 444*4 的二维数组赋值。

这样四种操作只是取元素的方向不同,其他的操作都是相同的,可以共用部分代码。

代码

#include <bits/stdc++.h>
using namespace std;

string member[6]={" ┌ ┬ ┬ ┬ ┬ ┐",
                  " ├         ┤",
                  " ├         ┤",
                  " ├         ┤",
                  " └ ┴ ┴ ┴ ┴ ┘"};
string pr="2048\n输入\"Start\"以开始游戏。\n输入\"Exit\"以结束游戏。\n";
int a[5][5],b[5][5];

void Exit();
void fengmian();
void print();
void game();
long long sum=0;
HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);


void gotoxy(HANDLE hOut, int x, int y);
void getxy(HANDLE hOut, int &xx, int &yy);
void gotoxy(HANDLE hOut, int x, int y)
{
    COORD pos;
    pos.X=x;
    pos.Y=y;
    SetConsoleCursorPosition(hOut,pos);
}

void getxy(HANDLE hOut,int &xx,int &yy)
{
    CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
    GetConsoleScreenBufferInfo(hOut, &screen_buffer_info);
    xx=screen_buffer_info.dwCursorPosition.X;
    yy=screen_buffer_info.dwCursorPosition.Y;
}

void hide()
{
	HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);  
	CONSOLE_CURSOR_INFO CursorInfo;  
	GetConsoleCursorInfo(handle, &CursorInfo);
	CursorInfo.bVisible=false;
	SetConsoleCursorInfo(handle, &CursorInfo); 
}

void ehide()
{
	HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);  
	CONSOLE_CURSOR_INFO CursorInfo;  
	GetConsoleCursorInfo(handle, &CursorInfo);
	CursorInfo.bVisible=true;
	SetConsoleCursorInfo(handle, &CursorInfo); 
}

void NEW()
{
	memset(a,0,sizeof(a));
	sum=0;
}

void Exit()
{
 	exit(0);
}

void copp()
{
	for (int i=1;i<=4;++i)
		for (int j=1;j<=4;++j) b[i][j]=a[i][j];
}

int zb[5][5][2]={   0,0 ,   0,0  ,  0,0  ,   0,0   ,  0,0 ,
                    0,0 ,   2,3  ,  2,15  ,  2,27  ,  2,39 ,        
                    0,0 ,   7,3  ,  7,15  ,  7,27  ,  7,39 ,   
                    0,0 ,  12,3  , 12,15  , 12,27  , 12,39 ,   
                    0,0	,  17,3  , 17,15  , 17,27  , 17,39
            };
void print()
{
	for (int i=1;i<=4;++i)
		for (int j=1;j<=4;++j)
			if (a[i][j]!=b[i][j])
			{
				gotoxy(hOut,zb[i][j][1],zb[i][j][0]);
				printf("        ");
				gotoxy(hOut,zb[i][j][1],zb[i][j][0]);
				if (a[i][j]) printf("%d",a[i][j]);
			}
	copp();
	gotoxy(hOut,16,20);
	printf(" %lld",sum);
}

bool qaq(int x)
{
	if (x<1) return 0;
	if (x>4) return 0;
	return 1;
}

bool move(int x,int y)
{
	for (int i=1;i<=4;++i)
		for (int j=1;j<=4;++j) 
			if (a[i][j]&&qaq(i+x)&&qaq(j+y)&&a[i+x][j+y]==0) return 1;
	for (int i=1;i<=4;++i)
		for (int j=1;j<=4;++j) 
			if (a[i][j]&&qaq(i+x)&&qaq(j+y)&&a[i+x][j+y]==a[i][j]) return 1;
	return 0;
}

int u,v,t;

void Move(char x)
{
	if (x=='d')
		for (int i=1;i<=4;++i)
		{
			t=bool(a[i][1])+bool(a[i][2])+bool(a[i][3])+bool(a[i][4]);
			while (t>0&&!a[i][4]) a[i][4]=a[i][3],a[i][3]=a[i][2],a[i][2]=a[i][1],a[i][1]=0;
			t--;
			while (t>0&&!a[i][3]) a[i][3]=a[i][2],a[i][2]=a[i][1],a[i][1]=0;
			t--;
			while (t>0&&!a[i][2]) a[i][2]=a[i][1],a[i][1]=0;
			if (a[i][4]==a[i][3]) a[i][4]+=a[i][3],a[i][3]=a[i][2],a[i][2]=a[i][1],a[i][1]=0;
			if (a[i][3]==a[i][2]) a[i][3]+=a[i][2],a[i][2]=a[i][1],a[i][1]=0;
			if (a[i][2]==a[i][1]) a[i][2]+=a[i][1],a[i][1]=0;
		}
	else if (x=='a')
		for (int i=1;i<=4;++i)
		{
			t=bool(a[i][1])+bool(a[i][2])+bool(a[i][3])+bool(a[i][4]);
			while (t>0&&!a[i][1]) a[i][1]=a[i][2],a[i][2]=a[i][3],a[i][3]=a[i][4],a[i][4]=0;
			t--;
			while (t>0&&!a[i][2]) a[i][2]=a[i][3],a[i][3]=a[i][4],a[i][4]=0;
			t--;
			while (t>0&&!a[i][3]) a[i][3]=a[i][4],a[i][4]=0;
			t--;
			if (a[i][1]==a[i][2]) a[i][1]+=a[i][2],a[i][2]=a[i][3],a[i][3]=a[i][4],a[i][4]=0;
			if (a[i][2]==a[i][3]) a[i][2]+=a[i][3],a[i][3]=a[i][4],a[i][4]=0;
			if (a[i][3]==a[i][4]) a[i][3]+=a[i][4],a[i][4]=0;
		}
	else if (x=='s')
		for (int i=1;i<=4;++i)
		{
			t=bool(a[1][i])+bool(a[2][i])+bool(a[3][i])+bool(a[4][i]);
			while (t>0&&!a[4][i]) a[4][i]=a[3][i],a[3][i]=a[2][i],a[2][i]=a[1][i],a[1][i]=0;
			t--;
			while (t>0&&!a[3][i]) a[3][i]=a[2][i],a[2][i]=a[1][i],a[1][i]=0;
			t--;
			while (t>0&&!a[2][i]) a[2][i]=a[1][i],a[1][i]=0;
			t--;
			if (a[4][i]==a[3][i]) a[4][i]+=a[3][i],a[3][i]=a[2][i],a[2][i]=a[1][i],a[1][i]=0;
			if (a[3][i]==a[2][i]) a[3][i]+=a[2][i],a[2][i]=a[1][i],a[1][i]=0;
			if (a[2][i]==a[1][i]) a[2][i]+=a[1][i],a[1][i]=0;
		}
	else if (x=='w')
		for (int i=1;i<=4;++i)
		{
			t=bool(a[1][i])+bool(a[2][i])+bool(a[3][i])+bool(a[4][i]);
			while (t>0&&!a[1][i]) a[1][i]=a[2][i],a[2][i]=a[3][i],a[3][i]=a[4][i],a[4][i]=0;
			t--;
			while (t>0&&!a[2][i]) a[2][i]=a[3][i],a[3][i]=a[4][i],a[4][i]=0;
			t--;
			while (t>0&&!a[3][i]) a[3][i]=a[4][i],a[4][i]=0;
			t--;
			if (a[1][i]==a[2][i]) a[1][i]+=a[2][i],a[2][i]=a[3][i],a[3][i]=a[4][i],a[4][i]=0;
			if (a[2][i]==a[3][i]) a[2][i]+=a[3][i],a[3][i]=a[4][i],a[4][i]=0;
			if (a[3][i]==a[4][i]) a[3][i]+=a[4][i],a[4][i]=0;
		}
		
}

bool GG()
{
	for (int i=1;i<=4;++i)
		for (int j=1;j<=4;++j)
			if (!a[i][j]) return 0;
	return 1;
}

void qwq()
{
	getch();
	system("CLS");
	printf("游戏结束!\n您的最终得分是%lld!\n",sum);
	getch();
	return;
}

char o;

void game()
{
	while (1)
	{
		if (GG())
		{
			qwq();
			getch();
			break;
		}
		print();
		Sleep(1000);
		while (1)
		{
			u=rand()%4+1;
			v=rand()%4+1;
			if (!a[u][v])
			{
				a[u][v]=(rand()%2+1)*2;
				sum+=a[u][v];
				break;
			}
		}
		print();
		while (1)
		{
			o=getch();
                        if (o=='E') printf("E"),getchar(),getchar(),getchar(),getchar();
                        if (o=='N') printf("N"),getchar(),getchar(),getchar();
                                if (o=='w'&&move(-1,0)) {Move('w');break;}
                                if (o=='s'&&move(1,0)) {Move('s');break;}
                                if (o=='a'&&move(0,-1)) {Move('a');break;}
                                if (o=='d'&&move(0,1)) {Move('d');break;}
                                if ((!move(-1,0))&&(!move(0,-1))&&(!move(0,1))&&(!move(1,0))) break;
                                if (o=='E') Exit();
		}    
	}
}

void fengmian()
{
	NEW();
	while (1)
	{
		system("CLS");
		for (int i=0;pr[i];i++)
		{
			printf("%c",pr[i]);
			if (pr[i]=='\n') Sleep(300);
			Sleep(100);
		}
		string o;
		cin>>o;
		while (1)
		{
			 if (o=="Start")
			 {
			 	hide();
			 	system("CLS");
			 	for (int j=1;j<=4;++j)
				 	for (int i=0;i<=4;++i)
				 		cout<<member[i]<<member[i]<<member[i]<<member[i]<<endl;
				gotoxy(hOut,0,20);
				printf(" 您目前的得分是:%lld\n\n",sum);
				printf(" 输入\"New\"以重新开始。\n\n");
   				printf(" 输入\"Exit\"以结束游戏。\n\n");
                                printf(" 通过'w','s','a','d'键,向上下左右方向合并数字。");
			 	game();
			 	ehide();
			 	break;
			 }
			 if (o=="Exit") Exit();
			 cin>>o;
		}
	}
}

int main()
{
	srand(time(0));
	fengmian();
	return 0;
}