From 4c090ccbe392618ef0fad1a374107e0f71c997ec Mon Sep 17 00:00:00 2001 From: Matthias Rupp Date: Sun, 6 Feb 2022 21:51:33 +0100 Subject: [PATCH] Initial --- .gitignore | 6 + Makefile | 20 +++ main.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++++++++ qr.png | Bin 0 -> 6235 bytes 4 files changed, 416 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 main.c create mode 100644 qr.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2c4b751 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.out +*.a +*.s +*.o +main +.vscode/ \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2387ecb --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ + +default: qr + +qr: main + cat main | qrencode -8 -o qr.png + +main: main.c + clang -s -Os \ + -nostdlib \ + -ffreestanding \ + -fno-stack-protector \ + -fno-unwind-tables \ + -fno-asynchronous-unwind-tables \ + -fomit-frame-pointer \ + -ffunction-sections \ + -fdata-sections \ + -Wl,--gc-sections \ + -static \ + -z noseparate-code \ + -o main main.c \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..67b79de --- /dev/null +++ b/main.c @@ -0,0 +1,390 @@ +// No headers or standardlib, we have to define constants ourselfes +#define O_RDONLY 0x0 +#define O_NONBLOCK 0x800 + +// No libc either - defining all systemcalls by hand +#define exit(code) asm("int $0x80;" ::"a"(1), "b"(code)) + +#define write(fd, str, len) asm volatile("int $0x80" ::"a"(4), "b"(fd), "c"(str), "d"(len) \ + : "memory") + +// Very dirty hack +int read_result; + +#define read(fd, buf, len) asm volatile("int $0x80" \ + : "=&a"(read_result) \ + : "a"(3), "b"(fd), "c"(buf), "d"(len) \ + : "memory") + +#define ioctl(fno, code, data) asm volatile("int $0x80" ::"a"(54), "b"(fno), "c"(code), "d"(data) \ + : "memory") + +#define fcntl(fno, code, data) asm volatile("int $0x80" ::"a"(55), "b"(fno), "c"(code), "d"(data) \ + : "memory") + +#define open(fno, path, flags) asm volatile("int $0x80" \ + : "=&a"(fno) \ + : "a"(5), "b"(path), "c"(flags) \ + : "memory") + +#define close(fd) asm volatile("int $0x80" ::"a"(6), "b"(fd) \ + : "memory") + +#define nanosleep(timespec) asm volatile("int $0x80" ::"a"(162), "b"(timespec), "c"(0) \ + : "memory") + +// Useful macros +#define clear() write(1, "\e[1;1H\e[2J", 11) +#define static_print(text) write(1, text, sizeof(text)) +#define print(text, len) write(1, text, len) + +// Math stuff +#define abs(expr) (expr >= 0) ? (expr) : -(expr) + +// Sleep function +unsigned timespec[2]; + +void sleep_ms(unsigned long nsecs) +{ + timespec[0] = 0; + timespec[1] = nsecs * 1000000L; + nanosleep(timespec); +} + +// Set console mode to raw (in order to read stdin nonblocking) +char ioctlbuf[36]; + +void raw_console() +{ + // Non-blocking stdin + fcntl(0, 4, O_RDONLY | O_NONBLOCK); + + // Raw Terminal + ioctl(0, 0x5401, ioctlbuf); + ioctlbuf[12] &= !0x00000002; + ioctl(0, 0x5402, ioctlbuf); +} + +// Simple function for generating random bytes +int fd; + +void rand(char *buf, int amount) +{ + open(fd, "/dev/random", O_RDONLY); + read(fd, buf, amount); + close(fd); +} + +/* + 2 Bytes per Block: + + 0 1 0 0 + 0 1 1 0 -> Byte 1 = 0 1 0 0 0 1 1 0 + 0 0 1 0 + 0 0 0 0 -> Byte 2 = 0 0 1 0 0 0 0 0 +*/ + +int blocks[] = { + // # + // ## + // # + 0b0100011000100000, + // ## + // ## + 0b0000011001100000, + // # + // # + // # + // # + 0b0100010001000100, + // # + // ### + 0b0100111000000000}; + +#define N_BLOCKS 4 + +int read_block(int type, int x, int y, int rotation) +{ + switch (rotation) + { + case 0: + return (blocks[type] >> (y * 4 + x)) & 1; + case 1: + return (blocks[type] >> (x * 4 + y)) & 1; + case 2: + return (blocks[type] >> ((4 - y) * 4 + x)) & 1; + case 3: + return (blocks[type] >> ((4 - x) * 4 + y)) & 1; + } + + return 0; +} + +#define GAMESIZE 15 +#define BLK_WALL 1 +#define BLK_BLOCK 2 +#define BLK_FALLING 3 + +// [y][x] +char field[GAMESIZE][GAMESIZE]; + +void copy_row(char *src, char *dest) +{ + for (int i = 0; i < GAMESIZE; i++) + dest[i] = src[i]; +} + +// Currently falling block +struct +{ + int x; + int y; + int type; + int rotation; + + int move_request; + int rotation_request; +} current_block; + +char randbuf[2]; + +void spawn_block() +{ + rand(randbuf, 2); + + current_block.type = abs(randbuf[0] % N_BLOCKS); + current_block.x = abs(randbuf[1] % (GAMESIZE - 6)) + 1; + current_block.y = 1; +} + +char linebuf[GAMESIZE + 1]; + +void draw_game() +{ + for (int y = 0; y < GAMESIZE; y++) + { + for (int x = 0; x < GAMESIZE; x++) + { + switch (field[y][x]) + { + case BLK_BLOCK: + case BLK_WALL: + linebuf[x] = '#'; + break; + case BLK_FALLING: + linebuf[x] = '+'; + break; + default: + linebuf[x] = ' '; + } + } + linebuf[GAMESIZE] = '\n'; + print(linebuf, GAMESIZE + 1); + } +} + +void rotate_block_if_possible() +{ + + int next_rotation = (current_block.rotation + 1) % 4; + + for (int y = 0; y < 4; y++) + { + for (int x = 0; x < 4; x++) + { + int obstacle = field[y + current_block.y][current_block.x + x]; + + if (read_block(current_block.type, x, y, next_rotation) && (obstacle == BLK_BLOCK || obstacle == BLK_WALL)) + // Goto saves a few instructions here + goto impossible; + } + } + + current_block.rotation = next_rotation; + +impossible: + return; +} + +void move_sideways_if_possible(int increment) +{ + int nextX = current_block.x + increment; + + for (int y = 0; y < 4; y++) + { + for (int x = 0; x < 4; x++) + { + int obstacle = field[y + current_block.y][nextX + x]; + + if (read_block(current_block.type, x, y, current_block.rotation) && (obstacle == BLK_BLOCK || obstacle == BLK_WALL)) + // Goto saves a few instructions here + goto impossible; + } + } + + current_block.x = nextX; + +impossible: + return; +} + +int move_block(int move_down) +{ + int can_move = 1; + + // Remove block from current position + if (current_block.y != 0) + { + for (int y = 0; y < 4; y++) + { + for (int x = 0; x < 4; x++) + { + if (read_block(current_block.type, x, y, current_block.rotation)) + { + field[current_block.y + y][current_block.x + x] = 0; + + // Can this block fall further down? + + char below = field[current_block.y + y + 1][current_block.x + x]; + if (below == BLK_BLOCK || below == BLK_WALL) + { + can_move = 0; + } + } + } + } + } + + move_sideways_if_possible(current_block.move_request); + if (current_block.rotation_request) + rotate_block_if_possible(); + + if (can_move && move_down) + current_block.y++; + + // Add block to next position + for (int y = 0; y < 4; y++) + { + for (int x = 0; x < 4; x++) + { + if (read_block(current_block.type, x, y, current_block.rotation)) + { + if (can_move) + field[current_block.y + y][current_block.x + x] = BLK_FALLING; + else + field[current_block.y + y][current_block.x + x] = BLK_BLOCK; + } + } + } + + return can_move; +} + +void delete_rows_if_possible() +{ + + for (int y = 1; y < GAMESIZE - 1; y++) + { + int can_delete = 1; + + for (int x = 1; x < GAMESIZE - 1; x++) + { + if (field[y][x] != BLK_BLOCK) + { + can_delete = 0; + break; + } + } + + if (can_delete) + { + for (int yy = y; yy > 2; yy--) + { + // Copy row[y-1] to row[y] + // We can assume that row[1] is 00000.... or the game would already be lost + copy_row(field[yy - 1], field[yy]); + } + } + } +} + +char keybuf; + +// This is our 'main' function +void _start() +{ + raw_console(); + + // Default field (walls) + for (int i = 0; i < GAMESIZE; i++) + { + field[0][i] = BLK_WALL; + field[GAMESIZE - 1][i] = BLK_WALL; + field[i][0] = BLK_WALL; + field[i][GAMESIZE - 1] = BLK_WALL; + } + + spawn_block(); + + int gamectr = 0; + + // Main loop + for (;;) + { + current_block.move_request = 0; + current_block.rotation_request = 0; + + keybuf = 0; + read(0, &keybuf, 1); + + if (keybuf == 'q') + { + exit(0); + } + + if (keybuf == 'a') + { + current_block.move_request = -1; + } + + if (keybuf == 'd') + { + current_block.move_request = 1; + } + + if (keybuf == 'r') + { + current_block.rotation_request = 1; + } + + // Read remaining keystrokes in buffer + // Bahhhhhh! + while (read_result > 0) + read(0, &keybuf, 1); + + if (!move_block(gamectr % 5 == 0)) + { + // Cant move and y == 1 -> lost game + if (current_block.y <= 1) + { + static_print("You lost"); + + // End here + exit(0); + } + // Spawn new block + spawn_block(); + } + + delete_rows_if_possible(); + + clear(); + static_print("a = left, d = right, w = rotate\n"); + draw_game(); + + sleep_ms(100); + gamectr++; + } + + exit(0); +} diff --git a/qr.png b/qr.png new file mode 100644 index 0000000000000000000000000000000000000000..62ac2a0d596ac4eab25de0de3d9edee8c19a70e5 GIT binary patch literal 6235 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