要在家目录下
makefile
1 main : main.o fun.o input.o fb_draw.o
2 gcc -Wall -o $@ $^
3 clean :
4 rm -rf *.o main
fb_draw.h
#ifndef __FB_DRAW_H
#define __FB_DRAW_H
int fb_open(void);
void fb_close(void);
void fb_draw_point(int x, int y, unsigned int color);
int xres(void);
int yres(void);
#endif
fun.h
#ifndef __INPUT_H
#define __INPUT_H
#define KEYBOARDMODE 0
#define CHARMODE 1
void input_init(void);
int input_choice_mode(int mode);
int input_kb_mode(void);
int input_char_mode(void);
void input_recover(void);
#endif
inc.h
#ifndef __INC_H
#define __INC_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include <string.h>
#include
#include "input.h"
#include "fb_draw.h"
#endif
input.h
#ifndef __INPUT_H
#define __INPUT_H
#define KEYBOARDMODE 0
#define CHARMODE 1
void input_init(void);
int input_choice_mode(int mode);
int input_kb_mode(void);
int input_char_mode(void);
void input_recover(void);
#endif
fb_draw.c
#include "include/inc.h"
/***********************************************
结构体中保存了有关操作framebuffer设备所需的成员
fix : 本地的fb数据
var : 可变的fb数据
bpp : 一个像素点所占位数
fd : 保存fb文件的文件描述符
fbp : 获取映射空间地址
fbpi: 获取映射空间地址
************************************************/
struct
{
struct fb_fix_screeninfo fix;//本地fb数据
struct fb_var_screeninfo var;//可变fb数据
unsigned int bpp;//一个像素点所占位数
int fd;//保存fb文件的文件描述符
unsigned char *fbp;//获取映射空间地址
unsigned int *fbpi;//获取映射空间地址
}fb_st;
/***********************************************
int fb_open(void);
功 能 : 把fb文件打开,通过ioctl控制fb设备
通过mmap映射fb文件
返回值 : 无
参 数 : 成功返回0, 失败返回-1
************************************************/
int fb_open(void)
{
int ret;
fb_st.fd = open("/dev/fb0", O_RDWR);
if(-1 == fb_st.fd)
{
perror("open");
goto error;
}
/* get fb_var_screeninfo */
ret = ioctl(fb_st.fd, FBIOGET_VSCREENINFO, &fb_st.var);
if(-1 == ret)
{
perror("ioctl(fb_st.var)");
goto close_fd;
}
fb_st.bpp = fb_st.var.bits_per_pixel >> 3;
/* get fb_fix_screeninfo */
ret = ioctl(fb_st.fd, FBIOGET_FSCREENINFO, &fb_st.fix);
if(-1 == ret)
{
perror("ioctl(fb_st.fix)");
goto close_fd;
}
/* get framebuffer start address */
fb_st.fbp = mmap(0, fb_st.fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb_st.fd, 0);
if((void *)-1 == fb_st.fbp)
{
perror("mmap");
goto close_fd;
}
return 0;
close_fd:
close(fb_st.fd);
error:
return -1;
}
/***********************************************
void fb_close();
功 能 : 解除设备文件的映射,关闭文件
返回值 : 无
参 数 : 无
************************************************/
void fb_close()
{
munmap(fb_st.fbp, fb_st.fix.smem_len);
close(fb_st.fd);
}
/***********************************************
void fb_draw_point(int x, int y, int color);
功 能 : 通过framebuff画点
返回值 : 无
参 数 : x 横坐标
y 纵坐标
color 要显示的颜色(现只支持白色0xFF 黑色0x00)
************************************************/
void fb_draw_point(int x, int y, unsigned int color)
{
unsigned long offset;
offset = fb_st.bpp * x + y * fb_st.fix.line_length;
//memset(fb_st.fbp + offset, color, fb_st.bpp);
fb_st.fbpi = (unsigned int *)(fb_st.fbp + offset);
*(fb_st.fbpi) = color;
}
/***********************************************
int xres(void);
功 能 : 获取x轴坐标
返回值 : 获取到的x轴坐标
参 数 : 无
************************************************/
int xres(void)
{
return fb_st.var.xres;
}
/***********************************************
int yres(void);
功 能 : 获取y轴坐标
返回值 : 获取到的y轴坐标
参 数 : 无
************************************************/
int yres(void)
{
return fb_st.var.yres;
}
input.c
#include "include/inc.h"
/***********************************************
结构体中保存了有关键盘操作或者终端设置的一些成员
old : 保存原始终端信息
new : 改变之后的终端信息
kb_fd : 保存键盘设备的设备号
ev : 保存输入设备的信息数据
************************************************/
struct
{
struct termios old;
struct termios new;
int kb_fd;
struct input_event ev;
}input_st;
/***********************************************
void input_init(void);
功 能 : 用来在接收输入值之前设置终端
返回值 : 无
参 数 : 无
************************************************/
void input_init(void)
{
tcgetattr(0, &input_st.old);
input_st.new = input_st.old;
input_st.new.c_lflag &= ~ICANON;
input_st.new.c_lflag &= ~ECHO;
tcsetattr(0, TCSANOW, &input_st.new);
}
/***********************************************
char *mystrcpy(char *dest, const char *src);
功 能 : 用来拷贝字符串,碰到尾0或者空格停止
返回值 : 指向dest的指针
参 数 : dest 拷贝的目标,dest指向拷贝的空间
src 拷贝的源,指向要拷贝的字符串
************************************************/
char *mystrcpy(char *dest, const char *src)
{
int i = 0;
for(i = 0; src[i] != '\0' && src[i] != ' '; i++)
dest[i] = src[i];
dest[i] = '\0';
return dest;
}
/***********************************************
void input_find_dev_file(char *buf_ev);
功 能 : 用来读取当前用户识别的键盘文件
返回值 : 无
参 数 : buf_ev 保存获取到的键盘设备文件名
************************************************/
void input_find_dev_file(char *buf_ev)
{
FILE *fp = NULL;
char buf[128] = {0};
char *find_kb = "keyboard";
char *find_ev = "event";
char *p = NULL;
fp = fopen("/proc/bus/input/devices", "r");
while((fgets(buf, sizeof(buf) - 1, fp)) != NULL)
{
p = strstr(buf, find_kb);
if(p == NULL)
continue;
else
{
while((fgets(buf, sizeof(buf) - 1, fp)) != NULL)
{
p = strstr(buf, find_ev);
if(p == NULL)
continue;
else
{
mystrcpy(buf_ev, p);
break;
}
}
break;
}
}
fclose(fp);
}
/***********************************************
int input_choice_mode(int mode);
功 能 : 用来选择接收输入源的模式
返回值 : 0 代表使用键盘模式
1 代表使用字符模式
-1 代表选择模式失败
参 数 : KEYBOARDMODE 键盘模式
CHARMODE 字符模式
************************************************/
int input_choice_mode(int mode)
{
char dest[64] = "/dev/input/";
char buf[8] = {0};
switch(mode)
{
case KEYBOARDMODE :
input_find_dev_file(buf);
strcat(dest, buf);
input_st.kb_fd = open(dest, O_RDONLY);
if(input_st.kb_fd < 0)
{
perror("open()");
return -1;
}
break;
case CHARMODE : break;
default : return -1;
}
return mode;
}
/***********************************************
int input_kb_mode(void);
功 能 : 获取键盘的键值,并返回
返回值 : 为了使用方便,返回[103上]
返回[108下], 返回[105左]
返回[106右], 返回[14落子]
返回[16quit]
参 数 : 无
************************************************/
int input_kb_mode(void)
{
read(input_st.kb_fd, &input_st.ev, sizeof(input_st.ev));
if(input_st.ev.type == EV_KEY)
if(input_st.ev.value == SYN_REPORT)
{
if(input_st.ev.code == 16)
{
tcsetattr(0, TCSANOW, &input_st.old);
close(input_st.kb_fd);
}
return input_st.ev.code;
}
return 0;
}
/***********************************************
int input_char_mode(void);
功 能 : 获取键盘字符,并返回
返回值 : 为了使用方便,返回[w上]
返回[s下], 返回[a左]
返回[d右], 返回[' ']
返回[qquit]
请自行处理大小写
参 数 : 无
************************************************/
int input_char_mode(void)
{
int val = 0;
val = getchar();
if(val == 'q' || val == 'Q')
tcsetattr(0, TCSANOW, &input_st.old);
return val;
}
/***********************************************
void input_recover(void);
功 能 : 用来恢复设置终端
返回值 : 无
参 数 : 无
************************************************/
void input_recover(void)
{
tcsetattr(0, TCSANOW, &input_st.old);
}
fun.c
#include
#include
#include "include/inc.h"
#include "include/fun.h"
int color = 0x000000; //棋盘线颜色 黑色
int back_color = 0xFFFFFF; //棋盘背景颜色 白色
int play1_color = 0xCC9966;//0x00BFFF; //玩家1棋子颜色
int play2_color = 0x000000;//0xFFBBFF; //玩家2棋子颜色
struct cir c = {0, 0, 20, 0x00BFFF};
int ifset(int (*arr)[17], int *x, int *y)
{
if((*x) > 16)
*x = 0;
if((*x) < 0)
*x = 16;
if((*y) > 16)
*y = 0;
if((*y) < 0)
*y = 16;
if(arr[(*x)][(*y)] == 1 || arr[(*x)][(*y)] == 2)
return 1;
return 0;
}
void draw_circle(int x, int y, int r, int color)
{
int x0, y0;
for(x0 = x - r; x0 <= x + r; x0++)
{
for(y0 = y - r; y0 <= y + r; y0++)
{
if((x0 - x) * (x0 - x) + (y0 - y) * (y0 - y) <= r * r)
fb_draw_point(x0, y0, color);
}
}
}
int is_win(int arr[][17], int x, int y, int mode)
{
int i = 0, j = 0, sum = 0;
for(i = x; i < x + 5 && i <= 16; i++) //判断横向能否赢
{
if(arr[i+1][y] == mode)
sum++;
else
break;
}
for(i = x; i > x - 5 && i >= 0; i--)
{
if(arr[i-1][y] == mode)
sum++;
else
break;
}
if(sum >= 4)
return 1;
else
sum = 0;
for(i = y; i < y + 5 && i <= 16; i++) //判断纵向能否赢
{
if(arr[x][i+1] == mode)
sum++;
else
break;
}
for(i = y; i >= y - 5 && i >= 0; i--)
{
if(arr[x][i-1] == mode)
sum++;
else
break;
}
if(sum >= 4)
return 1;
else
sum = 0;
j = y;
for(i = x; i < x + 5 && i <= 16; i++) //判断撇能否赢
{
if(arr[i+1][j-1] == mode)
sum++;
else
break;
j--;
}
j = y;
for(i = x; i > x - 5 && i >= 0; i--)
{
if(arr[i-1][j+1] == mode)
sum++;
else
break;
j++;
}
if(sum >= 4)
return 1;
else
sum = 0;
j = y;
for(i = x; i < x + 5 && i <= 16; i++) //判断捺能否赢
{
if(arr[i+1][j+1] == mode)
sum++;
else
break;
}
j = y;
for(i = x; i > x - 5 && i >= 0; i--)
{
if(arr[i-1][j-1] == mode)
sum++;
else
break;
j--;
}
if(sum >= 4)
return 1;
return 0;
}
void print() //打印棋盘
{
int i = 0, j = 0;
for(i = 510; i <= 1410; i++) //打印棋盘背景颜色
{
for(j = 90; j <= 990; j++)
fb_draw_point(i, j, back_color);
}
for(i = 530; i <= 1390; i++) //打印棋盘外边框 上
{
for(j = 110; j <= 113; j++)
fb_draw_point(i, j, color);
}
for(i = 530; i <= 1390; i++) //打印棋盘外边框 下
{
for(j = 970; j <= 973; j++)
fb_draw_point(i, j, color);
}
for(i = 530; i <= 533; i++) //打印棋盘外边框 左
{
for(j = 110; j <= 970; j++)
fb_draw_point(i, j, color);
}
for(i = 1390; i >= 1385; i--) //打印棋盘外边框 右
{
for(j = 112; j <= 970; j++)
fb_draw_point(i, j, color);
}
}
void print_line()
{
int i = 0, j = 0;
for(i = 560; i <= 1360; i++) //打印棋盘线条
{
for(j = 140; j <= 940; j += 50)
fb_draw_point(i, j, color);
}
for(i = 560; i <= 1360; i += 50)
{
for(j = 140; j <= 940; j++)
fb_draw_point(i, j, color);
}
}
void print_intime(int (*xy_point)[17], struct cir q)
{
int i = 0, j = 0, c = 0, d = 0, x = 0, y = 0;
for(i = 560, x = 0; i <= 1360; i += 50, x++)
{
for(j = 140, y = 0; j <= 940; j += 50, y++)
{
if(xy_point[x][y] == 1)
draw_circle(i, j, q.r, play1_color);
else if(xy_point[x][y] == 2)
draw_circle(i, j, q.r, play2_color);
else if(xy_point[x][y] == 0)
{
draw_circle(i, j, q.r, back_color);
for(c = i + 20, d = j; c >= i - 20; c--)
{
if(c < 560 || c > 1360)
continue;
fb_draw_point(c, d, color);
}
for(d = j + 20, c = i; d >= j - 20; d--)
{
if(d < 140 || d > 940)
continue;
fb_draw_point(c, d, color);
}
}
}
}
}
void _set(int *x, int *y)
{
(*x)++;
if((*x) == 17)
{
(*x) = 0;
(*y)++;
if((*y) == 17)
(*y) = 0;
}
}
int play(int (*xy_point)[17], int mode)
{
int ret = 0, flag = 0, val = 0, tmpx = 0, tmpy = 0;
flag = input_choice_mode(CHARMODE);
c.x = 0; c.y = 0;
while(ifset(xy_point, &c.x, &c.y))
_set(&c.x, &c.y);
xy_point[c.x][c.y] = mode;
print_intime(xy_point, c);
LEAP:
if(flag == 0)
{
val = input_kb_mode();
switch(val)
{
case 103 : tmpy = c.y;
tmpx = c.x;
c.y--;
while(ifset(xy_point, &c.x, &c.y))
_set(&c.x, &c.y);
xy_point[tmpx][tmpy] = 0;
break;
case 108 : tmpy = c.y;
tmpx = c.x;
c.y++;
while(ifset(xy_point, &c.x, &c.y))
_set(&c.x, &c.y);
xy_point[tmpx][tmpy] = 0;
break;
case 105 : tmpx = c.x;
tmpy = c.y;
c.x--;
while(ifset(xy_point, &c.x, &c.y))
_set(&c.x, &c.y);
xy_point[tmpx][tmpy] = 0;
break;
case 106 : tmpx = c.x;
tmpy = c.y;
c.x++;
while(ifset(xy_point, &c.x, &c.y))
_set(&c.x, &c.y);
xy_point[tmpx][tmpy] = 0;
break;
case 14 : ret = 1;
break;
case 16 : exit(0) ;
}
}
else if(flag == 1)
{
val = input_char_mode();
switch(val)
{
case 'W' :
case 'w' : tmpx = c.x;
tmpy = c.y;
c.y--;
while(ifset(xy_point, &c.x, &c.y))
_set(&c.x, &c.y);
xy_point[tmpx][tmpy] = 0;
break;
case 'S' :
case 's' : tmpx = c.x;
tmpy = c.y;
c.y++;
while(ifset(xy_point, &c.x, &c.y))
_set(&c.x, &c.y);
xy_point[tmpx][tmpy] = 0;
break;
case 'A' :
case 'a' : tmpx = c.x;
tmpy = c.y;
c.x--;
while(ifset(xy_point, &c.x, &c.y))
_set(&c.x, &c.y);
xy_point[tmpx][tmpy] = 0;
break;
case 'D' :
case 'd' : tmpx = c.x;
tmpy = c.y;
c.x++;
while(ifset(xy_point, &c.x, &c.y))
_set(&c.x, &c.y);
xy_point[tmpx][tmpy] = 0;
break;
case ' ' : ret = 1; break;
case 'q' : exit(0) ;
}
}
xy_point[c.x][c.y] = mode;
print_intime(xy_point, c);
if(ret != 1)
goto LEAP;
if(is_win(xy_point, c.x, c.y, mode))
return mode;
return 0;
}
main.c
#include
#include "include/fun.h"
#include "include/inc.h"
int main(void)
{
int i = 0, j = 0; //循环变量
int xy_point[17][17] = {0}; //保存棋盘坐标
int ret = 0; //接收函数返回值
fb_open();
xres();
yres();
input_init();
print(); //打印棋盘边框和背景
print_line(); //打印棋盘
while(1)
{
ret = play(xy_point, 1); //玩家1下棋
if(ret < 0)
break;
else if(ret == 1)
{
printf("play1 win\n");
break;
}
ret = play(xy_point, 2); //玩家2下棋
if(ret < 0)
break;
else if(ret == 2)
{
printf("play2 win\n");
break;
}
}
input_recover();
fb_close();
return 0;
}