2048

  2048这款游戏的玩法很简单,每次可以选择上下左右滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢,系统也会在空白的地方乱数出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。不断的叠加最终拼凑出2048这个数字就算成功。

这款游戏对于整天和二进制打交道的程序猿们来说简直就是量身定做的,当然作为一个程序猿怎么可能随随便便就去玩别人的游戏,我们程序猿不要面子啊,说干就干,撸起袖子就干,分分钟撸他个游戏出来。

其实完成这个游戏并没有多么难,利用简单的二位数组和一些简单的循环和判断就能做到,对于像我这样的编程菜鸟来说是再适合不过了。

以下只是提供一种思路,能力一般,水平有限,仅供参考,注释全部代码如下:

#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h> //设置颜色宏,可能用到的颜色,用于printf()输出时的颜色设置
//格式为printf(颜色A"输出的内容"颜色B);
//表示输出的该段颜色为A色,下一段为B色,一般B用"\033[m"表示默认的黑色
#define NONE "\033[m"
#define RED "\033[0;32;31m"
#define LIGHT_RED "\033[1;31m"
#define GREEN "\033[0;32;32m"
#define LIGHT_GREEN "\033[1;32m"
#define BLUE "\033[0;32;34m"
#define LIGHT_BLUE "\033[1;34m"
#define DARY_GRAY "\033[1;30m"
#define CYAN "\033[0;36m"
#define LIGHT_CYAN "\033[1;36m"
#define PURPLE "\033[0;35m"
#define LIGHT_PURPLE "\033[1;35m"
#define BROWN "\033[0;33m"
#define YELLOW "\033[1;33m"
#define LIGHT_GRAY "\033[0;37m"
#define WHITE "\033[1;37m" /*
** //操作
** // 1 上 72
** // 2 下 80
** // 3 左 75
** // 4 右 77
**
**函数
**void Arr(int p[][SIZE]); //初始化数组为为 SIZE 个随机值二位数组
**void SetArr(int p[][SIZE]); //每次移动后调用,使得二维数组随机出现一个2或SIZE
**
**int Up(int p[][SIZE]); //向上移动, 返回1表示移动成功,返回0表示移动失败
**int Down(int p[][SIZE]); //向下移动, 返回1表示移动成功,返回0表示移动失败
**int Left(int p[][SIZE]); //向左移动, 返回1表示移动成功,返回0表示移动失败
**int Right(int p[][SIZE]); //向右移动, 返回1表示移动成功,返回0表示移动失败
**
**int Count(int p[][SIZE]); //记录当前总分,返回分数
**int Full(int p[][SIZE]); //判断数组是否满, 返回1表示数组未满,返回1表示数组已满
**void Play(int p[][SIZE]); //开始游戏,该函数调用了"移动函数""判断结束函数"等多个函数
**
**void Show(int p[][SIZE],int flg=1); //输出游戏界面
**void Table_up(int size); //游戏界面上边框
**void Table_down(int size); //游戏界面下边框
**
**思路:
**1、构建二位数组初始化为0,利用随机数函数随机赋值
**2、捕捉键盘上的方向键,用来触发移动数组的函数
**3、构建移动数组的函数,分两部,第1步求该移动方向上相邻相等的数,合并为一个数
** 第2步进行数组移动,把该(列)上第一个不为0的数移至最前,第二个不为0的数移至……
**4、设计函数判断游戏结束标志,结束时应该为没有剩余空格,不能进行任何方向上的移动
**5、设计输出函数,输出游戏界面,并能时事的展示当前游戏状态
**6、设计函数,利用循环实现连续操作,并调用以上函数实现游戏的进行与结束
**7、调用主函数实现上述功能
**
*/ #define SIZE 4 //定义宏,确定游戏中数组的大小 void Arr(int p[][SIZE]) //初始数组随机产生SIZE个数字
{
srand((unsigned int)time(NULL));//随机种子
int i=SIZE;//初始化有SIZE个值
while(i--)
{
int index_row=rand()%SIZE;
int index_col=rand()%SIZE;
int num=(rand()%2+1)*2; //随机2或4
p[index_row][index_col]= num;
} } void SetArr(int p[SIZE][SIZE])//随机一个数字插入数组
{
srand((unsigned int)time(NULL));
while(1)
{
int index_row=rand()%SIZE;
int index_col=rand()%SIZE;
if(p[index_row][index_col] != 0) continue;
int num=(rand()%2+1)*2; //随机2或4
p[index_row][index_col]= num;
break;
}
} int Up(int p[][SIZE]) //向上移动
{
int flg=0; //标记,若函数退出时标记没变,则表示无法移动
for(int k=0; k<SIZE; k++)
{
for(int i=0; i<SIZE-1; i++)
{
if(p[i][k]==0) continue;
//向上合并
for(int j=i+1; j<SIZE; j++)
{
if(p[j][k]!=0) //不为0的数
{
if(p[j][k]==p[i][k]) //若有相邻相等的数,移动至当前位置加倍
{
p[i][k]*=2;
p[j][k]=0;
flg=1;
}
break;
} } } //向上移动
for(int i=0; i<SIZE; i++)
{
if(p[i][k]==0) continue; for(int j=0; j<i; j++)
{
if(p[j][k]==0)
{
p[j][k]=p[i][k];
p[i][k]=0;
flg=1;
break;
} } } }
if(flg==1) SetArr(p);
return flg;
} int Down(int p[][SIZE]) //向下移动
{
int flg=0; //标记是否移动成功
for(int k=0; k<SIZE; k++)
{
for(int i=SIZE-1; i>0; i--)
{
if(p[i][k]==0) continue;
//向下合并
for(int j=i-1; j>=0; j--)
{
if(p[j][k]!=0) //不为0的数
{
if(p[j][k]==p[i][k]) //若有相邻相等的数,移动至当前位置加倍
{
p[i][k]*=2;
p[j][k]=0;
flg=1;
}
break;
} } } //向下移动
for(int i=SIZE-1; i>=0; i--)
{
if(p[i][k]==0) continue; //查找该列上的数字 for(int j=SIZE-1; j>i; j--) //移动该数字
{
if(p[j][k]==0)
{
p[j][k]=p[i][k];
p[i][k]=0;
flg=1;
break;
} } } }
if(flg==1) SetArr(p); //移动成功,插入新元素
return flg;
} int Left(int p[][SIZE]) //向左移动
{
int flg=0; //标记是否移动成功
for(int k=0; k<SIZE; k++)
{
for(int i=0; i<SIZE-1; i++)
{
if(p[k][i]==0) continue;
//向左合并
for(int j=i+1; j<SIZE; j++)
{
if(p[k][j]!=0) //除过p[k][i]外不为0的数
{
if(p[k][j]==p[k][i]) //若有相邻相等的数,移动至当前位置加倍
{
p[k][i]*=2;
p[k][j]=0;
flg=1;
}
break;
} } } //向左移动
for(int i=0; i<SIZE; i++)
{
if(p[k][i]==0) continue; //查找该列上的数字 for(int j=0; j<i; j++) //移动该数字
{
if(p[k][j]==0)
{
p[k][j]=p[k][i];
p[k][i]=0;
flg=1;
break;
} } } }
if(flg==1) SetArr(p); //移动成功,插入新元素
return flg;
} int Right(int p[SIZE][SIZE])
{
int flg=0; //标记是否移动成功
for(int k=0; k<SIZE; k++) //K表示该行
{
for(int i=SIZE-1; i>0; i--) //i表示列
{
if(p[k][i]==0) continue;
//向右合并
for(int j=i-1; j>=0; j--)
{
if(p[k][j]!=0) //不为0的数
{
if(p[k][j]==p[k][i]) //若有相邻相等的数,移动至当前位置加倍
{
p[k][i]*=2;
p[k][j]=0;
flg=1;
}
break;
} } } //向右移动
for(int i=SIZE-1; i>=0; i--)
{
if(p[k][i]==0) continue; //查找该列上不为0数字 for(int j=SIZE-1; j>i; j--) //移动该数字
{
if(p[k][j]==0)
{
p[k][j]=p[k][i];
p[k][i]=0;
flg=1;
break;
} } } }
if(flg==1) SetArr(p); //移动成功,插入新元素
return flg;
} int Count(int p[][SIZE])//计算总分
{
int count = 0;
for(int i=0; i<SIZE; i++)
{
for(int j=0; j<SIZE; j++)
{
count += p[i][j];
}
}
return count;
} int Full(int p[][SIZE]) //监视数组是否满了
{
int flg=0; //标记,如果数组全部有值,则返回0值的flg,表示数组满了
for(int i=0; i<SIZE; i++)
{
for(int j=0; j<SIZE; j++)
{
if(p[i][j]==0)
{
flg=1;
return flg;
} }
}
return flg; //如果flg=0.数组满了
} void Table_up(int size)//上表格
{
printf("\t┌──");
for(int k=0; k<SIZE-1; k++)
{
printf("──┬──");
}
printf("──┐\n");
}
void Table_down(int size)//下表格
{
printf("\n\t└──");
for(int k=0; k<SIZE-1; k++)
{
printf("──┴──");
}
printf("──┘\n");
} void Show(int p[][SIZE],int flg=1)//输出数组,每次调用清屏
{
int count=0;//计数
system("cls"); //清屏效果
//system("color f9");
printf("\t方向↑↓←→移动,Esc退出\n");
Table_up(SIZE); //调用上表格函数
for(int i=0; i<SIZE; i++) //输出游戏中的数组的值
{
printf("\t┊"); //分割线
for(int j=0; j<SIZE; j++)
{
if(p[i][j]==0)
{
printf(LIGHT_PURPLE" "NONE,p[i][j]);//把0值输出为空白
}
else
printf(LIGHT_PURPLE"%4d"NONE,p[i][j]); //设置颜色
printf("┊"); //分割线 }
Table_down(SIZE); //下表格 }
count=Count(p); //调用计数函数计算总分
printf(BROWN"\t本局总分%d\n"NONE,count); if(flg==0) //移动失败,该方向不可移动
{
printf(RED"\t无法移动,请重更换方向\n"NONE);
} //判断结束标志
if(Full(p)==0 && Up(p)==0 && Down(p)==0 && Left(p)==0 && Right(p)==0)//方格满了&&不能移动
{
printf("----------------游戏结束------------\n");
printf("-----------双击键盘退出游戏-----------\n");
_getch();
_getch();
exit(0);
} } void Play(int p[][SIZE])
{
char tmp; //接受_getch()的第一个返回值
char ch; //接受键盘键入的值
int flg; //标记移动函数是否成功调用
while((tmp=_getch())!=27) //Esc退出 //ch == 0x1B
{
ch=_getch(); //读取功能键时有两个返回值,第二个为真实值
//if(tmp==0 || tmp==0xe0) continue;//非方向键重新录入//注:若tmp为char类型则 0xe0 银对应变成 -32
if(ch==75)
flg=Left(p); //左移
else if(ch==77)
flg=Right(p); //右移
else if(ch==72)
flg=Up(p); //上移
else if(ch==80)
flg=Down(p); //下移
else //键入了非方向键
{
printf(RED"无效输入(可能输入了非方向键),请按回车继续\n"NONE);
continue;
} Show(p,flg); //输出当前游戏状态
}
} int main()
{
//默认SIZE大小为4,可更改SIZE大小改变数组大小 int array[SIZE][SIZE] = {0};//构建数组,初始化为"空白" Arr(array);//初始化内容,随机值 Show(array);//游戏开始界面 Play(array);//开始游戏,该函数调用了"移动函数""判断结束函数"等多个函数 return 0;
}

输出展示:


开始界面

此时不能向下,向右移动,程序给出警告

游戏结束时的界面

以上为该程序的界面展示,另外如果不小输入了非方向键字符,程序会给出提示:

无效输入(可能输入了非方向键),请按回车继续

 只需按下回车即可继续游戏。

C语言小游戏——2048的更多相关文章

  1. C语言小游戏: 2048.c

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

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

    ​ 内容简介 1.课程大纲 2.第一部分第八课:第一个C语言小游戏 3.第一部分第九课预告: 函数 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写 ...

  3. 012-C语言小游戏之推箱子

    012-C语言小游戏之推箱子 一.创建游戏地图   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #define ROWS 11 #define COLS 12   char ...

  4. c语言----<项目>_小游戏<2048>

    2048 小游戏 主要是针对逻辑思维的一个训练. 主要学习方面:1.随机数产生的概率.2.行与列在进行移动的时候几种情况.3.MessageBox的使用 #include <iostream&g ...

  5. c语言小游戏-扫雷的完成

    C语言-扫雷游戏 本文将对此游戏做一个大致的概述,此代码适合初学者,编写软件使用了vs2017. 该代码可以实现如下功能: 1.用户可以选择3个难度,分别布置不同个数的雷. 2.随机数设置雷的位置. ...

  6. C语言小游戏: 推箱子 支线(一)--1

    好家伙,考完试了 回顾一下2021 回顾一下某次的作业 妙啊 所以, 做一个推箱子小游戏 1.先去4399找一下关卡灵感 就它了 2.在百度上搜几篇推箱子, 参考其中的"■ ☆"图 ...

  7. JavaScript小游戏--2048(PC端)

    1.初始化棋局 $(document).ready(function() { prepare_for_mobile(); //适配移动端 new_game(); }); 2.开始新游戏 functio ...

  8. C语言 小游戏之贪吃蛇

    还记得非常久曾经听群里人说做贪吃蛇什么的,那时候大一刚学了C语言,认为非常难,根本没什么思路. 前不久群里有些人又在谈论C语言贪吃蛇的事了,看着他们在做,我也打算做一个出来. 如今大三,经过了这一年半 ...

  9. C语言小游戏:贪吃蛇

    #include <graphics.h> #include <conio.h> #include <stdio.h> #define WIDTH 40 //设置宽 ...

随机推荐

  1. 洛谷训练P1008(循环+暴力)

    1 #include<stdio.h> 2 #include<string.h> 3 int a[10]; 4 int main(){ 5 for (int x=123;x&l ...

  2. MySQL函数及存储过程

    MySQL函数及存储过程 参考文章:https://www.cnblogs.com/wupeiqi/articles/5713323.html 1.函数 1.1内置函数 官方文档:https://de ...

  3. Spring入门一:IOC、DI、AOP基本思想

    Spring框架是一个集众多涉及模式于一身的开源的.轻量级的项目管理框架,致力于javaee轻量级解决方案.相对于原来学过的框架而言,spring框架和之前学习的struts2.mybatis框架有了 ...

  4. (八)使用 jmh 压测 Dubbo

    1.JMH简介 JMH即Java Microbenchmark Harness,是Java用来做基准测试的一个工具,该工具由OpenJDK提供并维护,测试结果可信度高. 相对于 Jmeter.ab , ...

  5. CSS简介,基础选择器,字体属性,文本属性

    欢迎大家去博客冰山一树Sankey,浏览效果更好.直接右上角搜索该标题即可 博客园主页:博客园主页-冰山一树Sankey CSDN主页:CSDN主页-冰山一树Sankey 前端学习:学习地址:黑马程序 ...

  6. Solon 1.6.30 发布,更现代感的应用开发框架

    相对于 Spring Boot 和 Spring Cloud 的项目 启动快 5 - 10 倍 qps 高 2- 3 倍 运行时内存节省 1/3 ~ 1/2 打包可以缩小到 1/2 ~ 1/10(比如 ...

  7. MariaDB 与Mysql版本对应关系

    特定MariaDB版本的完全兼容性 就InnoDB而言,MariaDB 10.2.MariaDB 10.3和MariaDB 10.4是MySQL 5.7的有限替代.然而,在每一个新的MariaDB版本 ...

  8. egg-multipart + el-upload 实现带参图片上传至阿里云OSS

    egg-multipart有两种模式:file和stream el-upload参数传递有两种方式:利用自带参数data和手动添加参数 egg-multipart介绍 一.file 模式下的带参传递 ...

  9. 浏览器中 Http缓存

    分类: web缓存主要有:数据库缓存.服务器缓存(代理服务器缓存.CDN缓存),浏览器缓存. 数据库缓存 当web应用的关系比较复杂,数据库中的表很多的时候,如果频繁进行数据库查询,很容易导致数据库不 ...

  10. numpy: np.logical_and/or/not (逻辑与/或/非)+python3-曲线拟合(polyfit/polyval)

    可以用拟合两个变量之间的关系,然后根据一个变量,去推测出另外一个变量的推测值