当前位置:首页 > 公众号精选 > 嵌入式云IOT技术圈
[导读]大部分同学学习C语言编程以后不知道能通过什么样的项目才可以锻炼自己的思维功力,2048相信大家都应该熟悉,不管是手机上还是网页版的相信大家都玩过,这个简单的控制台版本的游戏是我曾经在伟易达上班时一个嵌入式应用游戏部门的大佬设计的,适合于喜欢用C语

大部分同学学习C语言编程以后不知道能通过什么样的项目才可以锻炼自己的思维功力,2048相信大家都应该熟悉,不管是手机上还是网页版的相信大家都玩过,这个简单的控制台版本的游戏是我曾经在伟易达上班时一个嵌入式应用游戏部门的大佬设计的,适合于喜欢用C语言写一些简易的游戏的朋友,逻辑性很强。

一、2048游戏原理

在最初的游戏, 它始于一个空4 x 4游戏板。

1)在空位置的游戏板上,每一轮游戏产生一个“2”或“4”随机的数字。

2)接下来,玩家输入的上移,下移,左移或右移命令移动块。两个相邻块相同的号码,若是Q,可以组合成一个块数量2Q。

3)如果没有空间产生一个新的数字块,玩家则game over。

4)想赢得游戏,玩家需要产生一块2048数字块。

二、2048游戏文档

当然,这些游戏的逻辑不是大家闷着脑子就能空想出来的,它一定有很规范的说明文档,由专业的人来书写,最后软件工程师参考对应的文档编写自己的代码

篇幅有限,详细的下载链接:

链接:https://pan.baidu.com/s/1Daan58WN-A95BeYQcmSyDA
提取码:m6ie

当然也可以访问Github网站,这是一个开源的项目,后面各位牛逼的大佬经过移植后,运行在各个平台下,原版本链接如下:

http://gabrielecirulli.github.io/2048/

三、2048游戏源代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <conio.h>

//num
#define FALSE 0
#define TRUE 1

#define EMPTY_CELL 0

#define GMAE_ROW 4
#define GMAE_COL 4

//GameState
#define STATE_SELECT 0
#define STATE_PREPARE 1
#define STATE_PALYING 2
#define STATE_EXIT 3

//GameMode
#define MODE_NONE 0
#define MODE_NORMAL 1
#define MODE_DEBUG 2

//Select Index
#define INDEX_MAXNUM 3
#define INDEX_NORMAL 0
#define INDEX_DEBUG 1
#define INDEX_EXIT 2

//Command
#define COM_LEFT 'a'
#define COM_RIGHT 'd'
#define COM_UP 'w'
#define COM_DOWN 's'
#define COM_QUIT 'q'

//direction
#define DIR_HEAD 0xe0
#define KEY_UP 0xe048
#define KEY_DOWN 0xe050
#define KEY_LEFT 0xe04b
#define KEY_RIGHT 0xe04d


#define ESC 0x1B
#define ENTER 0x0D

//type
typedef unsigned int Uint;
typedef unsigned short Ushort;
typedef unsigned char Uchar;

//declaration
static void GM_Init(void);
static void GM_End(void);

static Uint GM_SelectInit(void);
static Uint GM_SelectHandle(void);
static Uint GM_SelectEnd(void);

static Uint GM_PrepareInit(void);
static Uint GM_PrepareHandle(void);
static Uint GM_PrepareEnd(void);

static Uint GM_PlayingInit(void);
static Uint GM_PlayingHandle(void);
static Uint GM_PlayingEnd(void);


static Uint GM_SelectHandleEnter(void);
static Uint GM_SelectHandleEsc(void);
static void GM_PrintSelectMode(void);
static void GM_RandAddOneNum(void);
static Uchar GM_FromFileAddNum(void);
static Uchar GM_InputAddOneNum(void);
static Uchar GM_NotMoreMove(void);
static void GM_PrintBoard(void);

static Uchar GM_CheckWin2048(void);
static Uchar GM_PlayingPull(void);
static Uchar GM_CombineRight(Uint *array, int num);
static Uchar GM_CombineLeft(Uint *array, int num);
static Uchar GM_MoveRight(Uint *array, int num);
static Uchar GM_MoveLeft (Uint *array, int num);

