Linux C语言编写2048小游戏

2048

Linux C语言编写2048小游戏_第1张图片

2048小游戏是用Linux C语言写的,运行在Ubuntu系统上,其中Ubuntu链接Ncuses库。首先,我们简单了解一下Ncurses。 Ncurses库是由原CURSES库发展而来的,这个库提供了C/C++对屏幕以及光标、鼠标访问的特性。使得C/C++简易写屏成为可能。

1.1常用函数的介绍

如果要调用NCURSES库中的函数,你必须在代码中加载ncurses.h文件,就是在C或C++程序中添加#include 这一行。
例如: Hello World程序
#include
int main()
{
initscr(); //初始化,进入curses模式 ,用来清除屏幕("stdscr"窗口)上所有的字符,使屏幕变为空白,等待下一步处理
printw(“Hello World”); //在虚拟屏幕上打印Hello World 输出到”stdscr"的虚拟坐标(0,0)上
refresh(); //将虚拟屏幕上的内容写到显示器上,并刷新 (将缓冲区的内容输出到 屏幕上)printw+refresh()可以不断在虚拟屏幕上写入数据,而调用refresh()函数时让一切看起来似乎时一次完成的。因为refresh()函数至核查窗口和数据中变动的部分。
getch(); //等待用户输入
endwin(); //退出NCURSES模式 释放了curses子系统和相关数据结构的内存,才回到普通字符行模式,否则,结束后终端可能运转得不正常 如果你的程序不能正常地显示东西了,看看initscr()函数和endwin()函数是不是在不该被调用的地方调用了
}

1.2 游戏代码

1.2.1 input.h

#ifdef   __INPUT_H
#define  __INPUT_H

#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4

#define FIRST 10
#define NEXT  11
#define THEN 12
#define LAST 13

#define QUIT 100
#define UNKNOW 250

int get_user_input(void);

#endif

1.2.2 input.c

#include 
#include "input.h"

extern WINDOW *w_2048;  //声明一个外部变量,表示这个变量是其他文件(2048.c)中定义的   
int get_user_input(void)
{
	keypad(w_2048,TRUE);
	int ch=wgetch(w_2048);
 	keypad(w_2048,FALSE);
	
	if(ch=='q'||ch=='Q')
	 {
	 	 return QUIT;
	 }
	else if(ch=='a'||ch==KEY_LEFT)
	 {
 		 return LEFT;
	 }
	 else if(ch=='d'||ch==KEY_RIGHT)
	 {
 		 return RIGHT;
	 }
	 else if(ch=='s'||ch==KEY_DOWN)
 	{
  		return DOWN;
 
	 }
	 else if(ch=='w'||ch==KEY_UP)
	 {
		return UP;
	}
	else if(ch=='1')
	{
		return FIRST;
	}
	else if(ch=='2')
	{
		return NEXT;
	
	}
	else if(ch=='3')
	{
		return THEN;
	}
	else if(ch=='4')
	{
		return LAST;
	}
	else
	{
		return UNKNOW;
	}
	

}

相关函数解释:
1.keypad()函数
这个函数允许使用功能键:F1,F2,方向键等。使用keypad(stdscr,TURE)就是显示设备 (stdscr)上使用这些功能。keypad(stdscr,FALSE);就是显示设备(stdscr)关闭这些功能。
2.wgetch()函数
wgetch(*WINDOWS)
这个函数从指定的窗口接收字符

1.2.3 screen.h代码

#define __SCREEN_H
#define __SCREEN_H

//打开字符屏幕
void open_screen(void);

//关闭字符屏幕
void close_screen(void);

1.2.4 screen.c代码

#include 
//打开字符屏幕
void open_screen(void)
{
	initscr();
	cbreak();
	noecho();
	keypad(stdscr,TRUE);
	
}

//关闭字符屏幕
void close_screen(void)
{
	endwin();
}

相关代码解释:
1. initscr()函数
初始化,进入curses模式 ,用来清除屏幕("stdscr"窗口)上所有的字符,使屏幕变为空白,等待下一步处理
2. cbreak()函数
通常情况下,用户输入的字符将被终端程序送入终端的缓冲区。但当用户有输入换行符时,终端程序将会终端,同时输出当前的缓冲区内容并启用新行的输出缓冲。后面的2048.c代码中, game_is_over()函数 直接改成printf(“game over”) ;程序结束后,会在终端输出game over。但是改成printf(“game over\n”),会显示在屏幕上。但是大多数需要用户输入单个字符并能显示在屏幕上。
cbreak()用来禁用行缓冲,这个函数所初始化的模式可以用来给程序传送控制字符,比如:挂起,中断或退出。这些控制字符被认为是终端驱动程序中的控制字符,因而将这些这符传给终端程序。
3.noecho()函数
这个函数控制用户输入的键盘回显。 noecho()函数可以不让控制字符出现在屏幕上。

