基于GEC6818的五子棋游戏

基本的五子棋游戏,有UI界面,能悔棋,需要预装驱动和文件才能运行。

设计思路流程图

以下是代码

main.c

#include <stdio.h>
#include "bmp.h"
#include "game.h"
#include "lcd.h"	
#include <stdlib.h>		//	abs 的头文件





int main()
{
	//屏幕初始化
 	unsigned int *plcd = lcd_init();
    

game:
	
	//开始操作屏幕
 	Display_homepage("gobang.bmp",plcd);    //封面图片

	
	//播放背景音乐
	system("killall -KIll madplay");
	system("madplay -Q 2.mp3 -a -20 &");
	//
	Game_play( plcd);
	
	goto game;
	
	//关闭屏幕
	lcd_end( plcd);
	return 0 ;
}




lcd.c        操作屏幕函数的封装

#include <stdio.h>
#include <sys/types.h>	//	open 头文件
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>		//	read、write、close 头文件
#include <sys/mman.h>	//	mmap 的头文件
#include "lcd.h"		//	用到哪个函数就得 加上 对应的头文件


int lcd_fd = -1;		//	全局变量

/*
	lcd_init:	屏幕初始化 打开 + 映射
	返回值:		第一个像素点的地址
*/
unsigned int *lcd_init()
{
	//	1、打开屏幕文件
	lcd_fd = open("/dev/fb0",O_RDWR);	//	读写打开 显示屏
	if(lcd_fd == -1)
	{
		perror("open error");		//	显示错误原因
		return NULL;
	}

	//	2、屏幕映射
	unsigned int *plcd = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED,lcd_fd,0);
	if(plcd == MAP_FAILED)
	{
		perror("mmap error");		//	显示错误原因
		return NULL;
	}
	return plcd;
}

/*
	lcd_end:	屏幕扫尾 解映射 + 关闭
	返回值:		第一个像素点的地址
*/
void lcd_end(unsigned int *plcd)
{
	//	4、解除映射
	munmap(plcd,800*480*4);
	
	//	5、关闭屏幕文件
	close(lcd_fd);

}



lcd.h        

#ifndef __LCD_H__		//	固定格式
#define __LCD_H__		//	固定格式
		
/*
	lcd_init:	屏幕初始化 打开 + 映射
	返回值:		第一个像素点的地址
*/
unsigned int *lcd_init();


/*
	lcd_end:	屏幕扫尾 解映射 + 关闭
	返回值:		第一个像素点的地址
*/
void lcd_end(unsigned int *plcd);

#endif		//	固定格式

bmp.c        UI界面及屏幕输入的封装

#include "bmp.h"
#include "game.h"
#include <stdlib.h>		//	abs 的头文件






