欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

俄罗斯方块

程序员文章站 2023-12-23 20:49:51
...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#include "keyboard.h"

int FC = 5;
int BC = 4;
#define W 10
#define H 20
#define WHICH_SHAPE rand() / 7 

struct data
{
    int x;
    int y;
};

struct Game
{
    int score;
    int is_shape_bottom;
    int shape_start_num;
}Game;
int random_arr_number;
struct shape
{
    int s[5][5];
};

struct shape shape_arr[7] = {
    { 0,0,0,0,0, 0,0,1,0,0, 0,1,1,1,0, 0,0,0,0,0, 0,0,0,0,0 },
    { 0,0,0,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,0,0,0 },
    { 0,0,0,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,1,1,0, 0,0,0,0,0 },
    { 0,0,0,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,1,1,0,0, 0,0,0,0,0 },
    { 0,0,0,0,0, 0,1,1,0,0, 0,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0 },
    { 0,0,0,0,0, 0,1,1,0,0, 0,0,1,1,0, 0,0,0,0,0, 0,0,0,0,0 },
    { 0,0,0,0,0, 0,0,1,1,0, 0,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0 } 

};
int background[H][W] = {0};


//测试背景函数
void print_backgroud()
{
    int i = 0;
    for(; i < H; i++)
    {
        int j = 0;
        for(; j < W; j++)
        {
            printf("%d ", background[i][j]);
        }
        printf("\n");
    }
}

void draw_element(int x, int y, int c)
{
    x *= 2;
    x++;
    y++;
    printf("\033[%d;%dH", y, x);
    printf("\033[3%dm\033[4%dm", c, c);
    printf("[]");
    printf("\033[0m");
    fflush(stdout);
}

//绘制背景
void draw_bk()
{
    int i = 0;
    for(; i < H; i++)
    {
        int j = 0;
        for(; j < W; j++)
        {
            if(background[i][j] == 0)//初始化背景对应的数组为全0
            {
                //如果背景对应的数组为 0, 就将其颜色绘制为背景色
                draw_element(j, i, BC);
            }
            else
            {
                //否则绘制为前景色
                draw_element(j, i, FC);
            }
        }
    }
}

//画图形
void draw_shape(int x, int y, struct shape p, int c)
{
    int i = 0;
    for(; i < 5; i++)
    {
        int j = 0;
        for(; j < 5; j++)
        {
            if(p.s[i][j] != 0)//当图形对应的数组的取值不是零, 则将其绘制为前景色
            {
                draw_element(x +j, y + i, c);
            }
        }
    }
}

//判断能否移动
int can_move(int x, int y, struct shape p)
{
    int i = 0;
    for(; i < 5; i++)
    {
        int j = 0;
        for(; j < 5; j++)
        {
            //如果图形对用的数组的值为0
            if(p.s[i][j] == 0)
            {
                continue;
            }
            if(y + i >= H)
            {
                return 0;
            }
            if(x + j >= W || x + j < 0)
            {
                return 0;
            }
            if(background[y + i][x + j] != 0)
            {
                return 0;
            }
        }
    }
    return 1;
}

//将图形装到对应的背景数组中
void set_back(struct data* position, struct shape p)
{
    //测试变量
    int i = 0;
    for(; i < 5; i++)
    {
        int j = 0;
        for(; j < 5; j++)
        {
            if(p.s[i][j] != 0)//如果图形对应的数组中的元素是1, 就将背景对应的数组的元素置为1
            {
                background[position -> y + i][position -> x + j] = 1;
            }
        }
    }
}

//消除一整行
int clean_line()
{
    int i = 0;
    //遍历这个背景对应的数组的每一行, 如果数组对应的元素的值非0, 就将total 加1
    for(; i < H; i++)
    {
        int j = 0;
        int total = 0;
        for(; j < W; j++)
        {
            if(background[i][j] != 0)
            {
                total++;
            }     
        }
        //如果一行满了, 就将上一行全部拷贝给这一行
        if(total == W)
        {
            int k = i;
            for(; k > 0; k--)
            {
                memcpy(background[k], background[k - 1], sizeof(background[k]));
            }
            //此时已经将第二行拷给第三行, 第三行拷给第四行, ..., 第k-1行拷给第 k 行, 循环出来
            //时, k 等于0, 此时只有第0行没有被覆盖, 其他的都已经被覆盖, 于是将第 0 行全部置位 0
            memset(background[0], 0x00, sizeof(background[0]));
            Game.score += 10;
            printf("\033[5;40H当前得分: %d\n", Game.score);
        }
    }
}