1.2.5 main.c代码

#include 
#include 
#include 
#include "screen.h"
#include "time.h"

int main()
{	//设置随机数zhongz
	srandom(time(NULL));	

	//创建(初始化)我们的字符窗口屏幕
	open_screen();

	//进入2048的主循环
	game_2048();	

	//关闭字符屏幕
	close_screnen();
	return 0;
}

1.2.6 2048.h代码

#ifndef __2048_H__
#define __2048_H__

void game_2048(void);

#endif

1.2.7 2048.c 代码

#include 
#include 
#include 
#include "input.h"
#include 

//提示窗口相关参数
WINDOW *wel=NULL;
int wel_lines=2;      //提示窗口的行数
int wel_columns=40;   //提示窗口的列数
int wel_y0=0;         //提示窗口左上顶点的y坐标
int wel_x0=20;        //提示窗口右上顶点的x坐标

//游戏数字窗口
WINDOW *w_2048=NULL;
int w_2048_lines=4;
int w_2048_coluwns=24;
int w_2048_y0=3;
int w_2048_x0=20;

//得分窗口
WINDOW *w_score=NULL;
int w_score_lines=2;
int w_score_coluwns=24;
int w_score_y0=10;
int w_score_x0=20;

//结束窗口
WINDOW *w_over=NULL;
int w_over_lines=4;
int w_over_coluwns=24;
int w_over_y0=14;
int w_over_x0=20;

#define ITEM_NUM 4

int matrix_2048[ITEM_NUM][ITEM_NUM]=
{
 0,0,0,0,
 0,0,0,0,
 0,0,0,0,
 0,0,0,0,
};

//删除行
void Del(int num)
{
  int i; 
  for(i=0;i<ITEM_NUM;i++)
  {
  if(matrix_2048[num][i]!=0)
   matrix_2048[num][i]=0;
   
  }
}

//获取0的个数
int get_zero_num()
{
 int i,j;
 int n=0;//计数
 for(i=0;i<ITEM_NUM;i++)
 {
  for(j=0;j<ITEM_NUM;j++)
  {
   if(matrix_2048[i][j]==0)
    n++;
  }
 }
 return n;
}

//在空白位置上随机填充一个数字
void fill_a_number(void)
{
 int zero_num=get_zero_num();
 if(zero_num==0)
 {
   return;
 }
 int pos=random()%zero_num+1;  //范围是【1~zero_num】
 int n=0;//第几个0
 int i,j; 
 for(i=0;i<ITEM_NUM;i++)
 {
    for(j=0;j<ITEM_NJM;j++)
    {
    	if(matrix_2048[i][j]==0)
    	{
    		n++;
    		if(n==pos)
    		{
			//要填充的位置找到了
			int a[4]={2,2,4,8};
			int index=random()%4;
			matrix_2048[i][j]=a[index];
			return ;
		}
	   }
       }
    }
}

//初始化游戏界面需要用到的窗口
void init_windows()
{
      start_color();
      init_pair(1,COLOR_RED,COLOR_BLACK);    
       //1.创建一个提示(欢迎)字符
       wel=newwin(wel_lines,wel_columns,wel_y0,wel_x0);
       wmove(wel,0,0);
       wattron(wel,COLOR_PAIR(1));
       waddstr(wel,"welcome to game2048");

       wmove(wel,1,3);
       waddstr(wel,"Author:liyingzhi");        
       wrefresh(wel);

       //2.创建一个游戏数字字符窗口    
       w_2048=newwin(w_2048_lines,w_2048_coluwns,w_2048_y0,w_2048_x0);
    
       //3.显示最高得分
       w_score=newwin(w_score_lines,w_score_coluwns,w_score_y0,w_score_x0);
         
        //4.结束窗口
       w_over=newwin(w_over_lines,w_over_coluwns,w_over_y0,w_over_x0);
}
void del_windows()
{
    delwin(wel);     //删除欢迎框
    delwin(w_2048);  //删除字符框
    delwin(w_score); //删除得分框
}


//在非0位置随机删除一个数字
void delete_number(int del)
{
    int zero_num=get_zero_num();
    int i,j;
    if(zero_num==0)
    {
       return;
    }
    for(i=0;i<ITEM_NUM;i++)
    {
          for(j=0;j<ITEM_NUM;j++)
          {
	      if (del==j)
              {
                    matrix_2048[i][j]=0;
             }   
        }
    }
}

