Backgammon version framebuffer

To home directory

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 <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;
}

 

Guess you like

Origin www.cnblogs.com/zjw2030/p/11428705.html