Small block game in C
Commit 77d71a4dea0a
tarball12 files changed+804-684
@@ -1,2 +1,11 @@
1
-tetoris: main.c draw.c logic.c2
- gcc -Wall -Wextra -o tetoris main.c draw.c logic.c1
+CC = gcc2
+CFLAGS = -Wall -Wextra3
+4
+SRC = $(wildcard source/*.c)5
+OBJ = $(SRC:.c=.o)6
+7
+tetoris: $(OBJ)8
+ $(CC) $(CFLAGS) -o $@ $(OBJ)9
+10
+clean:11
+ rm -f $(OBJ) tetoris@@ -1,106 +0,0 @@
1
-#include "main.h"2
-3
-4
-#define RED "\033[38;2;255;0;0m"5
-#define GREEN "\033[38;2;0;255;0m"6
-#define BLUE "\033[38;2;0;0;255m"7
-#define YELLOW "\033[38;2;255;255;0m"8
-#define MAGENTA "\033[38;2;255;0;255m"9
-#define TEAL "\033[38;2;0;255;255m"10
-#define PURPLE "\033[38;2;127;0;255m"11
-#define WHITE "\033[38;2;255;255;255m"12
-13
-14
-void draw_color (tetromino current_square) {15
- switch (current_square) {16
- case I_PIECE:17
- printf("%s", RED);18
- break;19
- case J_PIECE:20
- printf("%s", GREEN);21
- break;22
- case L_PIECE:23
- printf("%s", BLUE);24
- break;25
- case O_PIECE:26
- printf("%s", YELLOW);27
- break;28
- case S_PIECE:29
- printf("%s", MAGENTA);30
- break;31
- case T_PIECE:32
- printf("%s", TEAL);33
- break;34
- case Z_PIECE:35
- printf("%s", PURPLE);36
- break;37
- default:38
- break;39
- } 40
-}41
-42
-43
-void draw_board(piece current_piece, bool *blink, bool is_piece) {44
-45
- uint8_t i, j;46
-47
-48
- printf("\033[H");49
- printf("┏");50
- for (i = 0; i < FIELD_WIDTH; i++)51
- printf("━━");52
- printf("┓\n");53
-54
-55
- for (i = 0; i < FIELD_HEIGHT; i++) {56
- 57
- printf("┃");58
-59
- for (j = 0; j < FIELD_WIDTH; j++) {60
- 61
- if ( blink != NULL && blink[i]) {62
- 63
- printf("%s", WHITE);64
- } else {65
-66
-67
- tetromino current_square = current_square = playfield[i][j + BORDER_WIDTH];68
-69
- if (is_piece) {70
-71
- uint8_t k, l;72
- 73
- for (k = 0; k < current_piece.size; k++) {74
- for (l = 0; l < current_piece.size; l++) {75
-76
- coord points = find_direction(current_piece, l, k);77
-78
- if (79
- i == current_piece.y + points.y && 80
- j == current_piece.x + points.x - BORDER_WIDTH && 81
- current_piece.piece[k][l]) 82
- {83
- current_square = current_piece.name;84
- }85
- }86
- }87
- }88
-89
- if (current_square <= EMPTY || current_square > Z_PIECE) {90
- printf("· ");91
- continue;92
- }93
-94
- draw_color(current_square);95
- }96
- 97
- printf("██\033[0m");98
- }99
- printf("┃\n");100
- }101
-102
- printf("┗");103
- for (i = 0; i < FIELD_WIDTH; i++)104
- printf("━━");105
- printf("┛\n");106
-}@@ -1,224 +0,0 @@
1
-#include "main.h"2
-3
-void init_field() {4
- uint8_t i, j;5
- for(i = 0; i < FULL_HEIGHT; i++) {6
- for (j = 0; j < FULL_WIDTH; j++) {7
- 8
- if (9
- j < BORDER_WIDTH || 10
- j >= FULL_WIDTH - BORDER_WIDTH ||11
- i >= FULL_HEIGHT - BORDER_WIDTH12
- ) {13
- playfield[i][j] = TETRIS; 14
- } else {15
- playfield[i][j] = EMPTY;16
- }17
- }18
- }19
-}20
-21
-22
-piece init_piece(tetromino new_piece) {23
- 24
- piece current_piece = {};25
-26
- current_piece.name = new_piece;27
-28
- current_piece.y = TOP_GAP;29
- current_piece.rotation = TOP;30
-31
-32
- switch (current_piece.name) {33
- case I_PIECE:34
- current_piece.size = 4;35
- current_piece.positions = 2;36
-37
- current_piece.piece[0][0] = false;38
- current_piece.piece[0][1] = false;39
- current_piece.piece[0][2] = false;40
- current_piece.piece[0][3] = false;41
-42
- current_piece.piece[1][0] = true;43
- current_piece.piece[1][1] = true;44
- current_piece.piece[1][2] = true;45
- current_piece.piece[1][3] = true;46
- 47
- current_piece.piece[2][0] = false;48
- current_piece.piece[2][1] = false;49
- current_piece.piece[2][2] = false;50
- current_piece.piece[2][3] = false;51
- 52
- current_piece.piece[3][0] = false;53
- current_piece.piece[3][1] = false;54
- current_piece.piece[3][2] = false;55
- current_piece.piece[3][3] = false;56
- 57
- current_piece.y = 0;58
-59
- break;60
-61
- case J_PIECE:62
- current_piece.size = 3;63
- current_piece.positions = 4;64
- 65
- current_piece.piece[0][0] = true;66
- current_piece.piece[0][1] = false;67
- current_piece.piece[0][2] = false;68
- 69
- current_piece.piece[1][0] = true;70
- current_piece.piece[1][1] = true;71
- current_piece.piece[1][2] = true;72
-73
- current_piece.piece[2][0] = false;74
- current_piece.piece[2][1] = false;75
- current_piece.piece[2][2] = false;76
-77
- break;78
-79
- case L_PIECE:80
- current_piece.size = 3;81
- current_piece.positions = 4;82
- 83
- current_piece.piece[0][0] = false;84
- current_piece.piece[0][1] = false;85
- current_piece.piece[0][2] = true;86
- 87
- current_piece.piece[1][0] = true;88
- current_piece.piece[1][1] = true;89
- current_piece.piece[1][2] = true;90
-91
- current_piece.piece[2][0] = false;92
- current_piece.piece[2][1] = false;93
- current_piece.piece[2][2] = false;94
-95
- break;96
-97
- case O_PIECE:98
- current_piece.size = 2;99
- current_piece.positions = 1;100
- 101
- current_piece.piece[0][0] = true;102
- current_piece.piece[0][1] = true;103
-104
- current_piece.piece[1][0] = true;105
- current_piece.piece[1][1] = true;106
- 107
- break;108
-109
- case S_PIECE:110
- current_piece.size = 3;111
- current_piece.positions = 2;112
- 113
- current_piece.piece[0][0] = false;114
- current_piece.piece[0][1] = true;115
- current_piece.piece[0][2] = true;116
-117
- current_piece.piece[1][0] = true;118
- current_piece.piece[1][1] = true;119
- current_piece.piece[1][2] = false;120
- 121
- current_piece.piece[2][0] = false;122
- current_piece.piece[2][1] = false;123
- current_piece.piece[2][2] = false;124
-125
- break;126
-127
- case T_PIECE:128
- current_piece.size = 3;129
- current_piece.positions = 4;130
- 131
- current_piece.piece[0][0] = false;132
- current_piece.piece[0][1] = true;133
- current_piece.piece[0][2] = false;134
- 135
- current_piece.piece[1][0] = true;136
- current_piece.piece[1][1] = true;137
- current_piece.piece[1][2] = true;138
- 139
- current_piece.piece[2][0] = false;140
- current_piece.piece[2][1] = false;141
- current_piece.piece[2][2] = false;142
-143
- break;144
- case Z_PIECE:145
- current_piece.size = 3;146
- current_piece.positions = 2;147
- 148
- current_piece.piece[0][0] = true;149
- current_piece.piece[0][1] = true;150
- current_piece.piece[0][2] = false;151
-152
- current_piece.piece[1][0] = false;153
- current_piece.piece[1][1] = true;154
- current_piece.piece[1][2] = true;155
-156
- current_piece.piece[2][0] = false;157
- current_piece.piece[2][1] = false;158
- current_piece.piece[2][2] = false;159
-160
- break;161
- default:162
- perror("Fuck you\n");163
- break;164
- }165
-166
- current_piece.x = ((FULL_WIDTH >> 1) - (current_piece.size >> 1));167
-168
- return current_piece;169
-}170
-171
-172
-173
-coord find_direction(piece current_piece, uint8_t x, uint8_t y) {174
-175
- coord points = {176
- x,177
- y178
- };179
-180
- switch (current_piece.rotation) {181
- case TOP:182
- /*183
- x = k;184
- y = j;185
- */186
- break;187
- case RIGHT:188
- points.x = y;189
- points.y = current_piece.size - (x + 1);190
- break;191
- case BOTTOM:192
- points.x = current_piece.size - (x + 1);193
- points.y = current_piece.size - (y + 1);194
- break;195
- case LEFT:196
- points.x = current_piece.size - (y + 1);197
- points.y = x;198
- break;199
- }200
-201
- return points;202
-}203
-204
-205
-bool valid_position(piece current_piece) {206
-207
- uint8_t i, j;208
-209
- for(i = 0; i < current_piece.size; i++) {210
- for (j = 0; j < current_piece.size; j++) {211
-212
- coord points = find_direction(current_piece, j, i);213
-214
- if (215
- current_piece.piece[i][j] &&216
- playfield[current_piece.y + points.y][current_piece.x + points.x] != EMPTY217
- ) {218
- return false;219
- }220
- }221
- }222
-223
- return true;224
-}@@ -1,277 +0,0 @@
1
-#include "main.h"2
-3
-4
-tetromino playfield[FULL_HEIGHT][FULL_WIDTH] = {};5
-6
-7
-int main () {8
- 9
-10
- /* Setting up the seed */11
- 12
- srand(time(NULL));13
-14
-15
- /* Setting up terminal with termios */16
- 17
- struct termios old, new;18
-19
- tcgetattr(STDIN_FILENO, &old);20
- new = old;21
-22
- new.c_lflag &= ~(ECHO | ICANON);23
- new.c_cc[VMIN] = 0;24
- new.c_cc[VTIME] = 0;25
-26
- tcsetattr(STDIN_FILENO, TCSANOW, &new);27
-28
- struct winsize init_size, current_size;29
- ioctl(STDOUT_FILENO, TIOCGWINSZ, &init_size);30
- current_size = init_size;31
-32
- printf("\033[?25l\033[?1049h");33
-34
-35
- /* Polling */36
-37
- struct pollfd polling[1];38
-39
- polling[0].fd = 0;40
- polling[0].events = POLLIN;41
-42
-43
- /* Init */44
-45
- init_field();46
-47
- bool blink[FIELD_HEIGHT] = {};48
-49
- bool is_piece = false;50
-51
- piece current_piece = {};52
-53
-54
- /* Game Loop */55
-56
- struct timespec start, current;57
- clock_gettime(CLOCK_MONOTONIC_RAW, &start);58
-59
-60
- uint8_t i;61
- bool is_tetris = false;62
-63
- while (true) {64
-65
- int8_t move = 0;66
- bool down = false;67
- bool draw = false;68
- bool rotate = false;69
-70
- clock_gettime(CLOCK_MONOTONIC_RAW, ¤t);71
-72
- uint64_t time_diff = (current.tv_sec - start.tv_sec) * 1000000000ULL + (current.tv_nsec - start.tv_nsec);73
-74
-75
- /* Take care of the input */76
-77
- int is_poll = poll(polling, 1, 17);78
-79
- if (is_poll > 0 && polling[0].revents & POLLIN) {80
-81
- char buf[10] = {};82
-83
- if (read(STDIN_FILENO, buf, sizeof(buf)) > 0) {84
- if (buf[0] == 'q') {85
- break;86
- }87
-88
- if (buf[0] == '\033' && buf[1] == '[') {89
- 90
- switch (buf[2]) {91
- case 'A':92
- rotate = true;93
- break;94
- case 'B':95
- down = true;96
- break;97
- case 'C':98
- move = 1;99
- break;100
- case 'D':101
- move = -1;102
- break;103
- default:104
- break;105
- }106
- }107
- }108
- }109
-110
-111
- if (is_tetris) {112
-113
- if (time_diff >= FRAME * BLINK && i < 4) { 114
-115
- time_diff -= time_diff % (FRAME * BLINK);116
- start.tv_sec += time_diff / 1000000000ULL;117
- start.tv_nsec += time_diff % 1000000000ULL;118
- 119
- draw_board(current_piece, (i % 2 == 0) ? NULL : blink, is_piece);120
- i++;121
- }122
-123
- if (i == 4) {124
- 125
- int8_t j, k;126
-127
- for (j = 0; j < FIELD_HEIGHT; j++) {128
- if (blink[j]) {129
-130
- for (k = j; k > 0; k--) {131
- int8_t l;132
- 133
- for (l = 0; l < FIELD_WIDTH; l++) {134
- playfield[k][l + BORDER_WIDTH] = playfield[k - 1][l + BORDER_WIDTH];135
- }136
- }137
- }138
- }139
-140
- i = 0;141
- is_tetris = false;142
- }143
-144
- continue;145
- }146
-147
-148
-149
- /* Creates new piece */150
-151
- 152
- if (!is_piece) {153
- current_piece = init_piece((rand() % Z_PIECE) + 1);154
- is_piece = true;155
- draw = true;156
- }157
-158
-159
- /* Move piece */160
-161
- if (move != 0) {162
- if (163
- current_piece.x + move >= 0 && 164
- current_piece.x + move + current_piece.size <= FULL_WIDTH165
- ) {166
- 167
- piece moved_piece = current_piece;168
- moved_piece.x += move;169
-170
- if (valid_position(moved_piece)) {171
- current_piece.x += move;172
- draw = true;173
- }174
- }175
- }176
-177
-178
- /* Piece rotates */179
- 180
- if (rotate && current_piece.positions > 1) {181
- 182
- piece rotated = current_piece;183
-184
- rotated.rotation = (current_piece.rotation + 1) % (current_piece.positions);185
- 186
- if (valid_position(rotated)) {187
- current_piece = rotated;188
- draw = true;189
- }190
- } 191
- 192
-193
- /* Piece falls */194
-195
- if (time_diff >= (FRAME * FALL) || down) {196
- current_piece.y++;197
- 198
- time_diff -= time_diff % (FRAME * FALL);199
- start.tv_sec += time_diff / 1000000000ULL;200
- start.tv_nsec += time_diff % 1000000000ULL;201
- 202
-203
- draw = true;204
- }205
-206
-207
- /* When a piece is stuck */208
-209
- if (!valid_position(current_piece)) {210
-211
- int8_t j, k;212
-213
- for (j = 0; j < current_piece.size; j++) {214
- for (k = 0; k < current_piece.size; k++) {215
- 216
- if (current_piece.piece[j][k]) {217
- 218
- coord solid = find_direction(current_piece, k, j);219
-220
- playfield[current_piece.y - 1 + solid.y][current_piece.x + solid.x] = current_piece.name;221
- }222
- }223
- }224
- is_piece = false;225
- draw = true;226
- }227
-228
-229
- /* Looks if there is a tetris */230
-231
- int8_t j, k;232
-233
- for (j = FIELD_HEIGHT - 1; j >= 0; j--) {234
-235
- uint8_t blocked = 0;236
-237
- for (k = 0; k < FIELD_WIDTH; k++) {238
- if (playfield[j][k + BORDER_WIDTH] != EMPTY)239
- blocked++;240
- }241
-242
- if (blocked == 10) {243
- 244
- blink[j] = true;245
- is_tetris = true; 246
- } else {247
- blink[j] = false;248
- }249
- }250
-251
-252
- /* Looks for game over */253
-254
- for (j = 0; j < FIELD_WIDTH; j++) {255
- if (playfield[TOP_GAP][j + BORDER_WIDTH] > 0) {256
- draw_board(current_piece, NULL, is_piece);257
- sleep(2);258
- printf("\033[2J\033[H");259
- printf("HAHA LOSER\n");260
- sleep(1);261
- goto end;262
- }263
- }264
-265
-266
- if (draw)267
- draw_board(current_piece, NULL, is_piece);268
- }269
-270
-end:271
-272
- printf("\033[?1049l\033[?25h");273
-274
- tcsetattr(STDIN_FILENO, TCSANOW, &old);275
-276
- return 0;277
-}@@ -1,75 +0,0 @@
1
-#ifndef MAIN_C2
-3
-#define MAIN_C4
-5
-#include <stdio.h>6
-#include <stdint.h>7
-#include <stdbool.h>8
-#include <stdlib.h>9
-10
-#include <termios.h>11
-#include <sys/ioctl.h>12
-#include <sys/stat.h>13
-14
-#include <time.h>15
-#include <unistd.h>16
-#include <poll.h>17
-18
-#include <errno.h>19
-20
-21
-#define FIELD_WIDTH 1022
-#define FIELD_HEIGHT 2123
-24
-#define BORDER_WIDTH 225
-#define TOP_GAP 126
-27
-#define FULL_WIDTH (FIELD_WIDTH + BORDER_WIDTH * 2)28
-#define FULL_HEIGHT (FIELD_HEIGHT + BORDER_WIDTH)29
-30
-#define FRAME 1700000031
-32
-#define FALL 5833
-#define BLINK 1234
-35
-typedef enum {36
- EMPTY, I_PIECE, J_PIECE, L_PIECE, O_PIECE, S_PIECE, T_PIECE, Z_PIECE, TETRIS37
-} tetromino;38
-39
-typedef enum {40
- TOP, RIGHT, BOTTOM, LEFT41
-} direction;42
-43
-typedef struct {44
- tetromino name;45
- bool piece[4][4];46
- int8_t x;47
- int8_t y;48
- uint8_t size;49
- direction rotation;50
- uint8_t positions;51
-} piece;52
-53
-typedef struct {54
- int8_t x;55
- int8_t y;56
-} coord;57
-58
-59
-60
-void init_field();61
-62
-void draw_board(piece current_piece, bool *blink, bool is_piece);63
-64
-piece init_piece(tetromino new_piece);65
-66
-coord find_direction(piece current_piece, uint8_t x, uint8_t y);67
- 68
-bool valid_position(piece current_piece);69
-70
-71
-72
-extern tetromino playfield[FULL_HEIGHT][FULL_WIDTH];73
-74
-75
-#endif@@ -0,0 +1,171 @@
1
+#include "main.h"2
+3
+4
+#define RED "\033[38;2;255;0;0m"5
+#define GREEN "\033[38;2;0;255;0m"6
+#define BLUE "\033[38;2;0;0;255m"7
+#define YELLOW "\033[38;2;255;255;0m"8
+#define MAGENTA "\033[38;2;255;0;255m"9
+#define TEAL "\033[38;2;0;255;255m"10
+#define PURPLE "\033[38;2;127;0;255m"11
+#define WHITE "\033[38;2;255;255;255m"12
+13
+14
+void draw_color (tetromino current_square) {15
+ switch (current_square) {16
+ case I_PIECE:17
+ printf("%s", RED);18
+ break;19
+ case J_PIECE:20
+ printf("%s", GREEN);21
+ break;22
+ case L_PIECE:23
+ printf("%s", BLUE);24
+ break;25
+ case O_PIECE:26
+ printf("%s", YELLOW);27
+ break;28
+ case S_PIECE:29
+ printf("%s", MAGENTA);30
+ break;31
+ case T_PIECE:32
+ printf("%s", TEAL);33
+ break;34
+ case Z_PIECE:35
+ printf("%s", PURPLE);36
+ break;37
+ default:38
+ break;39
+ } 40
+}41
+42
+43
+void draw_board(piece current_piece, piece next_piece, bool *blink, bool is_piece) {44
+45
+ int8_t i, j;46
+47
+48
+ printf("\033[H");49
+ printf("┏");50
+ for (i = 0; i < FIELD_WIDTH; i++)51
+ printf("━━");52
+ printf("┓\n");53
+54
+55
+ for (i = 0; i < FIELD_HEIGHT; i++) {56
+ 57
+ printf("┃");58
+59
+ for (j = 0; j < FIELD_WIDTH; j++) {60
+ 61
+ if ( blink != NULL && blink[i]) {62
+ 63
+ printf("%s", WHITE);64
+ } else {65
+66
+67
+ tetromino current_square = playfield[i][j + BORDER_WIDTH];68
+69
+ if (is_piece) {70
+71
+ uint8_t k, l;72
+ 73
+ for (k = 0; k < current_piece.size; k++) {74
+ for (l = 0; l < current_piece.size; l++) {75
+76
+ coord points = find_direction(current_piece, l, k);77
+78
+ if (79
+ i == current_piece.y + points.y && 80
+ j == current_piece.x + points.x - BORDER_WIDTH && 81
+ current_piece.piece[k][l]) 82
+ {83
+ current_square = current_piece.name;84
+ }85
+ }86
+ }87
+ }88
+89
+ if (current_square <= EMPTY || current_square > Z_PIECE) {90
+ printf("· ");91
+ continue;92
+ }93
+94
+ draw_color(current_square);95
+ }96
+ 97
+ printf("██\033[0m");98
+ }99
+ printf("┃\n");100
+ }101
+102
+ printf("┗");103
+ for (i = 0; i < FIELD_WIDTH; i++)104
+ printf("━━");105
+ printf("┛\n");106
+107
+108
+ /* next piece preview */109
+110
+ printf("\033[H");111
+ printf("\033[%iC", FIELD_WIDTH * 2 + 1);112
+ printf("┱──────────┐\n");113
+114
+ for (i = 4; i > 0; i--) {115
+ printf("\033[%iC", FIELD_WIDTH * 2 + 1);116
+ printf("┃");117
+118
+ draw_color(next_piece.name);119
+120
+ for (j = 4; j >= 0; j--) {121
+ 122
+ int8_t y = next_piece.size - i;123
+ int8_t x = next_piece.size - j;124
+ 125
+126
+ if (127
+ y < next_piece.size && x < next_piece.size &&128
+ y >= 0 && x >= 0 &&129
+ next_piece.piece[y][x]130
+ ) {131
+ printf("██");132
+ continue;133
+ }134
+ 135
+ printf(" ");136
+ }137
+138
+ printf("\033[0m│\n");139
+ }140
+141
+ printf("\033[%iC", FIELD_WIDTH * 2 + 1);142
+ printf("┠──────────┘\n");143
+144
+}145
+146
+void draw_pause () {147
+ 148
+ uint8_t i;149
+150
+ printf("\033[H");151
+ printf("\033[%iB", 1 + (FIELD_HEIGHT >> 2));152
+153
+ for (i = 0; i < 3; i++) {154
+155
+ printf("\033[%iC", 1 + (((FIELD_WIDTH * 2 - 7) >> 1)));156
+157
+ switch(i) {158
+ case 0:159
+ printf("╭─────╮");160
+ break;161
+ case 1:162
+ printf("│PAUSE│");163
+ break;164
+ case 2:165
+ printf("╰─────╯");166
+ break;167
+ }168
+169
+ printf("\n");170
+ } 171
+}Binary file not shown.
@@ -0,0 +1,238 @@
1
+#include "main.h"2
+3
+void init_field() {4
+ uint8_t i, j;5
+ for(i = 0; i < FULL_HEIGHT; i++) {6
+ for (j = 0; j < FULL_WIDTH; j++) {7
+ 8
+ if (9
+ j < BORDER_WIDTH || 10
+ j >= FULL_WIDTH - BORDER_WIDTH ||11
+ i >= FULL_HEIGHT - BORDER_WIDTH12
+ ) {13
+ playfield[i][j] = TETRIS; 14
+ } else {15
+ playfield[i][j] = EMPTY;16
+ }17
+ }18
+ }19
+}20
+21
+22
+piece init_piece(tetromino new_piece) {23
+ 24
+ piece current_piece = {};25
+26
+ current_piece.name = new_piece;27
+28
+ current_piece.y = TOP_GAP;29
+ current_piece.rotation = TOP;30
+31
+32
+ switch (current_piece.name) {33
+ case I_PIECE:34
+ current_piece.size = 4;35
+ current_piece.positions = 2;36
+37
+ current_piece.piece[0][0] = false;38
+ current_piece.piece[0][1] = false;39
+ current_piece.piece[0][2] = false;40
+ current_piece.piece[0][3] = false;41
+42
+ current_piece.piece[1][0] = true;43
+ current_piece.piece[1][1] = true;44
+ current_piece.piece[1][2] = true;45
+ current_piece.piece[1][3] = true;46
+ 47
+ current_piece.piece[2][0] = false;48
+ current_piece.piece[2][1] = false;49
+ current_piece.piece[2][2] = false;50
+ current_piece.piece[2][3] = false;51
+ 52
+ current_piece.piece[3][0] = false;53
+ current_piece.piece[3][1] = false;54
+ current_piece.piece[3][2] = false;55
+ current_piece.piece[3][3] = false;56
+ 57
+ current_piece.y = 0;58
+59
+ break;60
+61
+ case J_PIECE:62
+ current_piece.size = 3;63
+ current_piece.positions = 4;64
+ 65
+ current_piece.piece[0][0] = true;66
+ current_piece.piece[0][1] = false;67
+ current_piece.piece[0][2] = false;68
+ 69
+ current_piece.piece[1][0] = true;70
+ current_piece.piece[1][1] = true;71
+ current_piece.piece[1][2] = true;72
+73
+ current_piece.piece[2][0] = false;74
+ current_piece.piece[2][1] = false;75
+ current_piece.piece[2][2] = false;76
+77
+ break;78
+79
+ case L_PIECE:80
+ current_piece.size = 3;81
+ current_piece.positions = 4;82
+ 83
+ current_piece.piece[0][0] = false;84
+ current_piece.piece[0][1] = false;85
+ current_piece.piece[0][2] = true;86
+ 87
+ current_piece.piece[1][0] = true;88
+ current_piece.piece[1][1] = true;89
+ current_piece.piece[1][2] = true;90
+91
+ current_piece.piece[2][0] = false;92
+ current_piece.piece[2][1] = false;93
+ current_piece.piece[2][2] = false;94
+95
+ break;96
+97
+ case O_PIECE:98
+ current_piece.size = 4;99
+ current_piece.positions = 1;100
+ 101
+ current_piece.piece[0][0] = false;102
+ current_piece.piece[0][1] = false;103
+ current_piece.piece[0][2] = false;104
+ current_piece.piece[0][3] = false;105
+ 106
+ current_piece.piece[1][0] = false;107
+ current_piece.piece[1][1] = true;108
+ current_piece.piece[1][2] = true;109
+ current_piece.piece[1][3] = false; 110
+ 111
+ current_piece.piece[2][0] = false;112
+ current_piece.piece[2][1] = true;113
+ current_piece.piece[2][2] = true;114
+ current_piece.piece[2][3] = false; 115
+ 116
+ current_piece.piece[3][0] = false;117
+ current_piece.piece[3][1] = false;118
+ current_piece.piece[3][2] = false;119
+ current_piece.piece[3][3] = false;120
+ 121
+ break;122
+123
+ case S_PIECE:124
+ current_piece.size = 3;125
+ current_piece.positions = 2;126
+ 127
+ current_piece.piece[0][0] = false;128
+ current_piece.piece[0][1] = true;129
+ current_piece.piece[0][2] = true;130
+131
+ current_piece.piece[1][0] = true;132
+ current_piece.piece[1][1] = true;133
+ current_piece.piece[1][2] = false;134
+ 135
+ current_piece.piece[2][0] = false;136
+ current_piece.piece[2][1] = false;137
+ current_piece.piece[2][2] = false;138
+139
+ break;140
+141
+ case T_PIECE:142
+ current_piece.size = 3;143
+ current_piece.positions = 4;144
+ 145
+ current_piece.piece[0][0] = false;146
+ current_piece.piece[0][1] = true;147
+ current_piece.piece[0][2] = false;148
+ 149
+ current_piece.piece[1][0] = true;150
+ current_piece.piece[1][1] = true;151
+ current_piece.piece[1][2] = true;152
+ 153
+ current_piece.piece[2][0] = false;154
+ current_piece.piece[2][1] = false;155
+ current_piece.piece[2][2] = false;156
+157
+ break;158
+ case Z_PIECE:159
+ current_piece.size = 3;160
+ current_piece.positions = 2;161
+ 162
+ current_piece.piece[0][0] = true;163
+ current_piece.piece[0][1] = true;164
+ current_piece.piece[0][2] = false;165
+166
+ current_piece.piece[1][0] = false;167
+ current_piece.piece[1][1] = true;168
+ current_piece.piece[1][2] = true;169
+170
+ current_piece.piece[2][0] = false;171
+ current_piece.piece[2][1] = false;172
+ current_piece.piece[2][2] = false;173
+174
+ break;175
+ default:176
+ perror("Fuck you\n");177
+ break;178
+ }179
+180
+ current_piece.x = ((FULL_WIDTH >> 1) - (current_piece.size >> 1));181
+182
+ return current_piece;183
+}184
+185
+186
+187
+coord find_direction(piece current_piece, uint8_t x, uint8_t y) {188
+189
+ coord points = {190
+ x,191
+ y192
+ };193
+194
+ switch (current_piece.rotation) {195
+ case TOP:196
+ /*197
+ x = k;198
+ y = j;199
+ */200
+ break;201
+ case RIGHT:202
+ points.x = y;203
+ points.y = current_piece.size - (x + 1);204
+ break;205
+ case BOTTOM:206
+ points.x = current_piece.size - (x + 1);207
+ points.y = current_piece.size - (y + 1);208
+ break;209
+ case LEFT:210
+ points.x = current_piece.size - (y + 1);211
+ points.y = x;212
+ break;213
+ }214
+215
+ return points;216
+}217
+218
+219
+bool valid_position(piece current_piece) {220
+221
+ uint8_t i, j;222
+223
+ for(i = 0; i < current_piece.size; i++) {224
+ for (j = 0; j < current_piece.size; j++) {225
+226
+ coord points = find_direction(current_piece, j, i);227
+228
+ if (229
+ current_piece.piece[i][j] &&230
+ playfield[current_piece.y + points.y][current_piece.x + points.x] != EMPTY231
+ ) {232
+ return false;233
+ }234
+ }235
+ }236
+237
+ return true;238
+}Binary file not shown.
@@ -0,0 +1,305 @@
1
+#include "main.h"2
+3
+4
+tetromino playfield[FULL_HEIGHT][FULL_WIDTH] = {};5
+6
+7
+int main () {8
+ 9
+10
+ /* Setting up the seed */11
+ 12
+ srand(time(NULL));13
+14
+15
+ /* Setting up terminal with termios */16
+ 17
+ struct termios old, new;18
+19
+ tcgetattr(STDIN_FILENO, &old);20
+ new = old;21
+22
+ new.c_lflag &= ~(ECHO | ICANON);23
+ new.c_cc[VMIN] = 0;24
+ new.c_cc[VTIME] = 0;25
+26
+ tcsetattr(STDIN_FILENO, TCSANOW, &new);27
+28
+ struct winsize init_size, current_size;29
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &init_size);30
+ current_size = init_size;31
+32
+ printf("\033[?25l\033[?1049h");33
+34
+35
+ /* Polling */36
+37
+ struct pollfd polling[1];38
+39
+ polling[0].fd = 0;40
+ polling[0].events = POLLIN;41
+42
+43
+ /* Init */44
+45
+ init_field();46
+47
+ bool blink[FIELD_HEIGHT] = {};48
+49
+ bool is_piece = false;50
+51
+ bool paused = false;52
+53
+ uint64_t paused_diff;54
+55
+ piece current_piece = {};56
+ piece next_piece = init_piece((rand() % Z_PIECE) + 1);57
+58
+ /* Game Loop */59
+60
+ struct timespec start, current;61
+ clock_gettime(CLOCK_MONOTONIC_RAW, &start);62
+63
+64
+ uint8_t i;65
+ bool is_tetris = false;66
+67
+ while (true) {68
+69
+ int8_t move = 0;70
+ bool down = false;71
+ bool draw = false;72
+ bool rotate = false;73
+74
+ clock_gettime(CLOCK_MONOTONIC_RAW, ¤t);75
+76
+ uint64_t time_diff = 77
+ (current.tv_sec - start.tv_sec) * 1000000000ULL + 78
+ (current.tv_nsec - start.tv_nsec);79
+80
+81
+ /* Take care of the input */82
+83
+ int is_poll = poll(polling, 1, paused ? -1 : 17);84
+85
+ if (is_poll > 0 && polling[0].revents & POLLIN) {86
+87
+ char buf[10] = {};88
+89
+ if (read(STDIN_FILENO, buf, sizeof(buf)) > 0) {90
+ 91
+ if (tolower(buf[0]) == 'q') {92
+ break;93
+ }94
+95
+ if (tolower(buf[0]) == 'p') {96
+ if (paused) {97
+98
+ time_diff = paused_diff;99
+100
+ paused = false;101
+ } else {102
+103
+ paused_diff = time_diff;104
+105
+ draw_pause();106
+107
+ paused = true;108
+ }109
+ }110
+111
+112
+ if (buf[0] == '\033' && buf[1] == '[') {113
+ 114
+ switch (buf[2]) {115
+ case 'A':116
+ rotate = true;117
+ break;118
+ case 'B':119
+ down = true;120
+ break;121
+ case 'C':122
+ move = 1;123
+ break;124
+ case 'D':125
+ move = -1;126
+ break;127
+ default:128
+ break;129
+ }130
+ }131
+ }132
+ }133
+134
+135
+ if (is_tetris) {136
+137
+ if (time_diff >= FRAME * BLINK && i < 4) { 138
+139
+ time_diff -= time_diff % (FRAME * BLINK);140
+ start.tv_sec += time_diff / 1000000000ULL;141
+ start.tv_nsec += time_diff % 1000000000ULL;142
+ 143
+ draw_board(current_piece, (i % 2 == 0) ? NULL : blink, is_piece);144
+ i++;145
+ }146
+147
+ if (i == 4) {148
+ 149
+ int8_t j, k;150
+151
+ for (j = 0; j < FIELD_HEIGHT; j++) {152
+ if (blink[j]) {153
+154
+ for (k = j; k > 0; k--) {155
+ int8_t l;156
+ 157
+ for (l = 0; l < FIELD_WIDTH; l++) {158
+ playfield[k][l + BORDER_WIDTH] = playfield[k - 1][l + BORDER_WIDTH];159
+ }160
+ }161
+ }162
+ }163
+164
+ i = 0;165
+ is_tetris = false;166
+ }167
+168
+ continue;169
+ }170
+171
+172
+ if (paused)173
+ continue;174
+175
+176
+ /* Creates new piece */177
+178
+ 179
+ if (!is_piece) {180
+ current_piece = next_piece;181
+ next_piece = init_piece((rand() % Z_PIECE) + 1);182
+ is_piece = true;183
+ draw = true;184
+ }185
+186
+187
+ /* Move piece */188
+189
+ if (move != 0) {190
+ if (191
+ current_piece.x + move >= 0 && 192
+ current_piece.x + move + current_piece.size <= FULL_WIDTH193
+ ) {194
+ 195
+ piece moved_piece = current_piece;196
+ moved_piece.x += move;197
+198
+ if (valid_position(moved_piece)) {199
+ current_piece.x += move;200
+ draw = true;201
+ }202
+ }203
+ }204
+205
+206
+ /* Piece rotates */207
+ 208
+ if (rotate && current_piece.positions > 1) {209
+ 210
+ piece rotated = current_piece;211
+212
+ rotated.rotation = (current_piece.rotation + 1) % (current_piece.positions);213
+ 214
+ if (valid_position(rotated)) {215
+ current_piece = rotated;216
+ draw = true;217
+ }218
+ } 219
+ 220
+221
+ /* Piece falls */222
+223
+ if (time_diff >= (FRAME * FALL) || down) {224
+ current_piece.y++;225
+ 226
+ time_diff -= time_diff % (FRAME * FALL);227
+ start.tv_sec += time_diff / 1000000000ULL;228
+ start.tv_nsec += time_diff % 1000000000ULL;229
+ 230
+231
+ draw = true;232
+ }233
+234
+235
+ /* When a piece is stuck */236
+237
+ if (!valid_position(current_piece)) {238
+239
+ int8_t j, k;240
+241
+ for (j = 0; j < current_piece.size; j++) {242
+ for (k = 0; k < current_piece.size; k++) {243
+ 244
+ if (current_piece.piece[j][k]) {245
+ 246
+ coord solid = find_direction(current_piece, k, j);247
+248
+ playfield[current_piece.y - 1 + solid.y][current_piece.x + solid.x] = current_piece.name;249
+ }250
+ }251
+ }252
+ is_piece = false;253
+ draw = true;254
+ }255
+256
+257
+ /* Looks if there is a tetris */258
+259
+ int8_t j, k;260
+261
+ for (j = FIELD_HEIGHT - 1; j >= 0; j--) {262
+263
+ uint8_t blocked = 0;264
+265
+ for (k = 0; k < FIELD_WIDTH; k++) {266
+ if (playfield[j][k + BORDER_WIDTH] != EMPTY)267
+ blocked++;268
+ }269
+270
+ if (blocked == 10) {271
+ 272
+ blink[j] = true;273
+ is_tetris = true; 274
+ } else {275
+ blink[j] = false;276
+ }277
+ }278
+279
+280
+ /* Looks for game over */281
+282
+ for (j = 0; j < FIELD_WIDTH; j++) {283
+ if (playfield[TOP_GAP][j + BORDER_WIDTH] > 0) {284
+ draw_board(current_piece, NULL, is_piece);285
+ sleep(2);286
+ printf("\033[2J\033[H");287
+ printf("HAHA LOSER\n");288
+ sleep(1);289
+ goto end;290
+ }291
+ }292
+293
+294
+ if (draw)295
+ draw_board(current_piece, NULL, is_piece);296
+ }297
+298
+end:299
+300
+ printf("\033[?1049l\033[?25h");301
+302
+ tcsetattr(STDIN_FILENO, TCSANOW, &old);303
+304
+ return 0;305
+}@@ -0,0 +1,79 @@
1
+#ifndef MAIN_C2
+3
+#define MAIN_C4
+5
+#include <stdio.h>6
+#include <stdint.h>7
+#include <stdbool.h>8
+#include <stdlib.h>9
+10
+#include <termios.h>11
+#include <sys/ioctl.h>12
+#include <sys/stat.h>13
+14
+#include <time.h>15
+#include <unistd.h>16
+#include <poll.h>17
+18
+#include <ctype.h>19
+20
+#include <errno.h>21
+22
+23
+#define FIELD_WIDTH 1024
+#define FIELD_HEIGHT 2125
+26
+#define BORDER_WIDTH 227
+#define TOP_GAP 128
+29
+#define FULL_WIDTH (FIELD_WIDTH + BORDER_WIDTH * 2)30
+#define FULL_HEIGHT (FIELD_HEIGHT + BORDER_WIDTH)31
+32
+#define FRAME 1700000033
+34
+#define FALL 5835
+#define BLINK 1236
+37
+typedef enum {38
+ EMPTY, I_PIECE, J_PIECE, L_PIECE, O_PIECE, S_PIECE, T_PIECE, Z_PIECE, TETRIS39
+} tetromino;40
+41
+typedef enum {42
+ TOP, RIGHT, BOTTOM, LEFT43
+} direction;44
+45
+typedef struct {46
+ tetromino name;47
+ bool piece[4][4];48
+ int8_t x;49
+ int8_t y;50
+ uint8_t size;51
+ direction rotation;52
+ uint8_t positions;53
+} piece;54
+55
+typedef struct {56
+ int8_t x;57
+ int8_t y;58
+} coord;59
+60
+61
+62
+void init_field();63
+64
+void draw_board(piece current_piece, piece next_piece, bool *blink, bool is_piece);65
+void draw_pause();66
+67
+68
+piece init_piece(tetromino new_piece);69
+70
+coord find_direction(piece current_piece, uint8_t x, uint8_t y);71
+ 72
+bool valid_position(piece current_piece);73
+74
+75
+76
+extern tetromino playfield[FULL_HEIGHT][FULL_WIDTH];77
+78
+79
+#endifBinary file not shown.