//根据矩阵matrix_2048[][]的内容,在游戏中显示
void show_matrix(void)
{
      int i,j;
      int max=matrix_2048[0][0];//最高得分
      for(i=0;i<ITEM_NUM;i++)
      {
            for(j=0;j<ITEM_NUM;j++)
            {
                //移动光标wmove
                 wmove(w_2048, i, j*6);
                 //添加要显示的字符串  int转换成char
                  char buf[6];
                  if(matrix_2048[i][j]==0)
                  {
                      sprintf(buf,"%5d",'_');
                  }
                  else
                  {
                      sprintf(buf,"%5d",matrix_2048[i][j]);
                  }
                  waddstr(w_2048,buf);
     
                  if(matrix_2048[i][j]>max)
                   {
                        max=matrix_2048[i][j];
                   }
      }
}  


    //刷新窗口
     wrefresh(w_2048);

     //显示得分
     wmove(w_score,0,6);

     char buf1[24];
     sprintf(buf1,"score:%5d",max);
     waddstr(w_score,buf1);

     //刷新窗口 wrefresh
     wrefresh(w_score);

 }

void  move_rightr(void)
{ 
     int  i;
     for(i=0;i<ITEM_NUM;i++)
     {
	int x=0;//辅助存储非0值进行比较
	int m=ITEM_NUM-1;//指向这一行最后面(要被覆盖)的位置
	int k=0;//哨兵,从右往左,找下一个非0元素a[i][k],和x进行比较
	for(k=ITEM_NUM-1;k>=0;k--)
	{
	    if(matrix_2048[i][k]!=0)
	    {
	    	if(x==0)
	    	{
	    	   x=matrix_2048[i][k];
	    	   matrix_2048[i][k]=0;
	    	}
	    	else
	    	{
	    	     //找到两个非0值,进行比较
	    	     if(matrix_2048[i][k]==x)
	    	     {
	    	          //需要合并,后移
	    	          x=x+matrix_2048[i][k];  //合并的值
	    	          matrix_2048[i][k]=0;   //前移后的数字为0
	    	          matrix_2048[i][m--]=x;  //合并的值后移

                          x=0;
                   }
                   else
                   {
                        matrix_2048[i][m--]=x;
                        x=matrix_2048[i][k];
                        matrix_2048[i][k]=0;
                   
                   }
           }
        }
    }
    matrix_2048[i][m--]=x;
}


void move_up(void)
{    
    int i;  
    for(i=0;i<ITEM_NUM;i++)
    {
         int x=0;//辅助存储非0值进行比较
         int m=0;//指向这一行最前面(要被覆盖)的位置
         int k=0;//哨兵,从上往下,找下一个非0元素 a[i][k],和x进行比较  
         for(k=0;k<ITEM_NUM;k++)
          {
             if(matrix_2048[k][i]!=0)
             {
         
                   if(x==0)
                    {
                        x=matrix_2048[k][i];
                        matrix_2048[k][i]=0;      
                   }
                   else
                  {
                        //找到两个非0值,进行比较
                          if(matrix_2048[k][i]==x)
                          {  
                              //需要合并,前移
                             x=x+matrix_2048[k][i];  //合并的值
                             matrix_2048[k][i]=0;  //前移后的数字为0
                             matrix_2048[m++][i]=x;  //合并的值前移
                             x=0;//x已经合并前移了,x要重新清0
                           }
      
                           else
                          {
                              matrix_2048[m++][i]=x;
                              x=matrix_2048[k][i];
                              matrix_2048[k][i]=0;   
                          }       
                       }
                   }
              }
    
        matrix_2048[m++][i]=x;
      }

 void move_dowm(void)
{  
 int i;  
 for(i=0;i<ITEM_NUM;i++)
 {
       int x=0;//辅助存储非0值进行比较
       int m=ITEM_NUM-1;//指向这一行最前面(要被覆盖)的位置
       int k=0;//哨兵,从下往上,找下一个非0元素 a[i][k],和x进行比较  
       for(k=ITEM_NUM-1;k>=0;k--)
       {
         if(matrix_2048[k][i]!=0)
         {
              if(x==0)
              {
                  x=matrix_2048[k][i];
                  matrix_2048[k][i]=0;      
              }
              else
              {
                 //找到两个非0值,进行比较
                 if(matrix_2048[k][i]==x)
                  {  
                        //需要合并,前移
                       x=x+matrix_2048[k][i];  //合并的值
                       matrix_2048[k][i]=0;  //前移后的数字为0
                       matrix_2048[m--][i]=x;  //合并的值前移
                       x=0;//x已经合并前移了,x要重新清0
                 }
      
                 else
                 {
                      matrix_2048[m--][i]=x;
                      x=matrix_2048[k][i];
                      matrix_2048[k][i]=0;
                 }
             }
         }
     }
     matrix_2048[m--][i]=x;
    }
}

void move_left(void)
{
     int i;    
     for(i=0;i<ITEM_NUM;i++)
     {
         int x=0;//辅助存储非0值进行比较
         int m=0;//指向这一行最前面(要被覆盖)的位置
         int k=0;//哨兵,从左至右,找下一个非0元素 a[i][k],和x进行比较
         for(k=0;k<ITEM_NUM;k++)
         {
               if(matrix_2048[i][k]!=0)
               {
                     if(x==0)
                   {
                         x=matrix_2048[i][k];
                         matrix_2048[i][k]=0;
                   }
                   else
    		   {
       		        //找到两个非0值,进行比较
    		      if(matrix_2048[i][k]==x)
     		      {  
      			    //需要合并,前移
       			    x=x+matrix_2048[i][k];   //合并的值
   		            matrix_2048[i][k]=0;     //前移后的数字为0
   			    matrix_2048[i][m++]=x;   //合并的值前移
   			    x=0;//x已经合并前移了,x要重新清0
   		      }
   		      else
   		      {
               		      matrix_2048[i][m++]=x;
                	     x=matrix_2048[i][k];
     		              matrix_2048[i][k]=0;
                       }
                 }
           }
        }
        matrix_2048[i][m++]=x;
      }
    }
//完整代码在网址中

函数分析
1、删除函数Del: 参数num是个整型数字,num等于1时,删除第一行;num等于2时,删除第二行。
每一行会有ITEM_NUM个数字,所以用一个for循环,把一行的数字删了
2、get_zero_num()函数:遍历整个二维数组,返回0的个数
3、fill_a_number()函数:首先用get_zero_num()判断是否有空位,random()%zero_num的范围是0~zero_num-1 pos=random()%zero_num+1的范围是1到zero_num pos就可以随机取其中空白的一个位置 int a[4]数组存放要填充的数字
4、init_windows():初始化窗口
newwin()函数的作用是分配内存给窗口相关的数据结构,返回一个指向窗口的结构指针,失败返回NULL。
delwin()函数可以删除一个窗口,并且释放存储窗口数据结构的内存和信息。
第一个参数:窗口的行数 第二个参数:窗口的列数 第三个参数:窗口左上顶点的行坐标
第四个参数:窗口左上顶点的列坐标 成功返回OK,失败返回ERR
mvwin()函数:第一个参数:要移动的窗口的指针 第二个参数:要移动位置左上顶点的行坐标 第三个参数:要移动位置左上顶点的列坐标 成功返回OK,失败返回ERR
5.show_matrix()
max存放最高分数,sprintf()函数把格式化数据写入字符串 第一个参数为要写入的字符串,第二个为格式化字符串,第三 个为变量。sprintf()最常见的应 用之一莫过于把整数打印到字符串中,如:sprintf(s, “%d”, 123); //把整数123打印成一个字符串保存在s中 sprintf(s, “%8x”, 4567); //小写16进制,宽度占8个位置,右对齐 sprintf()会根据参数format 字符串来转换并格式化数据,然后将结果。复制到参数str 所指的字符串数组,直到出现字符串结束(’\0’)为止。
waddstr(w_2048,buf);在w_2048这个窗口输出字符buf
6.move_left()
二维数组行遍历,按下左移键或W,整行往左移,填补空位置(0)。如果相邻位置值相同,要合并并且前移(使用后置++)
x用来存储比较的第一个非0值 m指向这一行最前面(要被覆盖)的位置 k为哨兵,从左至右找下一个非0值
if(x==0) x保存第一个非0值,如果一行只有一个非0值或者是第奇数个0,就执行 matrix_2048[i][m++]。但是m++是后置++, 是赋值后++。如果不止一个0,那么两个值比较,如果相等,x保存合并值,前移后的matrix_2048[i][k]变为0。合并的值前移。如果不相同,首先移动第一个x,利用循环外的matrix_2048[i][m++]移动第二个x
7.move_right()
二维数组行遍历。与move_left不同的是,从右往左遍历,整体往右移,所以第一个遍历的非0数,放到最右边(下标最大值)所以m- -
8.move_up()
二维数组列遍历。所以i和k要交换位置,从上往下遍历,第一个遍历的非0数,放在最上面(下标最小),所以m++
9.move_dowm()
二位数组列遍历。与move_dowm()不同的是,从下往上遍历,第一个遍历的非0数,放在最下面(下标最大),所以m- -
10.change_matrix
判断按下方向键,是否二维数组是否有改变,把matrix_2048备份到matrix_2048_bak,如果有改变,返回1,没有改变,返回0

完整代码地址
链接:https://pan.baidu.com/s/1BvlnS57pMeShkYlHf-YvzA
提取码:s4lb

你可能感兴趣的:(游戏,游戏,c语言)