533 lines
12 KiB
C
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;
|
|
}
|