利用C语言实现2048小游戏的方法_C 语言

准备工作

首先上一张图,因为这里只是在用C语言验证算法,所以没有对界面做很好的优化,丑是理所应当的。

了解了游戏的工作原理,实际上可以将游戏描述为四个带有方向的同一操作:

    1、将所有数字向一个方向移动至中间没有空位

    2、将相邻的两个相同的数字加和然后放在更靠近移动方向前部的一个位置上

另外需要判断一下玩家当前输入的内容是否可以执行,如果不可以执行等待用户下一条记录。

同时需要对游戏的进程进行控制,如果可以继续游戏,那么运行玩家继续输入下一条指令,而如果不可以进行,那么提示无法继续游戏的提示。

首先的问题就是光标键的输入。光标键属于功能键,使用常规的scanf当然是无法进行读取的,而使用更加接近硬件的getch()进行以字节为单位的标准输入。当使用getch()函数进行标准输入时,如果用户输入了一个功能键,例如光标键、Home、PgUp、PgDn、End之类的键,getch()将能够读取得到两个字符。当遇到功能键输入的时候,可以编写一个检测程序以获取对应按键的数据:

#include<stdio.h>
int main(){
 while(1){
  printf("%d\n",getch());
 }
}

随后运行这个数据提取程序,程序将按照一个字节一行,以整型的格式输出getch得到的数据。这里我查询到2048需要用到的四个按键↑↓←→对应的两个字节为:

按键 第一字节 第二字节
↑  224  72
224  80
224  75
→  224  77

然后就是游戏的主要的代码

#include<stdio.h>  //标准输入输出
#include<stdlib.h>  //基本工具函数
#define bool int  //C里边没有布尔类型,就自己造
#define true 1   //bool的两种值
#define false 0
int MAP[4][4]= {0};  //地图,默认0认为是空位
typedef enum {   //定义一个方向类型的枚举变量
 UNKNOW,
 UP,
 DOWN,
 LEFT,
 RIGHT
} Direction;

void printMap();  //绘制图形
Direction getNextDirection(); //从键盘读入下一个用户操作
bool canMove(Direction direction); //判断是否可以进行指定方向的操作
void doAction();   //游戏事件
void move(Direction direction);  //移动数字
void putNew();    //放入一个新的数字
int main() {    //主函数
 Direction nextStep;   //下一步
 int i,j;
 srand(time(0));
 putNew();    //游戏开始默认放两个数字
 putNew();
 printMap();    //打印格子
 while(1) {
  if(!canMove(UP)&&!canMove(LEFT)&&!canMove(DOWN)&&!canMove(RIGHT)) break; //任意方向都不能移动,那么终止游戏
  nextStep=getNextDirection();  //获取下一个用户操作
  if(nextStep==UNKNOW) continue;  //如果不知道用户按了个什么键或者用户胡乱按的,那么进入新的循环
  if(!canMove(nextStep)) continue; //如果下一步不可继续操作,进入新的循环
  system("cls");    //对于Windows来说,执行命令行命令cls清屏
  doAction(nextStep);   //执行操作
  putNew();    //放新的数字
  printMap();    //打印格子
 }
 printf("You Died!");   //提示游戏结束
 while(1);     //等待游戏结束
}