// 居中显示图片
void Display_homepage(char *bmp_name,unsigned int * plcd)  
{
	//	1、打开图片文件
	int fd = open(bmp_name,O_RDWR);	//	读写打开 图片
	if(fd == -1)
	{
		perror("open error");		//	显示错误原因
		return ;
	}
	//	2、判断图片是不是 BMP 
	char buf[2];
	read(fd,buf,2);
	if(!(buf[0] == 'B' && buf[1] == 'M'))
	{
		printf("你是不是憨批,转换不会\n");
		return ;
	}
	
	//	3、解析 位宽 位高 色深
	int width;
	lseek(fd,0x12,SEEK_SET);	//	定位到指定的位置
	read(fd,&width,4);		//	读取 4 字节的宽度
	
	int height;
	lseek(fd,0x16,SEEK_SET);	//	定位到指定的位置
	read(fd,&height,4);		//	读取 4 字节的高度

	short depth;
	lseek(fd,0x1c,SEEK_SET);	//	定位到指定的位置
	read(fd,&depth,2);		//	读取 2 字节的高度

	printf("%s:%d,%d,%d\n",bmp_name,width,height,depth);
	
	//	4、获取像素数组
	//	一行实际大小:
	int line_bytes = abs(width) * depth/8;
	int laizi = 0;		//	可能需要补充的字节数目
	if(line_bytes % 4)
	{
	laizi = 4 - line_bytes % 4;
	}
	//	一行保存总大小:
	int linebytes = line_bytes + laizi;
	//	像素数组总大小:
	int bytes = linebytes * abs(height);
	//	读取像素数组:	
	unsigned char array[bytes];	
	lseek(fd,0x36,SEEK_SET);	//	定位到指定的位置
	read(fd,array,bytes);




	//	5、显示图片
	unsigned char a,r,g,b;		//	保存每个像素点颜色值分量
	int i,j,k = 0;
	for(i = 0;i < abs(height);i++)		//	一行一行的显示
	{
		for(j = 0;j < abs(width);j++)	//	一行每个像素点依次显示
		{
			b = array[k++];		//	获取当前像素点的 蓝色分量
			g = array[k++];		//	获取当前像素点的 绿色分量
			r = array[k++];		//	获取当前像素点的 红色分量
			if(depth == 32)
			{
				a = array[k++];	//	获取当前像素点的 透明分量
			}
			else
			{
				a = 0;
			}
			unsigned int color = a << 24 | r << 16 | g << 8 | b;		//	合成当前像素点的颜色
			int x = width > 0 ? j : (abs(width) - 1 - j);		//	width > 0 从左到右,反之从右到左 0开始的
			int y = height > 0 ? (abs(height) - 1 - i) : i;		//	height > 0 从下到上,反之从上到下 0开始的
			 int m=(800-abs(width))/2;
			int n=(480-abs(height))/2;
			display_point(x+m,y+n,color,plcd);
			
			
		}
		k += laizi;		//	跳过加上的癞子
	}
	//	6、关闭图片文件
	close(fd);

}

	   






 
void Display_qipan()      //生成棋盘页面
{   //打开屏幕文件
 	int fd = open("/dev/fb0",O_RDWR);
	unsigned int *plcd = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);



	display_pic("duolah.bmp",plcd,0,0);//黑方
    display_pic("duolaw.bmp",plcd,600,0);//白方
    
    //生成棋盘
    for(int i = 0;i <= 480;i++)
 	{
 	 	for(int j = 120;j <= 600;j++)
  		{
   			if((i%30 -15 == 0||j%30 - 15 == 0)&& i >= 15&&i <= 465&&j >= 135&&j <= 585)
   			display_point(j, i,0x00, plcd);
   			else
   			{
   				display_point(j, i,0xCDAA7D,plcd);
   			}
   		}
	}
	munmap(plcd,800*480*4);  
	close(fd);		
}



















//设定位置显示图片
void display_pic(char *bmp_name,unsigned int * plcd,int m ,int n) 
{
	//	1、打开图片文件
	int fd = open(bmp_name,O_RDWR);	//	读写打开 图片
	if(fd == -1)
	{
		perror("open error");		//	显示错误原因
		return ;
	}

	//	2、判断图片是不是 BMP 
	char buf[2];
	read(fd,buf,2);
	if(!(buf[0] == 'B' && buf[1] == 'M'))
	{
		printf("你是不是憨批,转换不会\n");
		return ;
	}
	
	//	3、解析 位宽 位高 色深
	int width;
	lseek(fd,0x12,SEEK_SET);	//	定位到指定的位置
	read(fd,&width,4);		//	读取 4 字节的宽度
	
	int height;
	lseek(fd,0x16,SEEK_SET);	//	定位到指定的位置
	read(fd,&height,4);		//	读取 4 字节的高度

	short depth;
	lseek(fd,0x1c,SEEK_SET);	//	定位到指定的位置
	read(fd,&depth,2);		//	读取 2 字节的高度

	/*printf("%s:%d,%d,%d\n",bmp_name,width,height,depth);*/
	//	4、获取像素数组
	//	一行实际大小:
	int line_bytes = abs(width) * depth/8;
	int laizi = 0;		//	可能需要补充的字节数目
	if(line_bytes % 4)
	{
	laizi = 4 - line_bytes % 4;
	}
	//	一行保存总大小:
	int linebytes = line_bytes + laizi;
	//	像素数组总大小:
	int bytes = linebytes * abs(height);
	//	读取像素数组:	
	unsigned char array[bytes];	
	lseek(fd,0x36,SEEK_SET);	//	定位到指定的位置
	read(fd,array,bytes);

	//	5、显示图片
	unsigned char a,r,g,b;		//	保存每个像素点颜色值分量
	int i,j,k = 0;
	/*printf("请输入起始位置: ");
	scanf("%d,%d",&m,&n);*/
	
	for(i = 0;i < abs(height);i++)		//	一行一行的显示
	{
		for(j = 0;j < abs(width);j++)	//	一行每个像素点依次显示
		{
			b = array[k++];		//	获取当前像素点的 蓝色分量
			g = array[k++];		//	获取当前像素点的 绿色分量
			r = array[k++];		//	获取当前像素点的 红色分量
			if(depth == 32)
			{
				a = array[k++];	//	获取当前像素点的 透明分量
			}
			else
			{
				a = 0;
			}
		unsigned int color = a << 24 | r << 16 | g << 8 | b;		//	合成当前像素点的颜色
		int x = width > 0 ? j : (abs(width) - 1 - j);		//	width > 0 从左到右,反之从右到左 0开始的
		int y = height > 0 ? (abs(height) - 1 - i) : i;		//	height > 0 从下到上,反之从上到下 0开始的
		display_point(x+m,y+n,color,plcd);
			
		}
	k += laizi;		//	跳过加上的癞子
	}
	//	6、关闭图片文件
	close(fd);

}