//struct
typedef struct gameinfo {
Uint Board[GMAE_ROW][GMAE_COL];

Uchar GameState;
Uchar GameMode;

Uchar StateSelectIndex;

Uint PlayingCommand;

}GameInfo, *P_GameInfo;

GameInfo GM;

int main(void)
{
GM_Init();

while(1)
{
switch(GM.GameState)
{
case STATE_SELECT:
GM_SelectHandle();
break;
case STATE_PREPARE:
GM_PrepareHandle();
break;
case STATE_PALYING:
GM_PlayingHandle();
break;
case STATE_EXIT:
goto GAME_EXIT;
default:
break;
}
}

GAME_EXIT:
GM_End();
return 0;
}

static void GM_Init(void)
{
memset(&GM, 0, sizeof(GameInfo));
srand((int)time(NULL));

GM_SelectInit();
}

static void GM_End(void)
{
memset(&GM, 0, sizeof(GameInfo));

fflush(stdin);
printf("\nCommand [q] can quit\n");
while('q' != getch());

}

static Uint GM_SelectInit(void)
{
GM.GameState = STATE_SELECT;
GM.StateSelectIndex = INDEX_NORMAL;
GM_PrintSelectMode();
}

static Uint GM_SelectHandle(void)
{
GM_PrintSelectMode();

fflush(stdin);
Uchar ch1 = getch();
if( ENTER == ch1)
{
GM_SelectHandleEnter();
}
else if( ESC == ch1 )
{
GM_SelectEnd();
GM.GameState = STATE_EXIT;
}
else if ( DIR_HEAD == ch1)
{
Uchar ch2 = getch();
Ushort Key = (ch1 << 8)&0xff00 | ch2;
switch(Key)
{
case KEY_UP:
GM.StateSelectIndex = (GM.StateSelectIndex + INDEX_MAXNUM - 1) % INDEX_MAXNUM;
break;

case KEY_DOWN:
GM.StateSelectIndex = (GM.StateSelectIndex + 1) % INDEX_MAXNUM;
break;

default:
break;
}
}
}

static Uint GM_SelectEnd(void){}


static Uint GM_PrepareInit(void)
{
Uchar OldState = GM.GameState;
GM.GameState = STATE_PREPARE;

//from STATE_SELECT --> STATE_PREPARE
if(STATE_SELECT == OldState)
{
if(MODE_NORMAL == GM.GameMode)
{
GM_RandAddOneNum();
GM_RandAddOneNum();
}
else
{
GM_FromFileAddNum();
}
}
//from STATE_PALYING --> STATE_PREPARE
else
{
if(MODE_NORMAL == GM.GameMode)
{
GM_RandAddOneNum();
}
else
{
GM_PrintBoard();
while(FALSE == GM_InputAddOneNum());
}
}
GM_PrintBoard();
}

static Uint GM_PrepareHandle(void)
{
if(TRUE != GM_NotMoreMove())
{
GM_PrepareEnd();
GM_PlayingInit();
}
else
{
printf("Game Over!\n");
GM.GameState = STATE_EXIT;
}

}

static Uint GM_PrepareEnd(void){}

static Uint GM_PlayingInit(void)
{
GM.GameState = STATE_PALYING;
printf( "PULL: [a]LEFT [d]RIGHT [w]UP [s]DOWN [q]QUIT\n" );
printf( "Command: ");
fflush(stdout);
}

static Uint GM_PlayingHandle(void)
{
fflush(stdin);
GM.PlayingCommand = getch();


switch(GM.PlayingCommand)
{
case COM_LEFT:
case COM_RIGHT:
case COM_UP:
case COM_DOWN:
if( FALSE == GM_PlayingPull())
{
printf("[Error] invalid direction\n");
printf( "Command: ");
}
else
{
if( TRUE == GM_CheckWin2048() )
{
GM_PrintBoard();
printf("you win !\n");
GM.GameState = STATE_EXIT;
}
else
{
GM_PlayingEnd();
GM_PrepareInit();
}
}
break;
case COM_QUIT:
printf("Bye !\n");
GM.GameState = STATE_EXIT;
break;
default:
printf("[Error] Command is a, d, w, s, q \n");
printf( "Command: ");
fflush(stdout);
break;
}
//GM_PrintBoard();
}

static Uint GM_PlayingEnd(void)
{
GM.PlayingCommand = 0;
}


