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

C/C++的学习裙【七一二 二八四 七零五】,无论你是小白还是进阶者,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享!(点击蓝字进入)

一、2048游戏原理

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

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

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

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

4)想赢得游戏,玩家需要产生一块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分别代替左右上下以及退出键。如果最后游戏成功了,则会提示成功,如果失败则会退出程序。详细的游戏逻辑可通过代码以及文档进行了解。

C语言初级编程实践:2048小游戏的更多相关文章

  1. 2048小游戏代码解析 C语言版

    2048小游戏,也算是风靡一时的益智游戏.其背后实现的逻辑比较简单,代码量不算多,而且趣味性强,适合作为有语言基础的童鞋来加强编程训练.本篇分析2048小游戏的C语言实现代码. 前言 游戏截图:  游 ...

  2. jQuery实践-网页版2048小游戏

    ▓▓▓▓▓▓ 大致介绍 看了一个实现网页版2048小游戏的视频,觉得能做出自己以前喜欢玩的小游戏很有意思便自己动手试了试,真正的验证了这句话-不要以为你以为的就是你以为的,看视频时觉得看懂了,会写了, ...

  3. 2048小游戏4X4C语言

    */ #include<stdio.h> #include<stdlib.h> #include<conio.h> #include<time.h> v ...

  4. Swift实战之2048小游戏

    上周在图书馆借了一本Swift语言实战入门,入个门玩一玩^_^正好这本书的后面有一个2048小游戏的实例,笔者跟着实战了一把. 差不多一周的时间,到今天,游戏的基本功能已基本实现,细节我已不打算继续完 ...

  5. 如何在CentOS上安装一个2048小游戏

    如何在centos上安装一个2048小游戏 最近在学习CentOS系统,就琢磨着玩点什么,然后我看到有人在玩2048小游戏,所有我就在想,为啥不装一个2048小游戏搞一下嘞,于是乎,我就开始工作啦 由 ...

  6. 基于jQuery的2048小游戏设计(网页版)

    上周模仿一个2048小游戏,总结一下自己在编写代码的时候遇到的一些坑. 游戏规则:省略,我想大部分人都玩过,不写了 源码地址:https://github.com/xinhua6/2048game.g ...

  7. .NET手撸2048小游戏

    .NET手撸2048小游戏 2048是一款益智小游戏,得益于其规则简单,又和2的倍数有关,因此广为人知,特别是广受程序员的喜爱. 本文将再次使用我自制的"准游戏引擎"FlysEng ...

  8. C# 开发2048小游戏

    这应该是几个月前,闲的手痒,敲了一上午代码搞出来的,随之就把它丢弃了,当时让别人玩过,提过几条更改建议,但是时至今日,我也没有进行过优化和更改(本人只会作案,不会收场,嘎嘎),下面的建议要给代码爱好的 ...

  9. js、jQuery实现2048小游戏

    2048小游戏 一.游戏简介:  2048是一款休闲益智类的数字叠加小游戏 二. 游戏玩法: 在4*4的16宫格中,您可以选择上.下.左.右四个方向进行操作,数字会按方向移动,相邻的两个数字相同就会合 ...

随机推荐

  1. myBatis初学经验----(1)

    Java常用的三种编写模式 Spring,SpringMVC,myBatis. myBatis(原名:iBatis): 开源的ORM(持久层)框架,之前为apahce旗下顶级开源项目,后转到googl ...

  2. 【转】Event Driven Programming

    FROM: http://lazyfoo.net/tutorials/SDL/03_event_driven_programming/index.php Event Driven Programmin ...

  3. RocketMQ4.7.1双主双从集群搭建

    导读 上一集我们已经学会了SpringBoot整合RocketMQ点我直达,今天我们来搭建双主双从高性能MQ服务集群. 简介 主从架构 Broker角色,Master提供读写,Slave只支持读,Co ...

  4. 自己动手实现一个简单的 IOC容器

    控制反转,即Inversion of Control(IoC),是面向对象中的一种设计原则,可以用有效降低架构代码的耦合度,从对象调用者角度又叫做依赖注入,即Dependency Injection( ...

  5. Java学习的第二十五天

    1.字节流输出内容 用字节流读文件内容 字符输出流写入 字符输入流 2.没问题 3.明天学习到缓冲流

  6. .NET CORE QuartzJob定时任务+Windows/Linux部署

    前言 以前总结过一篇基于Quartz+Topshelf+.netcore实现定时任务Windows服务 https://www.cnblogs.com/gt1987/p/11806053.html.回 ...

  7. SYL数据库表关系图 AND 项目架构图

    关系图(内容按照具体项目要求可以改) 项目架构图

  8. 庐山真面目之二微服务架构NGINX版本实现

    一.简介          在上一篇文章<庐山真面目之微服务的简介和技术栈>中,我们已经探讨了微服务的来龙去脉,也说了想要实现微服务架构所需要的技术栈,今天我们开始实现一个微服务,当然这个 ...

  9. Vue的生命周期--代码片段

    Vue 实例有一个完整的生命周期,也就是从开始创建. 初始化数据. 编译模板. 挂载 Dom. 渲染→更新→渲染. 销毁等一系列过程,我们称这是 Vue 的生命周期.通俗说就是 Vue 实例从创建到销 ...

  10. 企业中真实需要的集中管理软件SVN即Subversion版本控制

    一.SVN基本概念 SVN是Subversion的简称,是一个自由开源的版本控制系统. checkout: 把整个项目源码下载到本地 update: 从服务器上更新代码,使本地达到最新版本 commi ...