/*
	display_point:	在(x,y)显示一个颜色为 color 的点
	@x:		x 坐标
	@y:		y 坐标
	@color:	要显示颜色
	@plcd:	第一个像素点的地址(mmap 的返回值)
*/
void display_point(int x,int y,unsigned int color,unsigned int *plcd)
{
	if(x >= 0 && x < 800 && y >= 0 && y < 480)	//	防止憨批
	{
		*(plcd + y * 800 + x) = color;
	}
}





//获取触屏坐标
struct point get_point()
{
	struct point xy = {-1,-1};			//	保存实时坐标
	//	1、打开文件
	int fd = open("/dev/input/event0",O_RDWR);	//	读写打开 触摸屏
	if(fd == -1)
	{
		perror("open error");		//	显示错误原因
		return xy;
	}
	
	//	2、操作文件	write
	struct input_event ev;		//	保存读取到的输入信息
	
	while(1)
	{
		read(fd,&ev,sizeof(ev));
		if(ev.type == EV_ABS && ev.code == ABS_X)
		{
			xy.x = ev.value;		//	保存 x 坐标
		}
		else if(ev.type == EV_ABS && ev.code == ABS_Y)
		{
			xy.y = ev.value;		//	保存 y 坐标
		}
		else if(ev.type == EV_KEY && ev.code == BTN_TOUCH && ev.value == 0)	//	手离开屏幕
		{
			break;
		}
	}
	
	//	3、关闭文件
	close(fd);
	return xy;
}



	

bmp.h

#ifndef __BMP_H__
#define __BMP_H__
#include <stdio.h>
#include "game.h"
struct point		//	保存触摸屏的坐标 point 对应两个值 point.x point.y
{
	int x;
	int y;
};


 
void Display_qipan();
void Display_homepage(char *bmp_name,unsigned int * plcd);
void display_point(int x,int y,unsigned int color,unsigned int *plcd);
void display_pic(char *bmp_name,unsigned int * plcd,int m ,int n) ;
struct point get_point();


#endif


gsme.c        游戏的算法

#include "bmp.h"
#include "game.h"
#include <stdlib.h>		//	abs 的头文件


int turn = 0;  //回合数
unsigned int Game_buf[16][17]={0};//存储16*16每个点

/*答辩结束后发现此处存在bug*/
unsigned int Game_buf2[10][16][17]={0};//存储10局16*16每个点

int Game_sta(int x,int y,unsigned int *plcd) //游戏开始 像素点坐标
{

	//得到棋盘坐标位置 
	int X = abs(x - 120) / 30;		//	120 = 135-(30/2)
	int Y = abs(y - 0) / 30;	//	0=15-(30/2);
	printf("落子位置为%d,%d \n",X,Y);
	//	将落棋状态写入数组 0/1/2 分别代表 空/黑/白
	if(Game_buf[X][Y]==0)	//避免重复落子
	{
		//轮数加1	
		
		for (int i = 0; i < 16; i++)
		{
			for (int j = 0; j < 16; j++)
			{	
				Game_buf2[turn][i][j] = Game_buf[i][j];		//保存 落子前所有的棋子位置
			}
		}
		turn++;
		if(turn	% 2)
		{
			Game_buf[X][Y]=1; 
			Luozi(X * 30 + 135,Y * 30 + 15,turn,plcd);
		}
		else
		{
			Game_buf[X][Y]=2;
			Luozi(X * 30 + 135,Y * 30 + 15,turn,plcd);
		} 
	}	
	//提醒下棋
	if(turn & 1)//黑方下完提示白方
	{
		display_pic("baiturn.bmp", plcd,600,175);
	}
	else
	{
		display_pic("heiturn.bmp", plcd,600,175);
	} 
	
	//游戏结束判定
	turn = Game_Over(X,Y,plcd,turn);
	return turn ;
}


