Changed characters used, added preview of next part, added scoring and fixed some bugs
This commit is contained in:
parent
b26e2e7876
commit
2cd6fafe2e
171
src/main.c
171
src/main.c
|
@ -1,14 +1,20 @@
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
|
#include "convert.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
|
|
||||||
const char* tetromino[7];
|
|
||||||
#define WIDTH 12
|
#define WIDTH 12
|
||||||
#define HEIGHT 18
|
#define HEIGHT 18
|
||||||
#define SCALE 1
|
#define SPEED 20
|
||||||
|
|
||||||
|
const char* tetromino[7];
|
||||||
|
|
||||||
uint8_t field[WIDTH*HEIGHT];
|
uint8_t field[WIDTH*HEIGHT];
|
||||||
uint8_t screen[WIDTH*HEIGHT];
|
uint8_t screen[WIDTH*HEIGHT];
|
||||||
|
|
||||||
|
uint16_t score = 0;
|
||||||
|
|
||||||
|
uint8_t cleared[HEIGHT-1] = {0};
|
||||||
|
|
||||||
void construct_shapes() {
|
void construct_shapes() {
|
||||||
tetromino[0] = "..X."
|
tetromino[0] = "..X."
|
||||||
"..X."
|
"..X."
|
||||||
|
@ -68,7 +74,7 @@ void initialize_field() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t does_piece_fit(uint8_t shape, uint8_t rotation, uint8_t px, uint8_t py) {
|
uint8_t does_piece_fit(uint8_t shape, uint8_t rotation, int8_t px, uint8_t py) {
|
||||||
for (uint8_t y = 0; y < 4; ++y) {
|
for (uint8_t y = 0; y < 4; ++y) {
|
||||||
for (uint8_t x = 0; x < 4; ++x) {
|
for (uint8_t x = 0; x < 4; ++x) {
|
||||||
// Index in piece
|
// Index in piece
|
||||||
|
@ -91,21 +97,25 @@ uint8_t does_piece_fit(uint8_t shape, uint8_t rotation, uint8_t px, uint8_t py)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t next_shape = 0;
|
||||||
uint8_t current_shape = 0;
|
uint8_t current_shape = 0;
|
||||||
uint8_t current_rotation = 0;
|
uint8_t current_rotation = 0;
|
||||||
uint8_t current_x = WIDTH/2;
|
int8_t current_x = WIDTH/2-2;
|
||||||
uint8_t current_y = 0;
|
uint8_t current_y = 0;
|
||||||
|
|
||||||
void new_shape() {
|
void new_shape() {
|
||||||
|
current_shape = next_shape;
|
||||||
do {
|
do {
|
||||||
current_shape = random() & 0x07;
|
next_shape = random() & 0x07;
|
||||||
} while (current_shape == 7);
|
} while (next_shape == 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render() {
|
void render() {
|
||||||
// Copy current state of the field
|
/* Copy current state of the field */
|
||||||
for (uint8_t i = 0; i < WIDTH*HEIGHT; ++i) {
|
for (uint8_t y = 0; y < HEIGHT; ++y) {
|
||||||
screen[i] = field[i];
|
for (uint8_t x = 0; x < WIDTH; ++x) {
|
||||||
|
screen[y*WIDTH + x] = field[y*WIDTH + x];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy current piece to the screen
|
// Copy current piece to the screen
|
||||||
|
@ -119,17 +129,18 @@ void render() {
|
||||||
}
|
}
|
||||||
|
|
||||||
__sfr __at (0x02) cout;
|
__sfr __at (0x02) cout;
|
||||||
void draw() {
|
void draw_part(uint8_t i) {
|
||||||
// Draw the screen
|
if (i == 9) {
|
||||||
put_string("\033[2;2H");
|
|
||||||
for (uint8_t y = 0; y < HEIGHT*SCALE; ++y) {
|
|
||||||
for (uint8_t x = 0; x < WIDTH*SCALE; ++x) {
|
|
||||||
uint8_t i = screen[y/SCALE*WIDTH + x/SCALE];
|
|
||||||
if (i >= 8) {
|
|
||||||
cout = '\033';
|
cout = '\033';
|
||||||
cout = '[';
|
cout = '[';
|
||||||
cout = '0';
|
cout = '0';
|
||||||
cout = 'm';
|
cout = 'm';
|
||||||
|
} else if (i == 8) {
|
||||||
|
cout = '\033';
|
||||||
|
cout = '[';
|
||||||
|
cout = '3';
|
||||||
|
cout = '3';
|
||||||
|
cout = 'm';
|
||||||
} else if (i > 0) {
|
} else if (i > 0) {
|
||||||
cout = '\033';
|
cout = '\033';
|
||||||
cout = '[';
|
cout = '[';
|
||||||
|
@ -137,8 +148,7 @@ void draw() {
|
||||||
cout = 48+i;
|
cout = 48+i;
|
||||||
cout = 'm';
|
cout = 'm';
|
||||||
}
|
}
|
||||||
/* char c = " RGOBMCW=#"[i]; */
|
|
||||||
/* cout = c; */
|
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0:
|
case 0:
|
||||||
cout = ' ';
|
cout = ' ';
|
||||||
|
@ -157,21 +167,77 @@ void draw() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
// Move to the start of the field
|
||||||
|
cout = '\033';
|
||||||
|
cout = '[';
|
||||||
|
cout = '2';
|
||||||
|
cout = ';';
|
||||||
|
cout = '2';
|
||||||
|
cout = 'H';
|
||||||
|
|
||||||
|
// Draw the screen
|
||||||
|
for (uint8_t y = 0; y < HEIGHT; ++y) {
|
||||||
|
for (uint8_t x = 0; x < WIDTH; ++x) {
|
||||||
|
uint8_t i = screen[y*WIDTH + x];
|
||||||
|
draw_part(i);
|
||||||
|
}
|
||||||
cout = '\n';
|
cout = '\n';
|
||||||
cout = '\r';
|
cout = '\r';
|
||||||
cout = ' ';
|
cout = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw next part
|
||||||
|
for (uint8_t y = 0; y < 4; ++y) {
|
||||||
|
cout = '\033';
|
||||||
|
cout = '[';
|
||||||
|
cout = '3' + y;
|
||||||
|
cout = ';';
|
||||||
|
cout = '1';
|
||||||
|
cout = '5';
|
||||||
|
cout = 'H';
|
||||||
|
|
||||||
|
for (uint8_t x = 0; x < 4; ++x) {
|
||||||
|
if (tetromino[next_shape][rotate(x, y, 0)] == 'X') {
|
||||||
|
draw_part(next_shape + 1);
|
||||||
|
} else {
|
||||||
|
draw_part(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cout = '\033';
|
||||||
|
cout = '[';
|
||||||
|
cout = '8';
|
||||||
|
cout = ';';
|
||||||
|
cout = '1';
|
||||||
|
cout = '5';
|
||||||
|
cout = 'H';
|
||||||
|
|
||||||
|
// Print the score
|
||||||
|
uint32_t r = uint16_to_bcd(score);
|
||||||
|
for (uint8_t j = 0; j < 6; ++j) {
|
||||||
|
cout = '0' + ((r >> (20 - j*4)) & 0xF);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cout = '\033';
|
||||||
|
cout = '[';
|
||||||
|
cout = '0';
|
||||||
|
cout = 'm';
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SPEED 2
|
|
||||||
uint8_t counter = SPEED;
|
uint8_t counter = SPEED;
|
||||||
|
|
||||||
__sfr __at (0x1F) status;
|
__sfr __at (0x1F) status;
|
||||||
__sfr __at (0x1E) key;
|
__sfr __at (0x1E) key;
|
||||||
|
__sfr __at (0xFF) debug;
|
||||||
uint8_t loop() {
|
uint8_t loop() {
|
||||||
// Check if a key has been pressed
|
// Check if a key has been pressed
|
||||||
|
uint8_t bonus = 0;
|
||||||
if (status & 1) {
|
if (status & 1) {
|
||||||
uint8_t nx = current_x;
|
int8_t nx = current_x;
|
||||||
uint8_t ny = current_y;
|
uint8_t ny = current_y;
|
||||||
uint8_t nr = current_rotation;
|
uint8_t nr = current_rotation;
|
||||||
// End program on ctrl-c
|
// End program on ctrl-c
|
||||||
|
@ -205,7 +271,10 @@ uint8_t loop() {
|
||||||
|
|
||||||
// Drop the piece
|
// Drop the piece
|
||||||
case 'w':
|
case 'w':
|
||||||
while (does_piece_fit(current_shape, current_rotation, current_x, ++ny + 1));
|
while (does_piece_fit(current_shape, current_rotation, current_x, ++ny + 1)) {
|
||||||
|
bonus++;
|
||||||
|
}
|
||||||
|
counter = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,6 +290,7 @@ uint8_t loop() {
|
||||||
if (does_piece_fit(current_shape, current_rotation, current_x, current_y+1)) {
|
if (does_piece_fit(current_shape, current_rotation, current_x, current_y+1)) {
|
||||||
current_y++;
|
current_y++;
|
||||||
} else {
|
} else {
|
||||||
|
uint8_t cc = 0;
|
||||||
// Copy piece to field
|
// Copy piece to field
|
||||||
for (uint8_t y = 0; y < 4; ++y) {
|
for (uint8_t y = 0; y < 4; ++y) {
|
||||||
for (uint8_t x = 0; x < 4; ++x) {
|
for (uint8_t x = 0; x < 4; ++x) {
|
||||||
|
@ -230,14 +300,62 @@ uint8_t loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uint8_t y = 0; y < 4; ++y) {
|
||||||
|
if (current_y + y < HEIGHT-1) {
|
||||||
|
uint8_t line = 1;
|
||||||
|
for (uint8_t x = 1; x < WIDTH-1; ++x) {
|
||||||
|
if (field[(current_y+y)*WIDTH + x] == 0 || field[(current_y+y)*WIDTH + x] == 8) {
|
||||||
|
line = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (line) {
|
||||||
|
for (uint8_t x = 1; x < WIDTH-1; ++x) {
|
||||||
|
field[(current_y+y)*WIDTH + x] = 8;
|
||||||
|
}
|
||||||
|
cleared[current_y+y] = (SPEED >> 2) + cc + 1;
|
||||||
|
cc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cc) {
|
||||||
|
score += 10*cc*cc + bonus;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cc) {
|
||||||
|
debug = (score >> 8) & 0xFF;
|
||||||
|
debug = score & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
new_shape();
|
new_shape();
|
||||||
current_y = 0;
|
current_y = 0;
|
||||||
current_x = WIDTH/2;
|
current_x = WIDTH/2-2;
|
||||||
current_rotation = 0;
|
current_rotation = 0;
|
||||||
|
|
||||||
|
// Check if the next piece can spawn
|
||||||
|
if (!does_piece_fit(current_shape, current_rotation, current_x, current_y)) {
|
||||||
|
put_string("Game over!\n\r");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
counter = SPEED;
|
counter = SPEED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uint8_t iy = 0; iy < HEIGHT-1; ++iy) {
|
||||||
|
if (cleared[iy]) {
|
||||||
|
cleared[iy]--;
|
||||||
|
|
||||||
|
if (!cleared[iy]) {
|
||||||
|
for (uint8_t x = 1; x < WIDTH-1; ++x) {
|
||||||
|
for (uint8_t y = iy; y > 0; --y) {
|
||||||
|
field[y*WIDTH + x] = field[(y-1)*WIDTH + x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
counter--;
|
counter--;
|
||||||
|
|
||||||
render();
|
render();
|
||||||
|
@ -246,18 +364,17 @@ uint8_t loop() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We do not initialize this in order to get a random seed
|
|
||||||
// We need to make sure that this ends up after most of the other things ram
|
|
||||||
// Otherwise we run the risk of the value being loaded from disk
|
|
||||||
// In which case it is no longer random
|
|
||||||
uint8_t random_seed;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
// Set the seed based on a hardware random number
|
||||||
|
random_set_seed(random_hw());
|
||||||
|
|
||||||
construct_shapes();
|
construct_shapes();
|
||||||
initialize_field();
|
initialize_field();
|
||||||
|
|
||||||
// Set initial shape
|
// Set initial shape
|
||||||
new_shape();
|
new_shape();
|
||||||
|
new_shape();
|
||||||
|
|
||||||
// Clear the screen
|
// Clear the screen
|
||||||
put_string("\033[2J");
|
put_string("\033[2J");
|
||||||
|
|
Loading…
Reference in New Issue
Block a user