static Uint GM_SelectHandleEnter(void)
{
switch(GM.StateSelectIndex)
{
case INDEX_NORMAL:
case INDEX_DEBUG:
if(INDEX_NORMAL == GM.StateSelectIndex)
{
GM.GameMode = MODE_NORMAL;
}
else
{
GM.GameMode = MODE_DEBUG;
}
GM_SelectEnd();
GM_PrepareInit();
break;

case INDEX_EXIT:
GM_SelectEnd();
GM.GameState = STATE_EXIT;
break;

default:
printf("error\n");
break;
}

}

static Uint GM_SelectHandleEsc(void){}


static void GM_PrintSelectMode(void)
{
system("cls");
printf("# - - - - - - - - #\n");
printf("# welcome to 2048 #\n");
printf("# - - - - - - - - #\n");
printf(" MODU SELECT \n");

printf("\n ");
printf(GM.StateSelectIndex==INDEX_NORMAL?"-->NORMAL":" NORMAL");
printf("\n ");
printf(GM.StateSelectIndex==INDEX_DEBUG? "-->DEBUG ":" DEBUG ");
printf("\n ");
printf(GM.StateSelectIndex==INDEX_EXIT? "-->EXIT ":" EXIT ");
}


static void GM_RandAddOneNum(void)
{
int row, col;

while (1)
{
row = rand() % GMAE_ROW;
col = rand() % GMAE_COL;
if ( GM.Board[row][col] == EMPTY_CELL )
{
GM.Board[row][col] = ((rand() % 2) + 1) * 2;
break;
}
}
}

static Uchar GM_FromFileAddNum(void)
{
FILE *infp;
Uchar tmp[6],tmp1;
Uchar ret = 0;
Uchar i,j;

if(infp = fopen("map.txt", "rb"))
{
for(i = 0; i < GMAE_ROW * GMAE_COL; i++)
{
j = 0;
memset(tmp, 0, sizeof(tmp));
while(1)
{
if(!fread(&tmp[j], 1, 1, infp))
ret |= 0x02;

if(tmp[j] == ' ' || tmp[j] == '\n' || tmp[j] == 0)
break;

j++;
}
*(&GM.Board[0][0]+i) = atoi((const char *)tmp);
}
}
else
{
ret |= 0x01;
}

if(NULL != infp)
{
fclose(infp);
}

if(ret != 0)
{
printf("read map txt fail\n");
}
return ret;

}

static Uchar GM_InputAddOneNum(void)
{
int row, col, value;
int ret = TRUE;
printf("please input add one num!\n");
printf("Row,Col,Value :");
fflush(stdout);
fflush(stdin);
scanf("%d,%d,%d", &row, &col, &value);

if(row >= GMAE_ROW || row < 0)
{
printf("[Error] Row is between 0 and %d !\n", GMAE_ROW-1);
ret = FALSE;
}

if(col >= GMAE_COL || col < 0)
{
printf("[Error] Col is between 0 and %d !\n", GMAE_COL-1);
ret = FALSE;
}

if(ret == TRUE && GM.Board[row][col] != 0)
{
printf("[Error] ( %d , %d ) is occupied!\n", row, col);
ret = FALSE;
}

if(value != 2 && value != 4)
{
printf("[Error] Cell Value is either 2 or 4\n");
ret = FALSE;
}

if(ret == TRUE)
{
GM.Board[row][col] = value;
}
return ret;
}

static Uchar GM_NotMoreMove(void)
{
int NotMoreMove = TRUE;
int row, col;
for ( row = 0; row < GMAE_ROW; row++)
{
for ( col = 0; col < GMAE_COL; col++)
{
if(GM.Board[row][col] == 0)
{
NotMoreMove = FALSE;
break;
}

if( col+1 < GMAE_COL && GM.Board[row][col] == GM.Board[row][col+1])
{
NotMoreMove = FALSE;
break;
}

if( row+1 < GMAE_ROW && GM.Board[row][col] == GM.Board[row+1][col])
{
NotMoreMove = FALSE;
break;
}
}
if(FALSE == NotMoreMove)
break;
}
return NotMoreMove;
}