//显示落子
int Luozi(int x,int y,int turn,unsigned int *plcd)
{
	int i,j;
	if (turn & 1)//执黑方先落子
	{
		for (i = 0; i < 800; i++)
		{
			for (j = 0; j < 480; j++)
			{
				if ((i-x)*(i-x)+(j-y)*(j-y)<=100)//生成半径为10的棋子
				{
						display_point(i, j, 0X000000,plcd);
						
				}
			}
		}
		printf("执白者已落子 \n");
	}
	else
	{
	  	for(i=0;i<800;i++)
	  		{
	   		for(j=0;j<480;j++)
	  			{	
	    		if((i-x)*(i-x)+(j-y)*(j-y)<=100)
	    			{
	     				display_point(i,j,0xffffff,plcd);
						
	    			}
			}
	 	}
		printf("执黑者已落子 \n");
 	}
}




//悔棋
int regret(int x,int y,unsigned int *plcd)
{	
	if(turn)
	{
		turn--;		//回合数减1	
		//存储   复位悔棋前的棋子布局
		for(int i = 0;i < 16;i++)
		{
			for(int j = 0;j < 16;j++)
			{
				Game_buf[i][j]=Game_buf2[turn][i][j]; //棋盘复位
				
			}
		}


		
		// 显示   复位悔棋前的棋子布局
		Display_qipan();
		for(int i = 0;i < 16;i++)
		{
			for(int j = 0;j < 16;j++)
			{
				int X = abs(x - 120) / 30;		//	120 = 135-(30/2)
				int Y = abs(y - 0) / 30;	//	0=15-(30/2);
				if(Game_buf[i][j] == 1)
				{
					Luozi(i * 30 + 135,j * 30 + 15,1,plcd);
				}
				if(Game_buf[i][j] == 2)
				{
					Luozi(i * 30 + 135,j * 30 + 15,2,plcd);
				}
			}
		}
	}
	else
	{
		printf("棋盘中已无棋子 \n");
	}
		
}





//清空棋盘
int clear()
{
	for(int a=0;a<16;a++)
 	{
  		for(int b=0;b <16;b++)
  		{
   			Game_buf[a][b]=0;
			for (int c= 0; c < 10; c++)
			{
				Game_buf2[c][a][b]=0;
			}
			
  		}
 	}
	turn = 0 ;
	printf("已清盘 \n");
}



//游戏结束条件
int Game_Over(int x,int y,unsigned int * plcd,int turn)  //棋盘落子坐标
{
 	
	int x1 = 0,y1 = 0,xy1 = 0,xy2 = 0;//四个方向的累计数
	for(int i = -4;i < 5;i ++)
	{
		
		//水平方向判定
		if(Game_buf[x][y] == Game_buf[x + i][y] )		
		{   
			x1++;
			printf("x1值为 %d\n",x1);
			if(x1 == 5)
			{
				break;
			}
		}
		else
		{
			x1 = 0;
		}
	
		//竖直方向判定	
		if(Game_buf[x][y] == Game_buf[x][y + i])		
		{
			y1++;
			printf("y1值为 %d\n",y1);
			if(y1 == 5)
			{
				break;
			}
		}
		else
		{
			y1 = 0;
		}
		//Y=X方向判定
		if(Game_buf[x][y] == Game_buf[x + i][y + i])		
		{
			xy1++;
			printf("xy1值为 %d\n",xy1);
			if(xy1 == 5)
			{
				break;
			}
		}
		else
		{
			xy1 = 0;
		}

		//Y=-X方向判定
		if(Game_buf[x][y] == Game_buf[x - i][y+i])		
		{
			xy2++;
			printf("xy2值为 %d\n",xy2);
			if(xy2 == 5)
			{
				break;
			}
		}
		else
		{
			xy2 = 0;
		}
		}
		if( x1 == 5||y1 == 5||xy1 == 5||xy2 == 5)//结束条件
		{
			if(turn & 1)
			{
				Display_homepage("heiwin.bmp", plcd);
				/*system("killall -KIll madplay");
				system("madplay -Q 3.mp3 &");*/
			}
			else
			{
				Display_homepage("baiwin.bmp", plcd);
				/*system("killall -KIll madplay");
				system("madplay -Q 4.mp3 &");*/
			}
			clear();	//清理棋盘
			sleep(3);	//复盘时间
			Display_qipan();
			//播放背景音乐
			system("killall -KIll madplay");
			system("madplay -Q 2.mp3 -a -20 &");
			return 0;
		}
		else
		{
			return turn;
		}
	
}