//判断游戏是否结束
void over()
{
    int i = 0;
    for(; i < W; i++)
    {
        if(background[3][i] != 0)//如果起始行对应的数组不为0, 就说明游戏结束
        {
            printf("你输了\n");
            recover_keyboard();
            exit(0);
        }
    }
}
//后序该函数会随着时间的变化往下落的更快
void shape_down(struct data* p)
{
    draw_shape(p -> x, p -> y, shape_arr[random_arr_number], BC);
    //判断下一个位置是否可以移动
    if(can_move(p -> x, p -> y + 1, shape_arr[random_arr_number]))
    {
        //如果能够移动, 就将相应的位置的 y 加1
        p -> y++;
        draw_shape(p -> x, p -> y, shape_arr[random_arr_number], FC);
    }
    else
    {
        //将图形保存, 绘制
        set_back(p, shape_arr[random_arr_number]);
        //将原来的位置绘制为前景色
        draw_shape(p -> x, p -> y, shape_arr[random_arr_number], FC);
        //消掉一整行, 然后重新绘制背景
        clean_line();
        over();
        //重新绘制背景
        draw_bk();
        //将位置重新定位
        p -> y = 1;
        p -> x = 3;
        random_arr_number = rand()%7;
        Game.is_shape_bottom = 1;
        FC = rand()%8;
        if(FC == BC)
        {
            FC = BC - 1;
        }
    }
}

struct shape shape_turn_90(struct shape p)
{
    struct shape tmp;
    int i = 0;
    for(; i < 5; i++)
    {
        int j = 0;
        for(; j < 5; j++)
        {
            tmp.s[i][j] = p.s[4 - j][i];
        }
    }
    return tmp;
}

struct data pos = {.x = 3, .y = 5};

void shape_handle(struct data* pos)
{
    int n = get_key();
    if(is_left(n) && can_move(pos -> x - 1, pos -> y, shape_arr[random_arr_number]))
    {
        draw_shape(pos -> x, pos -> y, shape_arr[random_arr_number], BC);
        pos -> x--;
        draw_shape(pos -> x, pos -> y, shape_arr[random_arr_number], FC);
    }
    if(is_right(n) && can_move(pos -> x + 1, pos -> y, shape_arr[random_arr_number]))
    {
        draw_shape(pos -> x, pos -> y, shape_arr[random_arr_number], BC);
        pos -> x++;
        draw_shape(pos -> x, pos -> y, shape_arr[random_arr_number], FC);
    }
    if(is_up(n))
    {
        draw_shape(pos -> x, pos -> y, shape_arr[random_arr_number], BC);
        shape_arr[random_arr_number] = shape_turn_90(shape_arr[random_arr_number]);
        if(can_move(pos -> x, pos -> y, shape_arr[random_arr_number]) == 0)
        {
            shape_arr[random_arr_number] = shape_turn_90(shape_arr[random_arr_number]);
            shape_arr[random_arr_number] = shape_turn_90(shape_arr[random_arr_number]);
            shape_arr[random_arr_number] = shape_turn_90(shape_arr[random_arr_number]);
        }
        draw_shape(pos -> x, pos ->y , shape_arr[random_arr_number], FC);
    }
    if(is_down(n))
    {
        draw_shape(pos -> x, pos -> y, shape_arr[random_arr_number], BC);
        if(can_move(pos -> x, pos -> y + 1, shape_arr[random_arr_number]))
        {
            pos -> y++;
            draw_shape(pos -> x, pos -> y, shape_arr[random_arr_number], FC);
        }
        else 
        {
            draw_shape(pos -> x, pos -> y, shape_arr[random_arr_number], FC);
        }
    }
}

void handler(int s)
{
    shape_down(&pos);
}

void handler_int(int s)
{
    recover_keyboard();
    exit(0);
}

int main()
{
    struct sigaction act;
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGALRM, &act, NULL);
    printf("\033[5;40H当前得分: %d\n", Game.score);

    signal(SIGINT, handler_int);
    signal(SIGQUIT, SIG_IGN);

    struct itimerval it;
    it.it_value.tv_sec = 0;
    it.it_value.tv_usec = 1;
    it.it_interval.tv_sec = 1;
    it.it_interval.tv_usec = 0;
    setitimer(ITIMER_REAL, &it, NULL);

    init_keyboard();
    draw_bk();
    while(1)
    {
        shape_handle(&pos);
    }
    recover_keyboard();
    return 0;
}

俄罗斯方块

相关标签: 俄罗斯方块

上一篇:

下一篇: