俄罗斯方块
程序员文章站
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;
}