int Game_play(unsigned int *plcd)
{
	while(1)
	{
			struct point p = get_point();
			printf("%d,%d\n",p.x,p.y);
			
			if (p.x>370&&p.x<625&&p.y>520&&p.y<600)  //进入游戏,生成棋盘
			{
				Display_qipan();					
				clear();
				system("killall -KIll madplay");
				system("madplay -Q 2.mp3 -a -20 &");
				printf("开始下棋 \n");
				break;
			}
			else
			{
				printf("请点击指定区域 \n");
			}
	}

	while(1)
	{
			struct point p = get_point();
			
			printf("%d,%d\n",p.x,p.y);
			int x1 = p.x * 800 / 1024,y1 = p.y * 480 / 600; 	//触屏坐标转化为像素点坐标			
			if (x1>120&&x1<600&&y1>0&&y1<480)  // 在范围内落子
			{
				//开始游戏
				Game_sta(x1,y1,plcd);
			}
			
			else if(x1>600&&x1<800&&y1>0&&y1<75||x1>0&&x1<120&&y1>0&&y1<80)//		悔棋
			{	
				regret(x1,y1,plcd);
			}
			else if (y1>400&&y1<480&&x1>600&&x1<800)
			{
				printf("返回主界面 \n");
				break ;
			}
				
			
	} 

}

game.h

#ifndef __GAME_H__
#define __GAME_H__
 
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <math.h>
#include <linux/input.h>
 
 
struct point get_point();
int Game_sta(int x,int y,unsigned int *plcd);
int save(int turn);

int Luozi(int x,int y,int turn,unsigned int *plcd);
int clear();
int regret(int x,int y,unsigned int *plcd);

int Game_Over(int x,int y,unsigned int * plcd,int turn);
int Game_play(unsigned int *plcd);


#endif

项目展示

项目讲解

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 基于GEC6818的五子棋是一种在GEC6818开发板上实现的五子棋游戏GEC6818是一款功能强大的开发板,搭载了ARM架构的处理器和Linux操作系统,可以方便地开发各种应用程序。 在这个基于GEC6818五子棋游戏中,我们可以通过连接显示器和输入设备(如键盘或鼠标)来进行游戏。通过GUI界面,我们可以看到一个棋盘和棋子,通过点击鼠标或使用键盘来下棋。 这个五子棋游戏程序是在GEC6818上通过编程实现的。首先,我们需要设计一个算法来判断下棋位置的合法性,并在合法的位置上落子。接着,我们需要实现一个判断胜负的算法,以便在游戏进行中及时判断出胜利者。 在这个基于GEC6818五子棋游戏中,我们还可以实现一些高级功能,如悔棋、重新开始、人机对战、网络对战等。通过GEC6818的强大计算能力和网络功能,我们可以实现人机对战或网络对战功能,与其他玩家进行五子棋对局。 总而言之,基于GEC6818的五子棋是一款利用GEC6818开发板的处理能力和软件开发环境实现的五子棋游戏。通过这个游戏,我们可以利用GEC6818的强大功能进行智能手动对弈,提高智力和娱乐性,推动技术的发展和应用的普及。 ### 回答2: 基于GEC6818的五子棋是一种利用GEC6818开发板的硬件资源和软件平台来实现的五子棋游戏GEC6818是一款ARM架构的开发板,拥有强大的计算能力和扩展性,非常适合用于实现五子棋游戏。 在硬件方面,我们可以利用GEC6818的高性能处理器和丰富的接口来实现五子棋游戏的核心功能。开发板上的触摸屏可以作为游戏的输入设备,玩家可以通过触摸屏来落子。同时,GEC6818的HDMI接口可以连接到显示器,用于展示游戏界面和棋盘。 在软件方面,我们可以使用C/C++语言和相关的开发工具来编写五子棋的算法和游戏逻辑。利用GEC6818强大的计算能力,可以实现高效的搜索算法和智能的人机对战。同时,开发板上的Linux操作系统和相关的开发框架可以为我们提供丰富的软件资源和开发工具,使得五子棋游戏的开发更加便捷和高效。 在游戏界面方面,我们可以利用GEC6818的图形处理能力和相关的图形库来设计美观的游戏界面。可以绘制出棋盘、棋子和其他游戏元素,给玩家带来良好的视觉体验。 总之,基于GEC6818的五子棋是一种利用GEC6818开发板的硬件资源和软件平台来实现的五子棋游戏。通过充分利用GEC6818的强大计算能力、丰富的接口和开发工具,我们可以实现高性能、智能化和美观的五子棋游戏
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值