static void GM_PrintBoard(void)
{
int row, col;
system("cls");
printf("# - - - - - - - - #\n");
printf("# welcome to 2048 #\n");
printf("# - - - - - - - - #\n");
for ( row = 0; row < GMAE_ROW; row++)
{
for ( col = 0; col < GMAE_COL; col++)
{
printf(" + - -", GM.Board[row][col]);
}
printf(" +\n");
for ( col = 0; col < GMAE_COL; col++)
{
if(0 == GM.Board[row][col])
printf(" | ");
else
printf(" |%4d", GM.Board[row][col]);
}
printf(" |\n");
}
printf(" + + + + + + + + + + + + + \n");

}

static Uchar GM_CheckWin2048(void)
{
int row,col;

for ( row = 0; row < GMAE_ROW; row++)
{
for ( col = 0; col < GMAE_COL; col++)
{
if( GM.Board[row][col] == 2048 )
{
return TRUE;
}
}
}
return FALSE;
}

static Uchar GM_PlayingPull(void)
{
//GMAE_ROW 行 4
//GMAE_COL 列 4

int index;
int col, row;
Uchar PullFlag = FALSE;
Uint array[GMAE_ROW > GMAE_COL? GMAE_ROW:GMAE_COL];

//******************COM_LEFT*******************
if( COM_LEFT == GM.PlayingCommand)
for ( row = 0; row < GMAE_ROW; row++)
{
PullFlag |= GM_MoveLeft( (Uint *)GM.Board[row], GMAE_COL );
PullFlag |= GM_CombineLeft( (Uint *)GM.Board[row], GMAE_COL );
PullFlag |= GM_MoveLeft( (Uint *)GM.Board[row], GMAE_COL );
}

//******************COM_RIGHT******************
else if( COM_RIGHT == GM.PlayingCommand)
for ( row = 0; row < GMAE_ROW; row++)
{
PullFlag |= GM_MoveRight( (Uint *)GM.Board[row], GMAE_COL );
PullFlag |= GM_CombineRight( (Uint *)GM.Board[row], GMAE_COL );
PullFlag |= GM_MoveRight( (Uint *)GM.Board[row], GMAE_COL );
}

//******************COM_UP*********************
else if( COM_UP == GM.PlayingCommand)
for ( col = 0; col < GMAE_COL; col++)
{
for ( row = 0; row < GMAE_ROW; row++)
{
array[row] = GM.Board[row][col];
}

//a col move Left
PullFlag |= GM_MoveLeft( (Uint *)array, GMAE_ROW );
PullFlag |= GM_CombineLeft( (Uint *)array, GMAE_ROW );
PullFlag |= GM_MoveLeft( (Uint *)array, GMAE_ROW );

//write a col
for ( row = 0; row < GMAE_ROW; row++)
{
GM.Board[row][col] = array[row];
}
}

//******************COM_DOWN******************
else if( COM_DOWN == GM.PlayingCommand)
for ( col = 0; col < GMAE_COL; col++)
{
//read a col
for ( row = 0; row < GMAE_ROW; row++)
{
array[row] = GM.Board[row][col];
}

//a col move right
PullFlag |= GM_MoveRight( (Uint *)array, GMAE_ROW );
PullFlag |= GM_CombineRight( (Uint *)array, GMAE_ROW );
PullFlag |= GM_MoveRight( (Uint *)array, GMAE_ROW );

//write a col
for ( row = 0; row < GMAE_ROW; row++)
{
GM.Board[row][col] = array[row];
}
}

return PullFlag;
}

static Uchar GM_CombineLeft(Uint *array, int num)
{
int i;
Uchar CombineFlag = FALSE;
for ( i = 0; i < num-1; i++ )
{
if( array[i] != 0 && array[i] == array[i+1] )
{
array[i] *= 2;
array[i+1] = 0;
CombineFlag = TRUE;
}
}
return CombineFlag;
}


static Uchar GM_CombineRight(Uint *array, int num)
{
int i;
Uchar CombineFlag = FALSE;
for ( i = num-1; i >= 1; i-- )
{
if( array[i] != 0 && array[i] == array[i-1] )
{
array[i] *= 2;
array[i-1] = 0;
CombineFlag = TRUE;
}
}
return CombineFlag;
}


static Uchar GM_MoveRight(Uint *array, int num)
{
int i;
int index = num - 1;
Uchar moveflg = FALSE;

for(i = num-1; i >= 0; i--)
{

if(array[i] != 0)
{
if(array[i] != array[index])
{
array[index] = array[i];
moveflg = TRUE;
}
index--;
}
}

while(index != -1)
{
array[index] = 0;
index--;
}

return moveflg;

}