void printMap() {
 int i,j;
 printf("*-------*-------*-------*-------*\n");
 for(i=0; i<4; i++) {
  printf("|");
  for(j=0; j<4; j++) {
   MAP[i][j]?printf("%d",MAP[i][j]):printf(" ");
   printf("\t|");
   if(j>2)
    printf("\n");
  }
  printf("*-------*-------*-------*-------*\n");
 }
}
void doAction(Direction direction){
 int i,j,k;
 /**
  * 为了方便处理问题,将每个方向的运动操作简化为三步
  * 1.将数字归并到一个方向
  * 2.处理相同数字可消,并将消掉的数据定为0
  * 3.再次将数字归并到一个方向
  */
 //1.移动数字,取消数字之间的空位
 move(direction);
 //2.按照方向处理相同数字
 switch(direction){
 case UP:
 //按列枚举
  for(i=0;i<4;i++){
  //对于每一行的每一个元素
   for(j=0;j<3;j++){
  //如果元素非零,并且当前和下一个相同,当前的翻倍,下一个置零
    if(MAP[j][i]&&MAP[j][i]==MAP[j+1][i]){
     MAP[j][i]+=MAP[j+1][i];
     MAP[j+1][i]=0;
    }
   }
  }
  break;
 case LEFT://同上
  for(i=0;i<4;i++)
   for(j=0;j<3;j++)
    if(MAP[i][j]&&MAP[i][j]==MAP[i][j+1]){
     MAP[i][j]+=MAP[i][j+1];
     MAP[i][j+1]=0;
    }
  break;
 case DOWN://同上
  for(i=0;i<4;i++)
   for(j=3;j>0;j--)
    if(MAP[j][i]&&MAP[j][i]==MAP[j-1][i]){
     MAP[j][i]+=MAP[j-1][i];
     MAP[j-1][i]=0;
    }
  break;
 case RIGHT://同上
  for(i=0;i<4;i++)
   for(j=3;j>0;j--)
    if(MAP[i][j]&&MAP[i][j]==MAP[i][j-1]){
     MAP[i][j]+=MAP[i][j-1];
     MAP[i][j-1]=0;
    }
  break;
 }
 //3.移动数字,取消因为上一步置零过程中新产生的空位
 move(direction);
}
void move(Direction direction) { //移动数字
 int i,j,k;
 switch(direction) {
 case UP:
  //按列枚举
  for(i=0;i<4;i++)
  //对于每一行的每一个元素
   for(j=0;j<4;j++)
  //如果非零,那么应当取消当前位置,后边元素向前移动
    if(!MAP[j][i]){
     for(k=j;k<3;k++){
      MAP[k][i]=MAP[k+1][i];
     }
   //新产生的空位置零
     MAP[k][i]=0;
    }
  break;
 case LEFT://同上
  for(i=0;i<4;i++)
   for(j=0;j<4;j++)
    if(!MAP[i][j]){
     for(k=j;k<3;k++){
      MAP[i][k]=MAP[i][k+1];
     }
     MAP[i][k]=0;
    }
  break;
 case DOWN://同上
  for(i=0;i<4;i++)
   for(j=3;j>=0;j--)
    if(!MAP[j][i]){
     for(k=j;k>0;k--){
      MAP[k][i]=MAP[k-1][i];
     }
     MAP[k][i]=0;
    }
  break;
 case RIGHT://同上
  for(i=0;i<4;i++)
   for(j=3;j>=0;j--)
    if(!MAP[i][j]){
     for(k=j;k>0;k--){
      MAP[i][k]=MAP[i][k-1];
     }
     MAP[i][k]=0;
    }
  break;
 }
}
bool canMove(Direction direction) { //判断是否可以进行指定方向的操作
 int i,j;
 switch(direction) {
 case UP:
 //依次检查每一列
  for(i=0;i<4;i++){
  //首先排除在远端的一串空位,直接将j指向第一个非零元素
   for(j=3;j>=0;j--)
    if(MAP[j][i])
     break;
  //j>0代表这一列并非全部为0
   if(j>0)
  //依次检查每一个剩余元素,遇见空位直接返回true
    for(;j>=0;j--)
     if(!MAP[j][i])
      return true;
  //依次检查相邻的元素是否存在相同的非零数字
   for(j=3;j>0;j--)
    if(MAP[j][i]&&MAP[j][i]==MAP[j-1][i])
     return true;
  }
  break;
 case DOWN://同上
  for(i=0;i<4;i++){
   for(j=0;j<4;j++)
    if(MAP[j][i]) break;
   if(j<4)
    for(;j<4;j++)
     if(!MAP[j][i]) return true;
   for(j=0;j<3;j++)
    if(MAP[j][i]&&MAP[j][i]==MAP[j+1][i])
     return true;

  }
  break;
 case LEFT://同上
  for(i=0; i<4; i++){
   for(j=3;j>=0;j--)
    if(MAP[i][j])
     break;
   if(j>=0)
    for(;j>=0;j--)
     if(!MAP[i][j])
      return true;
   for(j=0;j<3;j++)
    if(MAP[i][j]&&MAP[i][j]==MAP[i][j+1])
     return true;
  }
  break;
 case RIGHT://同上
  for(i=0; i<4; i++){
   for(j=0;j<4;j++)
    if(MAP[i][j])
     break;
   if(j<4)
    for(;j<4;j++)
     if(!MAP[i][j])
      return true;
   for(j=0;j<3;j++){
    if(MAP[i][j]&&MAP[i][j]==MAP[i][j+1])
     return true;
   }
  }
  break;
 }
 //当允许条件都被检查过后,返回不可执行的结果
 return false;
}
Direction getNextDirection() {
 //第一个字节必须是224,否则判定输入的不是功能键
 if(getch()!=224) return UNKNOW;
 //根据第二字节对应出来用户的操作
 switch(getch()) {
 case 72:
  return UP;
 case 80:
  return DOWN;
 case 75:
  return LEFT;
 case 77:
  return RIGHT;
 default:
  return UNKNOW;
 }
}
void putNew(){
 //为了方便操作,临时存储一下所有空闲格子的指针,这样可以用一个线性的内存随机访问实现对所有空位中任一空位的随机访问.
 int* boxes[16]={NULL};
 //用来临时保存目标格子的地址
 int* target;
 //统计一共有多少个有效空格
 int count=0;
 int i,j;
 //统计空位,发现空位即保存地址并累加计数器
 for(i=0;i<4;i++)
  for(j=0;j<4;j++)
   if(!MAP[i][j]){
    boxes[count]=&MAP[i][j];
    count++;
   }
 if(count){
  //如果有空位,那么对这一位进行随机赋值操作,对于每一位可能性是相同的
  target=boxes[rand()%count];
  //50%可能出现2 50% 可能出现4
  *target=rand()%2?2:4;
 }
}

总结

