C语言小游戏: 2048.c

概要:2048.c是一个C语言编写的2048游戏,本文将详细分析它的源码和实现。C语言是一种经典实用的编程语言,本身也不复杂,但是学会C语言和能够编写实用的程序还是有一道鸿沟的。本文试图通过一个例子展示如何用C语言实现一个简单但有用的程序。

一、程序简介

本文分析的代码是mevdschee在GitHub上的项目2048.c,游戏的规则和安装说明都可以到主页查看,本文不再赘述。顺便一提,这个程序虽然是纯C编写的,但是它适用于Linux终端,因此如果你想要看一下运行效果可能需要一个Linux.

2048.c源代码只有一个文件,也就是2048.c。它支持图形和色彩,右上角显示分数,下面是操作说明。界面整体看起来挺简洁美观,我们一会看一下它是怎么做到的。

二、代码结构

我们先看一下程序所包含的函数,大体了解它的结构和功能。

程序入口和测试:

  • main (argc,argv[])
  • test ()

绘制界面相关:

  • getColor (value,color,length)
  • drawBoard (board[][])
  • setBufferedInput (enable):设置终端的行为
  • signal_callback_handler (signum)

游戏逻辑:

  • findTarget (array[],x,stop)
  • slideArray (array[])
  • rotateBoard (board[][])
  • moveUp (board[][])
  • moveLeft (board[][])
  • moveDown (board[][])
  • moveRight (board[][])
  • findPairDown (board[][])
  • countEmpty (board[][])
  • gameEnded (board[][])
  • addRandom (board[][])
  • initBoard (board[][])

从函数的参数中可以看出,游戏使用的主要的数据结构是一个二维数组,在主函数中定义: uint8_t board[SIZE][SIZE] 。SIZE的值默认是4,这是2048游戏面板的一般大小,下文直接称为4。数组中的元素保存的是指数,例如如果显示的数是1024,那么存储的应该是10。在初始化过程中,该数组被填满0.

主函数中完成一些初始化和设置工作,然后进入主循环。在循环中接受用户的键盘输入,然后调用相应的函数。

三、图形绘制函数

 1 void drawBoard(uint8_t board[SIZE][SIZE]) {
 2     uint8_t x,y;
 3     char color[40], reset[] = "\033[m";
 4     printf("\033[H");
 5
 6     printf("2048.c %17d pts\n\n",score);
 7
 8     for (y=0;y<SIZE;y++) {
 9         for (x=0;x<SIZE;x++) {
10             getColor(board[x][y],color,40);
11             printf("%s",color);
12             printf("       ");
13             printf("%s",reset);
14         }
15         printf("\n");
16         for (x=0;x<SIZE;x++) {
17             getColor(board[x][y],color,40);
18             printf("%s",color);
19             if (board[x][y]!=0) {
20                 char s[8];
21                 snprintf(s,8,"%u",(uint32_t)1<<board[x][y]);
22                 uint8_t t = 7-strlen(s);
23                 printf("%*s%s%*s",t-t/2,"",s,t/2,"");
24             } else {
25                 printf("   ·   ");
26             }
27             printf("%s",reset);
28         }
29         printf("\n");
30         for (x=0;x<SIZE;x++) {
31             getColor(board[x][y],color,40);
32             printf("%s",color);
33             printf("       ");
34             printf("%s",reset);
35         }
36         printf("\n");
37     }
38     printf("\n");
39     printf("        ←,↑,→,↓ or q        \n");
40     printf("\033[A"); // one line up
41 }

在drawBoard函数中我们看到绘制的实现过程。函数的主体是一个for循环,每循环一次画一行,这里指的是Board中的一行。循环体中有3个小for循环,每个循环画出终端中的一行,也就是说Board的一行是终端的3行。每个格子的尺寸是3行7列,最中间的位置是数字,如果没有数字则输出一个点。其他区域则用空格填充。

细心的朋友可能已经发现,外循环的变量是y,内循环的变量为x,这样一来board[0][0]到board[3][0]表示的是第1行,board[0][1]到board[3][1]表示第2行,这种对应关系需要特别注意。

"\033m"之类的符号用于控制终端的颜色和其他一些行为。下面给出本程序中出现的用法,更多控制序列的用法可以参考这个网页。通过输出带颜色的空格和字符,2048.c在终端中实现了类似图形界面的效果。

\33[0m 关闭所有属性 
\33[30m -- \33[37m 设置前景色 
\33[40m -- \33[47m 设置背景色 
\33[nA 光标上移n行 
\33[nB 光标下移n行 
\33[nC 光标右移n行 
\33[nD 光标左移n行 
\33[y;xH设置光标位置 
\33[2J 清屏 
\33[?25l 隐藏光标 
\33[?25h 显示光标

四、游戏逻辑

我们现在已经知道游戏的主要数据结构,以及如何将它显示在屏幕上,我们接下来要关注游戏罗杰是怎么实现的。2048游戏本身非常简单,其实我们只想关心划的那一下是怎么实现的。我们已经看到2048.c实现了moveUp、moveLeft、moveDown、moveRight四个函数,表示4个划的方向。

moveUp函数看起来也非常简单,它仅仅调用4次slideArray函数。还记得刚刚说过的二维数组和盘面的对应规则吗,矩阵的每一行代表的是盘面的一列,因此每次滑动一个一维数组,实际上滑动的是一列。slideArray函数负责将数组从高index到低index滑动,对应在屏幕上,也就是向上滑动了。

1 bool moveUp(uint8_t board[SIZE][SIZE]) {
2     bool success = false;
3     uint8_t x;
4     for (x=0;x<SIZE;x++) {
5         success |= slideArray(board[x]);
6     }
7     return success;
8 }

slideArray函数和它的辅助函数findTarget任务已经比较简单明了,就不需要详细说了。需要注意的就是在滑的时候合并的块不能第二次合并了,例如2 2 2 2一次合并的结果是4 4,而不会是8.

其他几个函数实现比较巧妙,作者先把盘面进行旋转,然后再调用这个moveUp函数实现。作者通过rotateBoard函数把这个4x4的矩阵旋转90度。数组的下标可以通过建立坐标系得到。

 1 void rotateBoard(uint8_t board[SIZE][SIZE]) {
 2     uint8_t i,j,n=SIZE;
 3     uint8_t tmp;
 4     for (i=0; i<n/2; i++) {
 5         for (j=i; j<n-i-1; j++) {
 6             tmp = board[i][j];
 7             board[i][j] = board[j][n-i-1];
 8             board[j][n-i-1] = board[n-i-1][n-j-1];
 9             board[n-i-1][n-j-1] = board[n-j-1][i];
10             board[n-j-1][i] = tmp;
11         }
12     }
13 }

了解了这些信息,再看其他的函数比如countEmpty、addRandom等就非常简单了,大家直接去看代码就可以了。

五、总结

2048.c这个小游戏虽然只有400多行,但复现了2048游戏的精髓。而且程序以纯C语言实现,没有使用ncurses之类的第三方库,得到了很不错的效果。实现的过程也有一些精巧的地方,例如如何把问题化繁为简的,如何避免多次编写move函数。其实2048.c不仅可以拿来阅读,无聊的时候玩一局也是相当不错的。

原文地址:https://www.cnblogs.com/cocode/p/10268623.html

时间: 2024-08-07 15:50:26

C语言小游戏: 2048.c的相关文章

C语言小游戏设计报告

课程设计名称:贪吃蛇小游戏 专业班级:计科15-2 学号:150809229 姓名:XXX 一.设计目标 通过设计,培养学生对电脑的动手能力,使学生巩固<C语言程序设计>课程学习的内容,掌握编写程序的基本方法,强化对其的动手能力,可以独自完成程序的编写. 二.设计内容和要求 设计内容 编写贪吃蛇的小游戏,使其可以成功运行并且操作玩耍. 设计要求 1)源程序要有适当的注释,使程序便于阅读. 2)要有程序运行结果作为依据 三.程序流程 1.编写地图 运用函数,数组编写地图 2.相同的方法把蛇添加进

【C语言探索之旅】 第一部分第八课:第一个C语言小游戏

? 内容简介 1.课程大纲 2.第一部分第八课:第一个C语言小游戏 3.第一部分第九课预告: 函数 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏. C语言编程基础知识 什么是编程? 工欲善其事,必先利其器 你的第一个程序 变量的世界 运算那点事 条件表达式 循环语句 实战:第一个C语言小游戏 函数 练习题 习作:完善第一个C语言小游戏 C语言高级技术 模块化编程 进击的指针,C语言王牌 数组 字符串 预处理 创建你自己的变量类型 文

[小游戏]2048

益智小游戏2048    玩法:    该游戏使用方向键让方块上下左右移动.如果两个带有相同数字的方块在移动中碰撞,则它们会合并为一个方块,且所带数字变为两者之和.每次移动时,会有一个值为2或者4的新方块出现.    可能不好理解,你玩几下就知道了.    这款游戏玩起来会让你”根本停不下来“,很有意思的.通关截图: 游戏官网:http://gabrielecirulli.github.io/2048/ date:2014-10-26

C语言 小游戏之贪吃蛇

还记得非常久曾经听群里人说做贪吃蛇什么的,那时候大一刚学了C语言,认为非常难,根本没什么思路. 前不久群里有些人又在谈论C语言贪吃蛇的事了,看着他们在做,我也打算做一个出来. 如今大三,经过了这一年半的编程,如今认为这个C语言的贪吃蛇还是比較简单的,花的时间不非常多! 我认为主要是思路正确,基本上就米什么大的问题. 如今贴上我的代码和我的详解,希望大家多交流. 首先说下我这个贪吃蛇仅仅是一个简单的,游戏结束有2种可能:一碰墙,二自杀即蛇头碰到蛇身. 如有不好之处,请见谅把. 首先说下我这个贪吃蛇

C语言小游戏开发之贪吃蛇

寒假期间一时兴起,想着用C语言能开发出贪吃蛇小游戏应该是一件不错的事!但C语言学习过程中从来都是字符界面的编程,如何能有"图形化"的效果呢?于是小编就在度娘, 谷歌等网站搜索了一番,发现了一些有用的Win32 API函数,于是小编的心一下子激动了起来,有了这些API函数也许能够实现哟!开始吧! 编程之前小编的构思是这样的,贪吃蛇小游戏应该实现的有: 1.贪吃蛇在不进行控制的条件下应该能够自主前进. 2.玩家可以通过WASD键来控制贪吃蛇的前进方向. 3.运行过程中若贪吃蛇撞击到墙壁或自

结对编程小游戏2048

作业要求: 自选题目(不少于500行代码),进行结对编程 轮流担任领航员和驾驶员 记录结对编程的过程,写成结对博客 1.结对题目,写清需求 2.上传代码(截图),两人合作的合影 3.约定的规范 4.记录时间 5.心得和体会 Deadline 9月18日 23:59:59 小组成员 019任帅昌 020禹继跃 1.结对题目:2048小游戏 需求分析:在人们学习工作之余,小游戏成为了人们打发时间做的必不可少的事情了,而2048这款小游戏它不仅能在你工作学习疲惫之后使你身心放松,还能益智 2.游戏代码

JavaScript小游戏--2048(PC端)

1.初始化棋局 $(document).ready(function() { prepare_for_mobile(); //适配移动端 new_game(); }); 2.开始新游戏 function new_game() { back = []; //初始化棋盘 init(); //在随机两个格子生成数字 generate_one_number(); generate_one_number(); } 3.初始化 function init() { for (var i = 0; i < 4;

【C语言小游戏】 中国象棋

人人对战 [email protected]:~$ cat main.c  //  main.c //  象棋 //  車马相仕帅仕相马車 //  十十十十十十十十十 //  十炮十十十十十炮十 //  兵十兵十兵十兵十兵 //  十十十十十十十十十 //  --楚河-汉界-- //  十十十十十十十十十 //  卒十卒十卒十卒十卒 //  十炮十十十十十炮十 //  十十十十十十十十十 //  車马象士将士象马車 // #include <stdio.h> #include <stdb

JavaScript小游戏--2048(移动端)

HTML5中新添加了很多事件,但是由于他们的兼容问题不是很理想,应用实战性不是太强,所以在这里基本省略,咱们只分享应用广泛兼容不错的事件,日后随着兼容情况提升以后再陆续添加分享.今天为大家介绍的事件主要是触摸事件:touchstart.touchmove和touchend. 一开始触摸事件touchstart.touchmove和touchend是iOS版Safari浏览器为了向开发人员传达一些信息新添加的事件.因为iOs设备既没有鼠标也没有键盘,所以在为移动Safari浏览器开发交互性网页的时