From 2cd6fafe2e5931835fd64df6fcacb539accac28f Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Sun, 17 Jan 2021 16:11:52 +0100 Subject: [PATCH] Changed characters used, added preview of next part, added scoring and fixed some bugs --- src/main.c | 223 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 170 insertions(+), 53 deletions(-) diff --git a/src/main.c b/src/main.c index dab350c..dda480f 100644 --- a/src/main.c +++ b/src/main.c @@ -1,14 +1,20 @@ #include "console.h" +#include "convert.h" #include "random.h" -const char* tetromino[7]; #define WIDTH 12 #define HEIGHT 18 -#define SCALE 1 +#define SPEED 20 + +const char* tetromino[7]; uint8_t field[WIDTH*HEIGHT]; uint8_t screen[WIDTH*HEIGHT]; +uint16_t score = 0; + +uint8_t cleared[HEIGHT-1] = {0}; + void construct_shapes() { tetromino[0] = "..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 x = 0; x < 4; ++x) { // 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; } +uint8_t next_shape = 0; uint8_t current_shape = 0; uint8_t current_rotation = 0; -uint8_t current_x = WIDTH/2; +int8_t current_x = WIDTH/2-2; uint8_t current_y = 0; void new_shape() { + current_shape = next_shape; do { - current_shape = random() & 0x07; - } while (current_shape == 7); + next_shape = random() & 0x07; + } while (next_shape == 7); } void render() { - // Copy current state of the field - for (uint8_t i = 0; i < WIDTH*HEIGHT; ++i) { - screen[i] = field[i]; + /* Copy current state of the field */ + for (uint8_t y = 0; y < HEIGHT; ++y) { + for (uint8_t x = 0; x < WIDTH; ++x) { + screen[y*WIDTH + x] = field[y*WIDTH + x]; + } } // Copy current piece to the screen @@ -119,59 +129,115 @@ void render() { } __sfr __at (0x02) cout; +void draw_part(uint8_t i) { + if (i == 9) { + cout = '\033'; + cout = '['; + cout = '0'; + cout = 'm'; + } else if (i == 8) { + cout = '\033'; + cout = '['; + cout = '3'; + cout = '3'; + cout = 'm'; + } else if (i > 0) { + cout = '\033'; + cout = '['; + cout = '9'; + cout = 48+i; + cout = 'm'; + } + + switch (i) { + case 0: + cout = ' '; + break; + + case 8: + cout = 0xCD; + break; + + case 9: + cout = 0xB0; + break; + + default: + cout = 0xDB; + break; + } +} + void draw() { + // Move to the start of the field + cout = '\033'; + cout = '['; + cout = '2'; + cout = ';'; + cout = '2'; + cout = 'H'; + // Draw the screen - 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 = '['; - cout = '0'; - cout = 'm'; - } else if (i > 0) { - cout = '\033'; - cout = '['; - cout = '9'; - cout = 48+i; - cout = 'm'; - } - /* char c = " RGOBMCW=#"[i]; */ - /* cout = c; */ - switch (i) { - case 0: - cout = ' '; - break; - - case 8: - cout = 0xCD; - break; - - case 9: - cout = 0xB0; - break; - - default: - cout = 0xDB; - break; - } + 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 = '\r'; 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; __sfr __at (0x1F) status; __sfr __at (0x1E) key; +__sfr __at (0xFF) debug; uint8_t loop() { // Check if a key has been pressed + uint8_t bonus = 0; if (status & 1) { - uint8_t nx = current_x; + int8_t nx = current_x; uint8_t ny = current_y; uint8_t nr = current_rotation; // End program on ctrl-c @@ -205,7 +271,10 @@ uint8_t loop() { // Drop the piece 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; } @@ -221,6 +290,7 @@ uint8_t loop() { if (does_piece_fit(current_shape, current_rotation, current_x, current_y+1)) { current_y++; } else { + uint8_t cc = 0; // Copy piece to field for (uint8_t y = 0; y < 4; ++y) { 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(); current_y = 0; - current_x = WIDTH/2; + current_x = WIDTH/2-2; 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; } + 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--; render(); @@ -246,18 +364,17 @@ uint8_t loop() { 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() { + // Set the seed based on a hardware random number + random_set_seed(random_hw()); + construct_shapes(); initialize_field(); // Set initial shape new_shape(); + new_shape(); // Clear the screen put_string("\033[2J");