以上就是这篇文章的全部内容了,小编认为像俄罗斯方块、2048这些稍微偏算法的小游戏是程序员必写的几个小程序。希望这篇文章对大家的学习或者工作能有所帮助,如果有疑问大家可以留言交流。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索2048游戏c语言代码
, c语言2048
c语言2048代码
c语言2048、c语言2048代码、2048游戏c语言代码、北理工c语言作业 2048、c语言2048思路,以便于您获取更多的相关知识。

时间: 2024-09-12 08:06:15

利用C语言实现2048小游戏的方法_C 语言的相关文章

用VC++6.0的控制台实现2048小游戏的程序_C 语言

首先感谢这位大侠的无私分享,仔细学习这个程序以后收获很多,试着添加一些注释 源程序是从开源中国看到的,原作者是 刘地(sir?) 地址为http://www.oschina.net/code/snippet_593413_46040 geek_monkey于2015年3月5日为拜读该程序,受益匪浅 为了方便自己,以及更多初学者阅读,我试着写了写了注释供参考 我是C语言初学者,如有错误希望指正.轻喷 复制代码 代码如下: #include <stdlib.h> #include <stdi

C语言实现的猜拳游戏代码分享_C 语言

这是一个简单的猜拳游戏(剪子包子锤),让你与电脑对决.你出的拳头由你自己决定,电脑则随机出拳,最后判断胜负. 下面的代码会实现一个猜拳游戏,让你与电脑对决.你出的拳头由你自己决定,电脑则随机出拳,最后判断胜负. 启动程序后,让用户出拳,截图: 用户出拳,显示对决结果:截图: 代码实现: #include <stdio.h> #include <stdlib.h> #include <time.h> int main() { char gamer; // 玩家出拳 int

C语言实现BMP转换JPG的方法_C 语言

本文实例讲述了C语言实现BMP转换JPG的方法.分享给大家供大家参考.具体实现方法如下: /**************************************************************************** 名称: jpeg.c 功能: linux下bmp转化为jpeg程序源代码 日期: 2010.01.26 注意: 编译时加"-ljpeg"(gcc -o bmp2jpg jpeg.c -ljpeg) ***********************

C语言打印华氏-摄氏温度对照表的方法_C 语言

本文实例讲述了C语言打印华氏-摄氏温度对照表的方法.分享给大家供大家参考.具体实现方法如下: /* * 打印华氏-摄氏温度对照表 */ #include <stdio.h> /* 温度上限 */ #define MIN 20.0 /* 温度下限 */ #define MAX 300.0 /* 步长 */ #define BC 20.0 main() { /* 定义温度及上下限步常变量 */ float oc,of=1.0; /* 打印标题 */ printf("华氏-摄氏温度对照表\

C语言实现字母大小写转换的方法_C 语言

本文实例讲述了C语言实现字母大小写转换的方法.分享给大家供大家参考.具体实现方法如下: /* * 将大写字母转换为小写字母 */ #include <stdio.h> int lower(int c) { return ((c>='A')&&(c<='z'))?(c+'a'-'A'):(c); } main() { int i; char a[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; for(i=0;i<26;i++)

使用C语言求N的阶乘的方法_C 语言

用递归法求N的阶乘 程序调用自身称为递归( recursion).它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解. 递归的能力在于用有限的语句来定义对象的无限集合. 一般来说,递归需要有边界条件.递归前进段和递归返回段.当边界条件不满足时,递归前进:当边界条件满足时,递归返回. #include <stdio.h> #include <string.h> #include <stdlib.h> long factorial(int n) {

C语言中基础小问题详细介绍_C 语言

1.printf格式输出函数 如果格式控制说明项数多于输出表列个数,则会输出错误数据:如果输出表列个数多于格式控制说明数,则多出数不被输出.%md,m指的是输出字段的宽度.如果输出字段位数小于m,则左端以空格补齐,若大于m,则按照实际位数输出.%-md,基本同上,只不过不同之处在于,空格在右端补齐printf参数可以是常量,变量或表达式,VC++ 6.0中采用从右向左顺序求值,从左向右输出如 复制代码 代码如下: int x = 5; printf("%4d%4d%4d", x, ++

用C语言求幂函数和指数函数的方法_C 语言

C语言pow()函数:求x的y次方(次幂)头文件: #include <math.h> pow() 函数用来求 x 的 y 次幂(次方),其原型为: double pow(double x, double y); pow()用来计算以x 为底的 y 次方值,然后将结果返回.设返回值为 ret,则 ret = xy. 可能导致错误的情况: 如果底数 x 为负数并且指数 y 不是整数,将会导致 domain error 错误. 如果底数 x 和指数 y 都是 0,可能会导致 domain erro

C语言求圆周率的简单实现方法_C 语言

本文实例讲述了C语言求圆周率的方法.分享给大家供大家参考,具体如下: #include <stdio.h> #include <math.h> void main() { int s; float n,t,pi; t=1,pi=0;n=1.0;s=1; while(fabs(t)>1e-6) { pi=pi+t; n=n+2; s=-s; t=s/n; } pi=pi*4; printf("pi=%10.6f/n",pi); } 此处得出的结果可精确到小数