⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tetris.c

📁 一个类linux的dos下开发的操作系统.
💻 C
字号:
#include <stdlib.h> /* srand(), random() */
#include <stdio.h> /* printf() */
#include <conio.h> /* KEY_nnn */
#include <time.h> /* time() */
#include <os.h> /* read(), select(), ioctl() */

/* dimensions of playing area */
#define	SCN_WID		15
#define	SCN_HT		20
/* direction vectors */
#define	DIR_UP		{ 0, -1 }
#define	DIR_DN		{ 0, +1 }
#define	DIR_LT		{ -1, 0 }
#define	DIR_RT		{ +1, 0 }
#define	DIR_UP2		{ 0, -2 }
#define	DIR_DN2		{ 0, +2 }
#define	DIR_LT2		{ -2, 0 }
#define	DIR_RT2		{ +2, 0 }
/* ANSI colors */
#define	COLOR_BLACK	0
#define	COLOR_RED	1
#define	COLOR_GREEN	2
#define	COLOR_YELLOW	3
#define	COLOR_BLUE	4
#define	COLOR_MAGENTA	5
#define	COLOR_CYAN	6
#define	COLOR_WHITE	7

typedef struct
{
	short int delta_x, delta_y;
} vector_t;

typedef struct
{
/* pointer to shape rotated +/- 90 degrees */
	unsigned char plus_90, minus_90;
/* shape color */
	unsigned char color;
/* drawing instructions for this shape */
	vector_t dir[4];
} shape_t;

static shape_t _shapes[] =
{
/* shape #0:			cube */
	{
		0, 0, COLOR_BLUE,
		{
			DIR_UP, DIR_RT, DIR_DN, DIR_LT
		}
	},
/* shapes #1 & #2:		bar */
	{
		2, 2, COLOR_GREEN,
		{
			DIR_LT, DIR_RT, DIR_RT, DIR_RT
		}
	},
	{
		1, 1, COLOR_GREEN,
		{
			DIR_UP, DIR_DN, DIR_DN, DIR_DN
		}
	},
/* shapes #3 & #4:		'Z' shape */
	{
		4, 4, COLOR_CYAN,
		{
			DIR_LT, DIR_RT, DIR_DN, DIR_RT
		}
	},
	{
		3, 3, COLOR_CYAN,
		{
			DIR_UP, DIR_DN, DIR_LT, DIR_DN
		}
	},
/* shapes #5 & #6:		'S' shape */
	{
		6, 6, COLOR_RED,
		{
			DIR_RT, DIR_LT, DIR_DN, DIR_LT
		}
	},
	{
		5, 5, COLOR_RED,
		{
			DIR_UP, DIR_DN, DIR_RT, DIR_DN
		}
	},
/* shapes #7, #8, #9, #10:	'J' shape */
	{
		8, 10, COLOR_MAGENTA,
		{
			DIR_RT, DIR_LT, DIR_LT, DIR_UP
		}
	},
	{
		9, 7, COLOR_MAGENTA,
		{
			DIR_UP, DIR_DN, DIR_DN, DIR_LT
		}
	},
	{
		10, 8, COLOR_MAGENTA,
		{
			DIR_LT, DIR_RT, DIR_RT, DIR_DN
		}
	},
	{
		7, 9, COLOR_MAGENTA,
		{
			DIR_DN, DIR_UP, DIR_UP, DIR_RT
		}
	},
/* shapes #11, #12, #13, #14:	'L' shape */
	{
		12, 14, COLOR_YELLOW,
		{
			DIR_RT, DIR_LT, DIR_LT, DIR_DN
		}
	},
	{
		13, 11, COLOR_YELLOW,
		{
			DIR_UP, DIR_DN, DIR_DN, DIR_RT
		}
	},
	{
		14, 12, COLOR_YELLOW,
		{
			DIR_LT, DIR_RT, DIR_RT, DIR_UP
		}
	},
	{
		11, 13, COLOR_YELLOW,
		{
			DIR_DN, DIR_UP, DIR_UP, DIR_LT
		}
	},
/* shapes #15, #16, #17, #18:	'T' shape */
	{
		16, 18, COLOR_WHITE,
		{
			DIR_UP, DIR_DN, DIR_LT, DIR_RT2
		}
	},
	{
		17, 15, COLOR_WHITE,
		{
			DIR_LT, DIR_RT, DIR_UP, DIR_DN2
		}
	},
	{
		18, 16, COLOR_WHITE,
		{
			DIR_DN, DIR_UP, DIR_RT, DIR_LT2
		}
	},
	{
		15, 17, COLOR_WHITE,
		{
			DIR_RT, DIR_LT, DIR_DN, DIR_UP2
		}
	}
};

