要在家目录下 makefile 1 main : main.o fun.o input.o fb_draw.o 2 gcc -Wall -o [emailprotected] $^ 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_po
要在家目录下
makefile
1 main : main.o fun.o input.o fb_draw.o 2 gcc -Wall -o [email protected] $^
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 <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/fb.h> #include <linux/input.h> #include <unistd.h> #include <sys/mman.h> #include <string.h> #include <termios.h> #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 <stdio.h> #include <stdlib.h> #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 <stdio.h> #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; }