2048 游戏代码:C 语言实现,使用 curses 库

该代码使用 C 语言和 curses 库实现经典的 2048 游戏。代码简洁易懂,并附带详细解释。

//  gcc 2048.c -o 2048 -lpthread -lcurses

#include <stdio.h>
#include <curses.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

int array[4][4] = {
	{0,0,0,0},
	{0,0,0,0},
	{0,0,0,0},
	{0,0,0,0},
};
int tmp[4];//这个作为临时数据处理的一维数组
int kong = 16;//初始状态空位是16个。
int MAX=0;//最大值

WINDOW *win[16];//用来存放16个小窗口

void create_window()//创建16个小窗口
{
	int i,j;
	int data=0;
	for(i=0;i<4;i++)
		for(j=0;j<4;j++)
		{
			win[4*i+j] = subwin(stdscr,3,6,2+3*i,1+6*j);//创建小窗口,并定好位置
			box(win[4*i+j],0,0);//给每一个小窗口设置好边框
			wrefresh(win[4*i+j]);//只刷新小窗口
		}
}


void show_2048()//显示2048的矩阵
{
	int i,j;
	for(i=0;i<4;i++)
		for(j=0;j<4;j++)
		{
			//销毁小窗口
			delwin(win[4*i+j]);
			
			//创建新的小窗口
			win[4*i+j] = subwin(stdscr,3,6,2+3*i,1+6*j);//创建小窗口,并定好位置
			
			//根据数值开启颜色索引
			switch(array[i][j])
			{
				case 0: wattron(win[4*i+j],COLOR_PAIR(1)); break;
				case 2: wattron(win[4*i+j],COLOR_PAIR(2)); break;
			}
			
			box(win[4*i+j],0,0);//给每一个小窗口设置好边框
			
			//向第i行第j列的小窗口,放入数组中第i行第j列的数值
			mvwprintw(win[4*i+j],1,1,"%4d",array[i][j]);
			wrefresh(win[4*i+j]);//只刷新小窗口
			
			//关闭颜色索引
			switch(array[i][j])
			{
				case 0: wattroff(win[4*i+j],COLOR_PAIR(1)); break;
				case 2: wattroff(win[4*i+j],COLOR_PAIR(2)); break;
			}
		}
}

void get_rand()//获取随机数
{
	while(1)//判断条件非0,会永远循环,除非break
	{
		//数值只能在0~3之间获取
		int i,j;
		i = rand()%4;
		j = rand()%4;
		
		//当随机产生的位置上是数值0,则赋值为2
		if(array[i][j] == 0)
		{
			array[i][j] = 2;
			
			break;//跳出循环
		}
	}
	
	kong--;//每次产生一个随机数,空位-1
}


void do_date()//处理数据---数值累加并且把数值都向左边顶格
{
	int i,j;
	//printf("%d,%d,%d,%d----",tmp[0],tmp[1],tmp[2],tmp[3]);
	//第一步,从左边第一个数值开始,往右边判断是否有相邻数值
	//如果有,累加
	//如果是0,跳过
	//如果不等,结束本次循环
	for(i=0;i<4;i++)
	{
		if(tmp[i] == 0)//如果数值本身为0,不需要进行累加或其他判断,直接下一次循环
			continue;
		
		for(j=i+1;j<4;j++)
		{
			if(tmp[j] == 0)//相邻数值为0
				continue;//表示结束本次循环,j++会继续执行
			
			if( tmp[j] != 0 && tmp[i] == tmp[j])//如果两者相等,求和,并且后一个赋值0
			{
				tmp[i] = tmp[i] + tmp[j];
				tmp[j] = 0;
				
				kong++;//当两个相同的数值相加的时候,空位+1
				if(tmp[i] > MAX)
					MAX = tmp[i];//这里面始终保存最大值
				
				break;//表示结束本次循环,j++不执行,直接退出一层for循环
			}
			
			if(tmp[j] != 0 && tmp[i] != tmp[j])//不等且不为0
				break;//表示结束本次循环,j++不执行,直接退出一层for循环
		}
	}
	//printf("%d,%d,%d,%d----",tmp[0],tmp[1],tmp[2],tmp[3]);
	//去掉数值之间的空格,并且顶格。
	for(i=0;i<4;i++)
	{
		if(tmp[i] == 0)
		{
			for(j=i+1;j<4;j++)
			{
				if(tmp[j] !=0 )
				{
					tmp[i] = tmp[j];
					tmp[j] = 0;
					break;//表示结束本次循环,j++不执行,直接退出一层for循环
				}
			}
		}
	}
	
	//printf("%d,%d,%d,%d\n",tmp[0],tmp[1],tmp[2],tmp[3]);
}

void do_left()//向左
{
	//应该把数值都放入到tmp里面,然后每行都运行一次数据处理
	int i,j;
	for(i=0;i<4;i++)
	{
		for(j=0;j<4;j++)
			tmp[j] = array[i][j];//把第i行数据放入到tmp
		
		do_date();//数据放完了再处理
		
		for(j=0;j<4;j++)
			array[i][j] = tmp[j];//再把数据放回到第i行
	}
}

void do_right()//向右
{
	int i,j;
	for(i=0;i<4;i++)
	{
		for(j=0;j<4;j++)
			tmp[3-j] = array[i][j];//把第i行数据放入到tmp
		
		do_date();
			
		for(j=0;j<4;j++)
			array[i][j] = tmp[3-j];//把数据倒着放回到array中
	}
}