static unsigned char _dirty[SCN_HT], _screen[SCN_WID][SCN_HT];
/*****************************************************************************
*****************************************************************************/
static void draw_block(unsigned x_pos, unsigned y_pos, unsigned char color)
{
	if(x_pos >= SCN_WID)
		x_pos = SCN_WID - 1;
	if(y_pos >= SCN_HT)
		y_pos = SCN_HT - 1;
	color &= 7;

	_screen[x_pos][y_pos] = color;
	_dirty[y_pos] = 1;
}
/*****************************************************************************
*****************************************************************************/
static int detect_block_hit(unsigned x_pos, unsigned y_pos)
{
	return _screen[x_pos][y_pos];
}
/*****************************************************************************
*****************************************************************************/
static void draw_shape(unsigned x_pos, unsigned y_pos, unsigned which_shape)
{
	unsigned i;

	for(i = 0; i < 4; i++)
	{
		draw_block(x_pos, y_pos, _shapes[which_shape].color);
		x_pos += _shapes[which_shape].dir[i].delta_x;
		y_pos += _shapes[which_shape].dir[i].delta_y;
	}
	draw_block(x_pos, y_pos, _shapes[which_shape].color);
}
/*****************************************************************************
*****************************************************************************/
static void erase_shape(unsigned x_pos, unsigned y_pos, unsigned which_shape)
{
	unsigned i;

	for(i = 0; i < 4; i++)
	{
		draw_block(x_pos, y_pos, COLOR_BLACK);
		x_pos += _shapes[which_shape].dir[i].delta_x;
		y_pos += _shapes[which_shape].dir[i].delta_y;
	}
	draw_block(x_pos, y_pos, COLOR_BLACK);
}
/*****************************************************************************
*****************************************************************************/
static int detect_shape_hit(unsigned x_pos, unsigned y_pos,
		unsigned which_shape)
{
	unsigned i;

	for(i = 0; i < 4; i++)
	{
		if(detect_block_hit(x_pos, y_pos))
			return 1;
		x_pos += _shapes[which_shape].dir[i].delta_x;
		y_pos += _shapes[which_shape].dir[i].delta_y;
	}
	if(detect_block_hit(x_pos, y_pos))
		return 1;
	return 0;
}
/*****************************************************************************
*****************************************************************************/
static void init_screen(void)
{
	unsigned x_pos, y_pos;

	for(y_pos = 0; y_pos < SCN_HT; y_pos++)
	{
/* force entire screen to be redrawn */
		_dirty[y_pos] = 1;
		for(x_pos = 1; x_pos < (SCN_WID - 1); x_pos++)
			_screen[x_pos][y_pos] = 0;
/* draw vertical edges of playing field */
		_screen[0][y_pos] = _screen[SCN_WID - 1][y_pos] = COLOR_BLUE;
	}
/* draw horizontal edges of playing field */
	for(x_pos = 0; x_pos < SCN_WID; x_pos++)
		_screen[x_pos][0] = _screen[x_pos][SCN_HT - 1] = COLOR_BLUE;
}
/*****************************************************************************
*****************************************************************************/
static void refresh(void)
{
	unsigned x_pos, y_pos;

	for(y_pos = 0; y_pos < SCN_HT; y_pos++)
	{
		if(!_dirty[y_pos])
			continue;
/* gotoxy(0, y_pos) */
		printf("\x1B[%d;1H", y_pos + 1);
		for(x_pos = 0; x_pos < SCN_WID; x_pos++)
/* 0xDB is a solid rectangular block in the PC character set */
			printf("\x1B[%dm\xDB\xDB", 30 + _screen[x_pos][y_pos]);
		_dirty[y_pos] = 0;
	}
/* reset foreground color to gray */
	printf("\x1B[37m");
	fflush(stdout);
}
/*****************************************************************************
*****************************************************************************/
static void collapse(void)
{
	unsigned char solid_row[SCN_HT], solid_rows;
	int row, col, temp;

/* determine which rows are solidly filled */
	solid_rows = 0;
	for(row = 1; row < SCN_HT - 1; row++)
	{
		temp = 0;
		for(col = 1; col < SCN_WID - 1; col++)
		{
			if(detect_block_hit(col, row))
				temp++;
		}
		if(temp == SCN_WID - 2)
		{
			solid_row[row] = 1;
			solid_rows++;
		}
		else
			solid_row[row] = 0;
	}
	if(solid_rows == 0)
		return;
/* collapse them */
	for(temp = row=SCN_HT - 2; row > 0; row--, temp--)
	{
/* find a solid row */
		while(solid_row[temp])
			temp--;
/* copy it */
		if(temp < 1)
		{
			for(col = 1; col < SCN_WID - 1; col++)
				_screen[col][row] = COLOR_BLACK;
		}
		else
		{
			for(col = 1; col < SCN_WID - 1; col++)
				_screen[col][row] = _screen[col][temp];
		}
		_dirty[row] = 1;
	}
	refresh();
}
/*****************************************************************************
*****************************************************************************/
static unsigned char get_key(void)
{
	static unsigned long timeout = 200000L;
	unsigned char ret_val;

	if(select(0, timeout) != 0)
	{
/* wait up to 200 ms for key */
		timeout = 200000L;
		ret_val = 0;
	}
	else
		(void)read(0, &ret_val, 1);
	return ret_val;
}
/*****************************************************************************
for MinGW32
*****************************************************************************/
#ifdef __WIN32__
int __main(void) { return 0; }
#endif
/*****************************************************************************
*****************************************************************************/
int main(void)
{
	unsigned char fell, new_shape, new_x, new_y;
	unsigned char shape = 0, x = 0, y = 0;
	unsigned char key;

/* re-seed the random number generator */
	srand((unsigned long)time(NULL));
/* turn off keyboard input buffering */
	(void)ioctl(0, 0, 1);
/* banner screen */
	printf("\x1B[2J""\x1B[1;%dH""TETRIS by Alexei Pazhitnov",
		SCN_WID * 2 + 2);
	printf("\x1B[2;%dH""Software by Chris Giese", SCN_WID * 2 + 2);
	printf("\x1B[4;%dH""'1' and '2' rotate shape", SCN_WID * 2 + 2);
	printf("\x1B[5;%dH""Arrow keys move shape", SCN_WID * 2 + 2);
	printf("\x1B[6;%dH""Esc or Q quits", SCN_WID * 2 + 2);

NEW:	printf("\x1B[9;%dH""Press any key to begin", SCN_WID * 2 + 2);
	fflush(stdout);
/* await key pressed */
	(void)read(0, &key, 1);
/* erase banner */
	printf("\x1B[8;%dH""                      ", SCN_WID * 2 + 2);
	printf("\x1B[9;%dH""                      ", SCN_WID * 2 + 2);
	init_screen();
	goto FOO;

	while(1)
	{
		fell = 0;
		new_shape = shape;
		new_x = x;
		new_y = y;
		key = get_key();
		if(key == 0)
		{
			new_y++;
			fell = 1;
		}
		else
		{
			if(key == 'q' || key == 'Q' || key == 27)
				//break;
				goto FIN;
			if(key == '1')
				new_shape = _shapes[shape].plus_90;
			else if(key == '2')
				new_shape = _shapes[shape].minus_90;
			else if(key == KEY_LFT)
			{
				if(x > 0)
					new_x = x - 1;
			}
			else if(key == KEY_RT)
			{
				if(x < SCN_WID - 1)
					new_x = x + 1;
			}
/*			else if(key == KEY_UP)
			{
				if(y > 0)
					new_y = y - 1; 	cheat
			} */
			else if(key == KEY_DN)
			{
				if(y < SCN_HT - 1)
					new_y = y + 1;
			}
			fell = 0;
		}
/* if nothing has changed, skip the bottom half of this loop */
		if(new_x == x && new_y == y && new_shape == shape)
			continue;
/* otherwise, erase old shape from the old pos'n */
		erase_shape(x, y, shape);
/* hit anything? */
		if(detect_shape_hit(new_x, new_y, new_shape) == 0)
		{
/* no, update pos'n */
			x = new_x;
			y = new_y;
			shape = new_shape;
		}
/* yes -- did the piece hit something while falling on its own? */
		else if(fell)
		{
/* yes, draw it at the old pos'n... */
			draw_shape(x, y, shape);
/* ... and spawn new shape */
FOO:			y = 3;
			x = SCN_WID / 2;
			shape = rand();
/* debug to get rid of "invisible" (black) shapes */
printf("\x1B[24;0H""shape=%d, shape%%19=%d   ", shape, shape % 19);
shape %= 19;
if(shape > 18) { shape = 18; printf("too big!  "); }
fflush(stdout);
			collapse();
/* if newly spawned shape hits something, game over */
			if(detect_shape_hit(x, y, shape))
FIN:			{
				printf("\x1B[8;%dH""\x1B[37;40;1m"
					"       GAME OVER""\x1B[0m",
					SCN_WID * 2 + 2);
				goto NEW;
			}
		}
/* hit something because of user movement/rotate OR no hit: just redraw it */
		draw_shape(x, y, shape);
		refresh();
	}
/* turn on keyboard input buffering */
	(void)ioctl(0, 0, 0);
	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -