Changed characters used, added preview of next part, added scoring and fixed some bugs

This commit is contained in:
Dreaded_X 2021-01-17 16:11:52 +01:00
parent b26e2e7876
commit 2cd6fafe2e

View File

@ -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,59 +129,115 @@ void render() {
} }
__sfr __at (0x02) cout; __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() { void draw() {
// Move to the start of the field
cout = '\033';
cout = '[';
cout = '2';
cout = ';';
cout = '2';
cout = 'H';
// Draw the screen // Draw the screen
put_string("\033[2;2H"); for (uint8_t y = 0; y < HEIGHT; ++y) {
for (uint8_t y = 0; y < HEIGHT*SCALE; ++y) { for (uint8_t x = 0; x < WIDTH; ++x) {
for (uint8_t x = 0; x < WIDTH*SCALE; ++x) { uint8_t i = screen[y*WIDTH + x];
uint8_t i = screen[y/SCALE*WIDTH + x/SCALE]; draw_part(i);
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;
}
} }
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");