void do_up()//向上
{
	//应该把数值都放入到tmp里面,然后每行都运行一次数据处理
	int i,j;
	for(j=0;j<4;j++)
	{
		for(i=0;i<4;i++)
			tmp[i] = array[i][j];//把第j列数据放入到tmp
		
		do_date();
		
		for(i=0;i<4;i++)
			array[i][j] = tmp[i];//再把数据放回到第j列
	}
}

void do_down()//向下
{
	//应该把数值都放入到tmp里面,然后每行都运行一次数据处理
	int i,j;
	for(j=0;j<4;j++)
	{
		for(i=0;i<4;i++)
			tmp[3-i] = array[i][j];//把第j列数据放入到tmp
		
		do_date();
		
		for(i=0;i<4;i++)
			array[i][j] = tmp[3-i];//再把数据放回到第j列
	}
}

int main()
{
	initscr();//初始化屏幕和ty终端
	
	create_window();//创建16个小窗口
	keypad(stdscr,TRUE);//在stdscr中开启特殊键盘类
	start_color();//开启颜色
	
	//定义颜色索引
	init_pair(1 ,COLOR_WHITE ,COLOR_CYAN );//索引1
	init_pair(2 ,COLOR_RED ,COLOR_GREEN  );//索引2
	
	srand(time(NULL));//获取随机数种子
	
	get_rand();
	get_rand();

	show_2048();
	
	int num;
	while(1)
	{
		num = getch();//直接从键盘获取
		refresh();

		if(num==KEY_LEFT)//向左 KEY_LEFT
			do_left();
		if(num==KEY_RIGHT)//向右 KEY_RIGHT
			do_right();
		if(num==KEY_UP)//向上 KEY_UP
			do_up();
		if(num==KEY_DOWN)//向下 KEY_DOWN
			do_down();

		get_rand();//每次键盘结束以后,在空余的位置产生数值2
		show_2048();//显示屏幕
		
		if(MAX == 2048)
		{
			printf("游戏成功\n");
			return 0;
		}
		
		//判断是否还有空位
		if(kong == 0)
		{
			//检查两两相邻的数值有没有重复的
			//先检查横向是否有相邻,如果有,就判断只能左右按键
			//再检查纵向是否有相邻,如果有,就判断只能上下按键
			//总结按键方向的结果,判断是否可以继续运行。
			//如果都不可以,就结束游戏
			
			printf("结束游戏\n");
			sleep(3);
			break;
		}
	}
	
	endwin();//销毁屏幕和ty终端
	
	return 0;
}

代码说明

  1. 创建游戏矩阵

    array[4][4] 数组用来存储游戏矩阵。

  2. 创建游戏窗口

    create_window() 函数使用 curses 库创建 16 个小窗口,用于显示游戏矩阵的每个格子的数字。

  3. 显示游戏矩阵

    show_2048() 函数负责在每个小窗口中显示对应 array 中的数字,并根据数字大小设置不同的颜色。

  4. 随机生成数字

    get_rand() 函数随机选择一个空格子,并在该格子中生成数字 2。

  5. 处理玩家操作

    do_left(), do_right(), do_up(), do_down() 函数分别处理玩家向左、向右、向上、向下移动的操作。

    • 使用 tmp 数组临时存储一行或一列数据。
    • 调用 do_date() 函数处理数据,使相同数字合并,并把数值都向左边顶格。
    • 将处理后的数据写入 array 数组。
  6. 游戏逻辑

    main() 函数实现游戏主循环:

    • 初始化游戏环境,包括创建窗口、开启颜色、生成随机数字。
    • 循环读取玩家操作,调用对应函数处理数据,并更新游戏界面。
    • 判断游戏是否结束:
      • MAX 等于 2048 时,游戏成功。
      • kong 等于 0,即没有空格子时,游戏结束。

代码中关键部分的解释

  • do_date() 函数中 for(i=0;i<4;i++) 部分:

    这部分代码将 tmp 数组中的数字紧凑排列在一起,去掉数值之间的空格,并将数值都顶格。

    • tmp[i] 为 0 时,它将 tmp[i] 后面的非零数字往前移动,直到遇到非零数字或者到达数组末尾。
    • 缺少这部分代码会导致游戏界面中数字排列不整齐,影响游戏体验。

游戏玩法

  • 游戏目标:将数字方块合并成 2048。
  • 操作方法:使用方向键控制数字方块移动。
  • 规则:
    • 当两个相同的数字方块相撞时,它们会合并成一个新的数字方块,其值为两个相撞数字的和。
    • 每次移动后,游戏会在空格中随机生成一个新的数字方块。
    • 当游戏界面没有空格子且没有可以合并的数字时,游戏结束。

扩展功能

可以根据需要对代码进行扩展,例如:

  • 增加游戏难度,例如增加新数字 4 或 8,或改变生成数字的频率。
  • 实现游戏排行榜功能。
  • 使用更精美的界面设计。

总结

该代码是一个简单的 2048 游戏的 C 语言实现,使用 curses 库进行界面开发。代码简洁易懂,便于学习和修改。开发者可以根据自己的需求进行扩展,开发出更加丰富多彩的游戏。

希望这篇文章能够帮助您理解 2048 游戏的实现原理,并激发您开发游戏的想法!


原文地址: https://www.cveoy.top/t/topic/phlN 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录