static Uchar GM_MoveLeft(Uint *array, int num)
{
int i;
int index = 0;
Uchar moveflg = FALSE;

for(i = 0; i < num; i++)
{

if(array[i] != 0)
{
if(array[i] != array[index])
{
array[index] = array[i];
moveflg = TRUE;
}
index++;
}
}

while(index != num)
{
array[index] = 0;
index++;
}

return moveflg;

}

四、运行结果

游戏主菜单界面,通过方向键选择,分别有NORMAL(正常进行游戏)、DEBUG(调试模式)、EXIT(退出游戏)

按回车键进入对应的模式。

用字母a、d、w、s、q分别代替左右上下以及退出键。

如果最后游戏成功了,则会提示成功,如果失败则会退出程序。

详细的游戏逻辑可通过代码以及文档进行了解。

往期精彩

嵌入式系统软件架构设计(长篇深度好文)

专为MCU项目开发提速的代码框架BabyOS

嵌入式C语言代码优化方案(深度好文,建议花时间研读并收藏)

C语言表驱动法编程实践(精华帖,建议收藏并实践)

嵌入式工程师买车、用车的总结

若觉得本次分享的文章对您有帮助,随手点[在看]并转发分享,也是对我的支持。


免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

嵌入式开发作为信息技术领域的重要分支,其涉及的语言种类繁多,各具特色。这些语言的选择取决于目标平台的特性、性能需求、开发者的熟练程度以及项目的具体要求。本文将详细介绍几种常见的嵌入式开发语言,包括C语言、C++、汇编语言...

关键字: 嵌入式开发 C语言

Java语言和C语言是两种不同的编程语言,它们在语法、特性和应用领域上有许多差别。下面将详细介绍Java语言和C语言之间的差异以及它们各自的技术特点。

关键字: Java语言 C语言 编程

嵌入式系统是一种专门设计用于特定应用领域的计算机系统,它通常由硬件和软件组成,并且被嵌入到其他设备或系统中,以实现特定的功能。在嵌入式系统的开发过程中,选择适合的编程语言是至关重要的。C语言是一种被广泛应用于嵌入式系统开...

关键字: 嵌入式 计算机 C语言

C语言是一种广泛应用于软件开发领域的编程语言。它是由贝尔实验室的Dennis Ritchie在20世纪70年代初创建的,旨在为UNIX操作系统的开发提供一种高级编程语言。C语言具有简洁、高效、可移植性强等特点,因此成为了...

关键字: C语言 操作系统 应用程序

嵌入式系统是现代生活中无处不在的一部分。它们包括了我们的家电、汽车、智能手机、医疗设备等等。这些系统的工作必须高效、可靠,因为它们往往控制着生活中的关键方面。而C语言作为一种广泛用于嵌入式系统开发的编程语言,其质量和稳定...

关键字: 嵌入式系统 C语言 编程

在嵌入式系统开发领域中,C语言是使用最广泛的编程语言之一。它具有高效、灵活和可移植的特点,成为嵌入式系统设计师的首选语言。本文将介绍C语言编程的基本概念、特点以及在嵌入式系统开发中的应用。

关键字: 嵌入式系统 C语言 编程

C语言编译器是一种用于将C语言源代码转换为可执行程序的软件工具。它的主要功能是将C语言代码翻译成机器语言,以便计算机能够理解和执行。C语言编译器通常包括预处理器、编译器、汇编器和链接器等多个组件,它们协同工作以完成编译过...

关键字: C语言 编译器 Microsoft Visual C++

Matlab和C语言的区别是:1、用途不同;2、语法不同;3、运行速度不同;4、可移植性不同;5、代码管理不同。Matlab是一种数值计算和科学计算工具

关键字: matlab语言 C语言 系统编程

单片机是一种集成电路,它包含了中央处理器、存储器、输入输出接口和时钟等基本部件。单片机广泛应用于各种电子设备中,如家用电器、汽车电子、医疗设备等。单片机的使用领域已十分广泛,如智能仪表、实时工控、通讯设备、导航系统、家用...

关键字: 单片机编程 单片机 C语言

一直以来,嵌入式都是大家的关注焦点之一。因此针对大家的兴趣点所在,小编将为大家带来嵌入式的相关介绍,详细内容请看下文。

关键字: 嵌入式 C语言
关闭
关闭