初学者用c语言实现2048小游戏(简化版)

欧阳俊逸
2023-12-01

2048的界面是4*4的矩阵,用一个简单的循环先将界面函数做出来

//显示游戏界面
void showui(int buf[4][4])
{
	int i,j;
	for(i=0; i<4; i++)
	{
		for(j=0; j<4; j++)
			printf("%5d",buf[i][j]);
		printf("\n");
	}
}

在这款游戏中,每进行一次操作都有一个“2或4”随机出现在4*4矩阵中没有数字的随机位置,所以可以封装一个函数,表示“2或4”出现在矩阵的随机一个空白(即0)位置

//数组中某个为0的位置赋值为2或4---》在为0的位置随机产生2或4
void gettwo(int buf[4][4])
{
lb:
	row=rand()%4; //把随机数限制在4以内
	col=rand()%4; //把随机数限制在4以内
	int i=rand()%2;
	int arr[2]={2,4};  
	if(buf[row][col]==0) //这个随机位置没有数字,可以产生一个2或4
		buf[row][col]=arr[i];
	else //这个位置有数字,不能在这里产生2或4
		goto lb;
}

以向上操作为例,每次向上操作,矩阵中每一列的数字都会先往上挪动,再进行合并

        挪动:

        定义一个临时数组变量tempui[4][4],用来存放挪动后的结果

        

for(j=0; j<4; j++)
{
    for(i=0,k=0; i<4; i++)
    {
	if(gameui[i][j]!=0) //说明有数字
	{
	    tempui[k++][j]=gameui[i][j];
	}
    }
}

        合并

        挪动之后相邻的两个相同数字会进行合并,合并结果会保存在靠上的位置,后面的依次往前挪动

//相同的数据合并
for(j=0; j<4; j++)
{
    for(i=0; i<4; i++)
	{
	    if(tempui[i][j]==tempui[i+1][j]) //比较相邻的元素是否相同,相同就合并
	        {
		    if(tempui[i][j]!=0)
			flag=2;
		    tempui[i][j]=2*tempui[i][j];
		    //合并之后[i+1][j]后面的数据要往前挪动
		    for(k=i+1; k<3; k++)
		        tempui[k][j]=tempui[k+1][j];
		    tempui[3][j]=0;
		 }
	  }
}

基本的游戏规则就是上面这些

但有一些细节值得注意,比如:

1.当一个方向没有挪动且没有合并的情况,这种情况再按该方向键是不会出现新的“2或4”的

2.当所有位置都有数字且无论哪个方向都不能再合并的时候,游戏失败需要跳出

代码实现如下:

#include <stdio.h>

#include <pthread.h>

#include <unistd.h>

#include <time.h>

#include <stdlib.h>

#include <strings.h>

int row;  //行

int col;  //列

//显示游戏界面

void showui(int buf[4][4])

{

    int i,j;

    for(i=0; i<4; i++)

    {

        for(j=0; j<4; j++)

            printf("%5d",buf[i][j]);

        printf("\n");

    }

}

//数组中某个为0的位置赋值为2或4---》在为0的位置随机产生2或4

void gettwo(int buf[4][4])

{

lb:

    row=rand()%4; //把随机数限制在4以内

    col=rand()%4; //把随机数限制在4以内

    int i=rand()%2;

    int arr[2]={2,4};  

    if(buf[row][col]==0) //这个随机位置没有数字,可以产生一个2或4

        buf[row][col]=arr[i];

    else //这个位置有数字,不能在这里产生2或4

        goto lb;

}

//封装函数把挪动合并的结果备份到gameui,然后清除tempui

void cpui(int buf1[4][4],int buf2[4][4])

{

    int i,j;

    for(i=0; i<4; i++)

    {

        for(j=0; j<4; j++)

            buf1[i][j]=buf2[i][j]; //把buf2中的结果备份到buf1中

    }

    

    //把buf2清零

    bzero(buf2,16*4);

}

//封装一个函数来比较gameui和tempui

int comp(int a[4][4], int b[4][4])

{

    int i,j,count=0;

    for(i=0; i<4; i++)

    {

        for(j=0; j<4; j++)

        {

            if(a[i][j]==b[i][j])

            count++;

        }

    }

    if(count==16)

        return 1;

    else

        return 0;

}

