matrix_websocket_2023_18x18.../tetris.h

533 lines
12 KiB
C

/* TETRIS */
uint8_t last_leds[768*3];
int last_led_count = 768;
// First dimension: which shape
// Second dimension: which rotation, + color
// Third & fourth dimensions: rows and columns of shape
bool shapetypes[7][5][4][4] = {
{
// Line of four
{
{ 0, 0, 0, 0 },
{ 1, 1, 1, 1 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 1, 1, 1, 1 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 }
},
{
{1}, {1}, {0}
}
},
{
// S-shape (orientation 1)
{
{ 0, 0, 0, 0 },
{ 1, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 1, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{0}, {0}, {1}
}
},
{
// S-shape (orientation 2)
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 0 },
{ 1, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 0 },
{ 1, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{1}, {0}, {0}
}
},
{
// T-piece
{
{ 0, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 1, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 1, 1, 1, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{1}, {1}, {1}
}
},
{
// L-piece (orientation 1)
{
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 1, 1, 1, 0 },
{ 1, 0, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 1, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 0, 1, 0 },
{ 1, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{0}, {1}, {0}
}
},
{
// L-piece (orientation 2)
{
{ 0, 0, 1, 0 },
{ 0, 0, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 1, 1 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 1, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 1 },
{ 0, 0, 0, 1 },
{ 0, 0, 0, 0 }
},
{
{0}, {1}, {1}
}
},
{
// Cube
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 1, 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, 1, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{1}, {0}, {1}
}
}
};
/* SOMEBRICKS: Position, Type and Rotation of current piece (array index = player) */
/* number of players */
int players=2;
/* field position */
int p_field_pos[2][2] = {{2,2},{20,2}};
/* set players current shape xy-position */
int set_x[2]={3,3};
int set_y[2]={0,0};
/* set players current shapetype & rotation */
int current_btype[2]={0,1};
int current_brot[2]={0,0};
/* Somebricks Functions */
void init_lights() {
int arrsize = last_led_count*3;
int i;
int x;
int y;
int idx = 0;
for (int led=0;led<last_led_count;led++) {
x = lookup[led][0];
y = lookup[led][1];
last_leds[idx] = 0;
last_leds[idx+1] = 0;
last_leds[idx+2] = 0;
idx+=3;
}
}
void update_stones() {
/* Position in grid */
int field_x;
int field_y;
int light_i;
/* Walk piece-array, draw pixels */
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
/* Check active pixels */
for (int p=0; p<players; p++) {
if (shapetypes[current_btype[p]][current_brot[p]][i][j] == 1) {
/* set xy for current active pixel */
field_x=p_field_pos[p][0]+set_x[p]+j;
field_y=p_field_pos[p][1]+set_y[p]+i;
/* check boundaries */
if (field_x<32 && field_x>=0 && field_y<24 && field_y>=0) {
light_i = lookup_yx[field_y][field_x];
/* set rgb of pieces separately */
if (shapetypes[current_btype[p]][4][0][0]==1) { last_leds[light_i*3] = 100; } else { last_leds[light_i*3] = 0; }
if (shapetypes[current_btype[p]][4][1][0]==1) { last_leds[light_i*3+1] = 100; } else { last_leds[light_i*3+1] = 0; }
if (shapetypes[current_btype[p]][4][2][0]==1) { last_leds[light_i*3+2] = 100; } else { last_leds[light_i*3+2] = 0; }
}
}
}
}
}
}
void clear_lines(int player_id) {
int stones_in_line;
int pixel_value;
int light_int;
int light_int_old;
int field_newx;
int field_newy;
for (int j=p_field_pos[player_id][1]+19; j>p_field_pos[player_id][1]; j--) {
/* Count stones in line */
stones_in_line=0;
for (int i=p_field_pos[player_id][0]; i<p_field_pos[player_id][0]+10; i++) {
light_int = lookup_yx[j][i];
pixel_value=last_leds[light_int*3+0]+last_leds[light_int*3+1]+last_leds[light_int*3+2];
if (pixel_value>99) {
stones_in_line++;
}
}
/* Found complete line */
if (stones_in_line==10) {
/* Move down everything by 1 line */
for (int y=j; y>p_field_pos[player_id][1]; y--) {
for (int x=p_field_pos[player_id][0]; x<10+p_field_pos[player_id][0]; x++) {
light_int = lookup_yx[y][x];
if ((y-1)>=0) {
light_int_old = lookup_yx[y-1][x];
last_leds[light_int*3+0]=last_leds[(light_int_old)*3+0];
last_leds[light_int*3+1]=last_leds[(light_int_old)*3+1];
last_leds[light_int*3+2]=last_leds[(light_int_old)*3+2];
}
}
}
/* Set index to last line */
j++;
/* Change Enemy Field - Move up everything by 1 line */
for (int p=0; p<players; p++) {
if (p != player_id) {
/* Remove current position */
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
if (shapetypes[current_btype[p]][current_brot[p]][i][j] == 1) {
field_newx=p_field_pos[p][0]+set_x[p]+j;
field_newy=p_field_pos[p][1]+set_y[p]+i;
light_int = lookup_yx[field_newy][field_newx];
last_leds[light_int*3+0]=0;
last_leds[light_int*3+1]=0;
last_leds[light_int*3+2]=0;
}
}
}
/* Move all up */
for (int y=p_field_pos[p][1]; y<p_field_pos[p][1]+19; y++) {
for (int x=p_field_pos[p][0]; x<10+p_field_pos[p][0]; x++) {
light_int = lookup_yx[y][x];
if ((y+1)<p_field_pos[p][1]+20) {
light_int_old = lookup_yx[y+1][x];
last_leds[light_int*3+0]=last_leds[(light_int_old)*3+0];
last_leds[light_int*3+1]=last_leds[(light_int_old)*3+1];
last_leds[light_int*3+2]=last_leds[(light_int_old)*3+2];
}
}
}
/* Add a random line */
for (int x=p_field_pos[p][0]; x<10+p_field_pos[p][0]; x++) {
light_int = lookup_yx[p_field_pos[p][1]+19][x];
last_leds[light_int*3+1]=0;
if (rand()%10<3) {
last_leds[light_int*3]=0;
} else {
last_leds[light_int*3]=100;
}
last_leds[light_int*3+2]=0;
}
}
}
}
}
update_stones();
}
/* fix player_id's current stone in position, create new */
void merge_stone(int player_id) {
int field_newx;
int field_newy;
int light_int;
/* Place current position */
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
if (shapetypes[current_btype[player_id]][current_brot[player_id]][i][j] == 1) {
field_newx=p_field_pos[player_id][0]+set_x[player_id]+j;
field_newy=p_field_pos[player_id][1]+set_y[player_id]+i;
light_int = lookup_yx[field_newy][field_newx];
if (shapetypes[current_btype[player_id]][4][0][0] == 1) { last_leds[light_int*3] = 100; } else { last_leds[light_int*3] = 0; }
if (shapetypes[current_btype[player_id]][4][1][0] == 1) { last_leds[light_int*3+1] = 100; } else { last_leds[light_int*3+1] = 0; }
if (shapetypes[current_btype[player_id]][4][2][0] == 1) { last_leds[light_int*3+2] = 100; } else { last_leds[light_int*3+2] = 0; }
}
}
}
if (set_y[player_id]<1) {
init_lights();
}
/* set new piece position */
set_y[player_id]=0;
current_btype[player_id]=rand()%7;
current_brot[player_id]=rand()%4;
set_x[player_id]=3;
clear_lines(player_id);
}
/* check if player_id's next shapemove is possible */
/* returns false when move is not possible */
bool check_movement(int player_id, int x, int y, int rot) {
/* var for current pixel */
int field_newx;
int field_newy;
int light_int;
/* XY Offset for 4x4 shape field */
int temp_set_x=set_x[player_id]+x;
int temp_set_y=set_y[player_id]+y;
/* current rotation */
int temp_brot=(current_brot[player_id]+rot)%4;
int pixel_value;
/* Remove current shape position */
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
/* player_id's current shape and current rotation */
if (shapetypes[current_btype[player_id]][current_brot[player_id]][i][j] == 1) {
field_newx=p_field_pos[player_id][0]+set_x[player_id]+j;
field_newy=p_field_pos[player_id][1]+set_y[player_id]+i;
light_int = lookup_yx[field_newy][field_newx];
/* set pixels to 0 */
last_leds[light_int*3+0]=0;
last_leds[light_int*3+1]=0;
last_leds[light_int*3+2]=0;
}
}
}
/* Check future position */
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
if (shapetypes[current_btype[player_id]][temp_brot][i][j] == 1) {
field_newx=p_field_pos[player_id][0]+temp_set_x+j;
field_newy=p_field_pos[player_id][1]+temp_set_y+i;
if (field_newx>=0 && field_newx<32 && field_newy>=0 && field_newy<22) {
light_int = lookup_yx[field_newy][field_newx];
pixel_value=last_leds[light_int*3+0]+last_leds[light_int*3+1]+last_leds[light_int*3+2];
int p_min_x = p_field_pos[player_id][0];
int p_min_y = p_field_pos[player_id][1];
int p_max_x = p_field_pos[player_id][0]+9;
int p_max_y = p_field_pos[player_id][1]+19;
/* collision */
if (field_newx>p_max_x || field_newx<p_min_x || field_newy>p_max_y || field_newy<p_min_y || pixel_value > 99) {
if (y==1) {
merge_stone(player_id);
}
update_stones();
return false;
}
} else {
/* piece at the lowest point -> merge */
if (y==1) {
merge_stone(player_id);
}
update_stones();
return false;
}
}
}
}
/* Place future position (eventually will not be reached) */
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
if (shapetypes[current_btype[player_id]][temp_brot][i][j] == 1) {
field_newx=p_field_pos[player_id][0]+temp_set_x+j;
field_newy=p_field_pos[player_id][1]+temp_set_y+i;
light_int = lookup_yx[field_newy][field_newx];
if (shapetypes[current_btype[player_id]][4][0][0]==1) { last_leds[light_int*3] = 100; } else { last_leds[light_int*3] = 0; }
if (shapetypes[current_btype[player_id]][4][1][0]==1) { last_leds[light_int*3+1] = 100; } else { last_leds[light_int*3+1] = 0; }
if (shapetypes[current_btype[player_id]][4][2][0]==1) { last_leds[light_int*3+2] = 100; } else { last_leds[light_int*3+2] = 0; }
}
}
}
set_x[player_id] = temp_set_x;
set_y[player_id] = temp_set_y;
current_brot[player_id] = temp_brot;
update_stones();
return true;
}