一、背景

上一篇文章介绍了readline的基本用法,这一篇通过readline读取按键对2048游戏的c语言实现;

二、思路

2.1 游戏介绍

关于2048游戏,网上找了一下介绍,你可以点击这里在线进行体验:

"《2048》的初始数字则是由2+2组成的基数4。在操作方面的不同则表现为一步一格的移动,变成更为爽快的一次到底。

相同数字的方况在靠拢、相撞时会相加。系统给予的数字方块不是2就是4,玩家要想办法在这小小的16格范围中凑出「2048」这个数字方块。"

    看似简单的4x4方格游戏,梳理规则的时候发现还是比较繁琐的;

2.2 移动、合并规则

以向右移动为例,向右移动时,按照行(row)为单位各自进行处理:
  1. 移动完成后,需要保持有数字的方块都移动到最右侧,.eg: (0204)->(0024) / (2004)->(0024) / (2400)->(0024);
  2. 相邻的同等值方块进行一次合并动作,.eg: (0022)->(0004) / (0222) -> (0024) / (2222) -> (0044) / (2244) -> (0048);
  3. 相邻的意思为非零方块的相邻,即中间夹杂的零方块还需进行移动消除,.eg:(0202) -> (0004) / (2024) -> (0044);
  4. 移动、合并之后,在最左列某个零方块上产生一个2或4的新值,其中2出现的概率是4的两倍;

2.3 胜利、失败的界定

胜利则查找数组,若出现某个方格值大于等于2048则表示胜利;

失败的界定得符合以下两个条件:

  1. 4x4 数组方格都被填满,没有零值方格;
  2. 4x4 数组方格无法再相互合并,即相邻方块值各不相等;

3 实现

参考了文章[1]的思路,通过另外一个切入点,根据第二小节的描述,对移动、合并画出处理流程图如下:

开始代码的实现说明,先是定义了一个4x4的全局数组;

#define SIZE 4static int grid[SIZE][SIZE] = { {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},
};

定义了通用的移动、合并的宏,方便后续操作;

#define __move_a2b(a, b) if ( (a) != 0 ) { \printf("Move  %d to %d\n", (a), (b)); \(b) = (a); \(a) = 0; \
}#define __merge_a2b(a, b) if ( (b) != 0 ) { \printf("Merge %d to %d\n", (a), (b)); \(b) *= 2; \(a) = 0; \
}#define __try_merge_a2b(a, b) if ( (b) == (a) ) { \__merge_a2b(a, b); \
}

然后是对应流程图的右移函数的实现,(左移、上移、下移类似)

#define __for_each(i, n) for ( i = 0, n = random() % SIZE; i < SIZE; i++, n = (n + 1) % SIZE )int grid_move_right()
{   int ix = 0, jx = 0, row = 0, col = 0;printf("right\n");/* Move */for ( row = 0; row < SIZE; row++ ) {for ( col = SIZE - 1; col > 0; col-- ) {/* Fill zero by pulling */for ( ix = 0; ix < col && grid[row][col] == 0; ix++ ) {for ( jx = col; jx > 0; jx-- ) {__move_a2b(grid[row][jx - 1], grid[row][jx]);}}for ( ix = 0; ix < col - 1 && grid[row][col - 1] == 0; ix++ ) {for ( jx = col - 1; jx > 0; jx-- ) {__move_a2b(grid[row][jx - 1], grid[row][jx]);}}__try_merge_a2b(grid[row][col - 1], grid[row][col]);}}/* Generate one random cells in col[0] */if ( is_won() || is_over() ) {return;}__for_each(ix, row) {if ( grid[row][0] == 0 ) {grid[row][0] = __new_cell();break;}}grid_display(row, 0);
}

对于胜利失败的界定函数,根据需求描述进行实现:

int is_won()
{int ix = 0, jx = 0;for ( ix = 0; ix < SIZE; ix++ ) {for ( jx = 0; jx < SIZE; jx++ ) {if ( grid[ix][jx] >= 2048 ) {grid_display(ix, jx);printf("[ You won! ]\n");return 1;}}}return 0;
}int is_over()
{int ix = 0, jx = 0;for ( ix = 0; ix < SIZE; ix++ ) {for ( jx = 0; jx < SIZE; jx++ ) {if ( ix < SIZE - 1 && grid[ix][jx] == grid[ix + 1][jx] ) {return 0;}if ( jx < SIZE - 1 && grid[ix][jx] == grid[ix][jx + 1] ) {return 0;}if ( grid[ix][jx] == 0 ) {return 0;}}}printf("[ Game over! ]\n");return 1;
}

如果游戏还没结束,那么还得产生一个新的随机块,随机函数实现如下:

/* 66.66% is 2; 33.33% is 4 */
#define __new_cell() \(random() & 0x3 ? 2 : 4)

然后对应的显示函数,为了显示方便,对新产生的方块进行黄颜色标记处理

char *grid_generate(char *buffer, size_t size, int row, int col)
{int ix = 0;int jx = 0;int len = 0;#define __do_append(buffer, len, size, args...) do { \len += snprintf(buffer + len, size - len, args); \
} while(0);__do_append(buffer, len, size, "+----+----+----+----+\n");for ( ix = 0; ix < SIZE; ix++ ) {for ( jx = 0; jx < SIZE; jx++ ) {if ( grid[ix][jx] ) {if ( ix == row && jx == col ) {__do_append(buffer, len, size, "|\033[40;33m%4d\033[0m", grid[ix][jx]);}else {__do_append(buffer, len, size, "|%4d", grid[ix][jx]);}}else {__do_append(buffer, len, size, "|    ");}}__do_append(buffer, len, size, "|\n");__do_append(buffer, len, size, "+----+----+----+----+\n");}return buffer;
}void grid_display(int row, int col)
{char line[2048] = {0};fprintf(stderr, "%s", grid_generate(line, sizeof(line), row, col));
}

核心函数讲完了,最后说一下主函数,本例使用的readline库rl_bin_key()函数对按键进行绑定操作,

上下左右分别为(WSAD、KJHL),绑方向键的方法还没有找到;

// gcc -g -o 2048 2048.c -lreadline
int main(int argc, char *argv[])
{char *pline = NULL;char prompt[2048] = {0};grid_init();rl_bind_key('h', grid_move_left);rl_bind_key('j', grid_move_up);rl_bind_key('k', grid_move_down);rl_bind_key('l', grid_move_right);rl_bind_key('d', grid_move_left);rl_bind_key('w', grid_move_up);rl_bind_key('s', grid_move_down);rl_bind_key('a', grid_move_right);while ( 1 ) {pline = readline("");if ( !pline ) {break;}free(pline);}return EXIT_SUCCESS;
}

四、结果分析

运行成功、失败的结果如下:

    

上手发现一次成功的难度较大,需后续增加回滚功能减低难度,要不一步走错基本gg

然后在显示方面可以优化,比如说每次都清屏再重新打印,并增加一些提示功能...

工程源码下载

参考文章:

[1] http://www.cnblogs.com/judgeyoung/p/3760515.html

[2] https://github.com/gabrielecirulli/2048

Linux下使用readline库实现2048游戏相关推荐

  1. Linux下基于SDL库贪吃蛇游戏

    Linux下基于SDL库贪吃蛇游戏   SDL(Simple DirectMediaLayer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成.SDL提供了数种控制图像.声音.输出入的函数,让开 ...

  2. linux怎么编写弹球游戏,Linux下利用curses库实现弹球游戏.docx

    #define TOP #define TOP 0/*当前屏幕的最上边 */ Linux 下利用 curses 库实现弹球游戏 #include #include #include #define R ...

  3. linux curses,Linux下利用curses库实现弹球游戏

    控制球水平运动的变量*/ int vdir;   /*控制球垂直运动的变量*/ int pos_X;  /*球的横坐标*/ int pos_Y;  /*球的纵坐标*/ int delay=100; v ...

  4. Linux下的动态库和静态库

    什么是库? 在 Linux 开发时,我们经常会看到一些形如 xxx.so 的名称出现,其中 so 是 Shared Object 的缩写,即可以共享的目标文件,也就是我们所称为的动态链接库,和在 Wi ...

  5. Linux下的静态库、动态库和动态加载库

    from: http://www.techug.com/linux-static-lib-dynamic-lib 库的存在极大的提高了C/C++程序的复用性,但是库对于初学者来说有些难以驾驭,本文从L ...

  6. linux 下基于jrtplib库的实时传送实现

    linux 下基于jrtplib库的实时传送实现 一.RTP 是进行实时流媒体传输的标准协议和关键技术 实时传输协议(Real-time Transport Protocol,PRT)是在 Inter ...

  7. linux下安装uuid库

    1.linux 下安装UUID库 1.1)ubuntu下安装uuid链接库 sudo apt-get install uuid-dev 1.2)CentOS yum install libuuid-d ...

  8. Linux下基于Libmad库的MP3音乐播放器编写

    linux下基于Libmad库的MP3音乐播放器编写 libmad是一个开源mp3解码库,其对mp3解码算法做了很多优化,性能较好,很多播放器如mplayer.xmms等都是使用这个开源库进行解码的: ...

  9. linux下基于jrtplib库的实时传送实现

    linux 下基于jrtplib库的实时传送实现 一.RTP 是进行实时流媒体传输的标准协议和关键技术  实时传输协议(Real-time Transport Protocol,PRT)是在 Inte ...

最新文章

  1. Hive 基础(2):库、表、字段、交互式查询的基本操作
  2. 变频器输出功率_工业电气设计|变频器的输出功率该如何选择?
  3. 【转】[SharePoint 开发详解] 一个Feature中使用SPGridView的几个Tips
  4. 李洋疯狂C语言之求素数的方法
  5. 路由复用器--gorilla/mux
  6. C语言 VS输入输出字符设置
  7. mongoose数据查询or、and、where等用法
  8. Sublime Text3 注册码激活码
  9. 66. 编写高效的 JavaScript
  10. SpringBoot:java.lang.NullPointerException
  11. 蒙提霍尔问题(三门问题,概率论)C语言验证
  12. 前端性能优化 —— 起步篇(一)
  13. 台式计算机开机密码设置,设置台式电脑的开机锁屏密码的方法步骤
  14. Java sychronized关键字总结(一)
  15. python架构师是做什么的_架构师的工作都干些什么?!想做架构师必看!
  16. eps如何建立立体白模_EPS 三维测图系统(垂直摄影)快速入门手册.pdf
  17. 阿里云API调用 OCR python
  18. c语言例题18:完全平方数
  19. HTML5期末大作业:售票网站设计——票务网站整套模板(24个页面) HTML+CSS+JavaScript
  20. git生成公钥的步骤

热门文章

  1. 分类按照拼音第一字母排序显示实现
  2. jquery 抽离公共页面
  3. MIT6.824 Primary-Backup Replication论文导读
  4. 前麦弗逊独立悬架设计(设计说明书+CAD图纸+CATIA三维图)
  5. 第二章 C#+STM32实现设备远程管理与IAP—STM32的BootLoader
  6. java 大数据(多线程)和尚分馒头 整理
  7. idea不配置jdk也能运行_安装idea用配置jdk环境变量吗
  8. BCrypt算法的基础使用
  9. HEVC的Merge模式
  10. git安装教程(超详细,后附git命令大全)