//封装一个函数用来标志2048结束程序

int vectory(int c[4][4])

{

    int i,j,flag=0;

    for(i=0; i<4; i++)

    {

        for(j=0; j<4; j++)

        {

            if(c[i][j]==2048)

            flag=1;

        }

    }

    if(flag==1)

        return 1;

    else

        return 0;

}

//封装一个函数用来判断当所有格子都有数字且上下左右都无法合并时,结束程序

int cantmov(int d[4][4])

{

    int i,j,k=0,count=0;

    for(i=0; i<4; i++)

    {

        for(j=0; j<4; j++)

        {

            if(d[i][j] != 0)         //判断每行相邻元素是否相等

            k++;

        }

    }

    if(k==16)

    {

        for(i=0; i<4; i++)

        {

            for(j=0; j<3; j++)

            {

                if(d[i][j] != d[i][j+1])         //判断每行相邻元素是否相等

                count++;

            }

        }

        for(i=0; i<4; i++)

        {

            for(j=0; j<3; j++)

            {

                if(d[j][i] != d[j+1][i])         //判断每列相邻元素是否相等

                count++;

            }

        }

    }

    if(count==24)

        return 1;

    else

        return 0;

}

//主函数

int main()

{

    int flag=0;

    int ret;

    int i,j,k;

    int f=0;

    int v=0;

    //随机数种子

    srand(time(NULL));

    //定义二维数组表示2048的界面

    int gameui[4][4]={0};  

    //定义临时数组用来存放挪动的结果

    int tempui[4][4]={0};

    /*

        00  01  02  03

        10  11  12  13

        20  21  22  23

        30  31  32  33

    */

    //初始化游戏界面

    system("clear"); //清屏操作

    //在4*4的矩阵位置产生2个2

    gettwo(gameui);

    gettwo(gameui);

    showui(gameui);

    

    while((ret=getchar())!=27) //按ESC键退出

    {

        switch(ret)

        {

            //向上

            case 'w':

                //每一列向上靠拢,相同的数据合并,其他为0的位置随机产生一个2

                //界面再刷新一次

                //每一列向上靠拢

                if(cantmov(tempui)==1)

                    v=1;

                for(j=0; j<4; j++)

                {

                    for(i=0,k=0; i<4; i++)

                    {

                        if(gameui[i][j]!=0) //说明有数字

                        {

                            tempui[k++][j]=gameui[i][j];

                        }

                    }

                }

                int ret1= comp(tempui,gameui);

                if (ret1 != 1)

                    flag=1;

                //相同的数据合并

                for(j=0; j<4; j++)

                {

                    for(i=0; i<4; i++)

                    {

                        if(tempui[i][j]==tempui[i+1][j]) //比较相邻的元素是否相同,相同就合并

                        {

                            if(tempui[i][j]!=0)

                                flag=2;

                            tempui[i][j]=2*tempui[i][j];

                            //合并之后[i+1][j]后面的数据要往前挪动

                            for(k=i+1; k<3; k++)

                                tempui[k][j]=tempui[k+1][j];

                            tempui[3][j]=0;

                        }

                    }

                }

                //其他为0的位置随机产生一个2

                if(flag !=0)

                {

                    gettwo(tempui);

                    flag=0;

                }

                //界面再刷新一次

                system("clear");

                showui(tempui);

                if(vectory(tempui)==1)

                    f=1;

                //把目前游戏的结果备份到gameui,顺便把tempui清零方便下次计算

                cpui(gameui,tempui);

                if(cantmov(gameui)==1)

                    v=1;

                break;



 

            //向下    

            case 's':

                //向下挪动

                for(j=0; j<4; j++)

                {

                    for(i=3,k=3; i>=0; i--)

                    {

                        if(gameui[i][j]!=0) //说明有数字

                        {

                            tempui[k--][j]=gameui[i][j];

                        }

                    }

                }

                int ret2= comp(tempui,gameui);

                if (ret2 != 1)

                    flag=1;

                //相同的数据合并

                for(j=0; j<4; j++)

                {

                    for(i=3; i>=0; i--)

                    {

                        if(tempui[i][j]==tempui[i-1][j]) //比较相邻的元素是否相同,相同就合并

                        {

                            if(tempui[i][j]!=0)

                            flag=2;

                            tempui[i][j]=2*tempui[i][j];

                            //合并之后[i-1][j]前面的数据要往后挪动

                            for(k=i-1; k>0; k--)

                                tempui[k][j]=tempui[k-1][j];

                            tempui[0][j]=0;

                        }

                    }

                }

               //其他为0的位置随机产生一个2

                if(flag !=0)

                {

                    gettwo(tempui);

                    flag=0;

                }

                //界面再刷新一次

                system("clear");

                showui(tempui);

                if(vectory(tempui)==1)

                    f=1;

                //把目前游戏的结果备份到gameui,顺便把tempui清零方便下次计算

                cpui(gameui,tempui);

                if(cantmov(gameui)==1)

                    v=1;

                break;



 

            //向左

            case 'a':

                //每一行向左靠拢,相同的数据合并,其他为0的位置随机产生一个2

                //界面再刷新一次

                //每一行向左靠拢

                for(j=0; j<4; j++)

                {

                    for(i=0,k=0; i<4; i++)

                    {

                        if(gameui[j][i]!=0) //说明有数字

                        {

                            tempui[j][k++]=gameui[j][i];

                        }

                    }

                }

                int ret3= comp(tempui,gameui);

                if (ret3 != 1)

                    flag=1;

                //相同的数据合并

                for(j=0; j<4; j++)

                {

                    for(i=0; i<4; i++)

                    {

                        if(tempui[j][i]==tempui[j][i+1]) //比较相邻的元素是否相同,相同就合并

                        {

                            if(tempui[j][i]!=0)

                                flag=2;

                            tempui[j][i]=2*tempui[j][i];

                            //合并之后[j][i+1]后面的数据要往前挪动

                            for(k=i+1; k<3; k++)

                                tempui[j][k]=tempui[j][k+1];

                            tempui[j][3]=0;

                        }

                    }

                }

                //其他为0的位置随机产生一个2

                if(flag !=0)

                {

                    gettwo(tempui);

                    flag=0;

                }

                //界面再刷新一次

                system("clear");

                showui(tempui);

                if(vectory(tempui)==1)

                    f=1;

                //把目前游戏的结果备份到gameui,顺便把tempui清零方便下次计算

                cpui(gameui,tempui);

                if(cantmov(gameui)==1)

                    v=1;

                break;


 

            //向右

            case 'd':

                //每一行向右靠拢,相同的数据合并,其他为0的位置随机产生一个2

                //界面再刷新一次

                //每一行向右靠拢

                for(j=0; j<4; j++)

                {

                    for(i=3,k=3; i>=0; i--)

                    {

                        if(gameui[j][i]!=0) //说明有数字

                        {

                            tempui[j][k--]=gameui[j][i];

                        }

                    }

                }

                int ret4= comp(tempui,gameui);

                if (ret4 != 1)

                    flag=1;

                //相同的数据合并

                for(j=0; j<4; j++)

                {

                    for(i=3; i>=0; i--)

                    {

                        if(tempui[j][i]==tempui[j][i-1]) //比较相邻的元素是否相同,相同就合并

                        {

                            if(tempui[j][i]!=0)

                            flag=2;

                            tempui[j][i]=2*tempui[j][i];

                            //合并之后[j][i-1]前面的数据要往后挪动

                            for(k=i-1; k>0; k--)

                                tempui[j][k]=tempui[j][k-1];

                            tempui[j][0]=0;

                        }

                    }

                }

                //其他为0的位置随机产生一个2

                if(flag !=0)

                {

                    gettwo(tempui);

                    flag=0;

                }

                //界面再刷新一次

                system("clear");

                showui(tempui);

                if(vectory(tempui)==1)

                    f=1;

                //把目前游戏的结果备份到gameui,顺便把tempui清零方便下次计算

                cpui(gameui,tempui);

                if(cantmov(gameui)==1)

                    v=1;

                break; 

        }

        if(f==1)

        {

            printf("您已成功完成游戏!\n");

            break;

        }

        if(v==1)

        {

            printf("游戏失败!\n");

            break;

        }

    }

}

 类似资料: