Small block game in C
Commit 376b4433efc1
tarball5 files changed+604-0
@@ -0,0 +1,2 @@
1
+tetoris: main.c2
+ gcc -Wall -Wextra -o tetoris main.cBinary file not shown.
@@ -0,0 +1,602 @@
1
+#include <stdio.h>2
+#include <stdint.h>3
+#include <stdbool.h>4
+#include <stdlib.h>5
+6
+#include <termios.h>7
+#include <sys/ioctl.h>8
+#include <sys/stat.h>9
+10
+#include <time.h>11
+#include <unistd.h>12
+13
+#include <errno.h>14
+15
+16
+/* TETRIS */17
+18
+#define FIELD_WIDTH 1019
+#define FIELD_HEIGHT 2020
+21
+#define BORDER_WIDTH 222
+#define TOP_GAP 123
+24
+#define FULL_WIDTH (FIELD_WIDTH + BORDER_WIDTH * 2)25
+#define FULL_HEIGHT (FIELD_HEIGHT + BORDER_WIDTH + TOP_GAP)26
+27
+typedef enum {28
+ EMPTY, I_PIECE, J_PIECE, L_PIECE, O_PIECE, S_PIECE, T_PIECE, Z_PIECE, TETRIS29
+} tetromino;30
+31
+typedef enum {32
+ TOP, RIGHT, BOTTOM, LEFT33
+} direction;34
+35
+typedef struct {36
+ tetromino name;37
+ bool piece[4][4];38
+ int8_t x;39
+ int8_t y;40
+ uint8_t width;41
+ uint8_t height;42
+ direction rotation;43
+} piece;44
+45
+typedef struct {46
+ int8_t x;47
+ int8_t y;48
+} coord;49
+50
+tetromino playfield[FULL_HEIGHT][FULL_WIDTH] = {};51
+52
+53
+void init_field();54
+55
+void draw_board(piece current_piece, int8_t blink, bool is_piece);56
+57
+piece init_piece(tetromino new_piece);58
+59
+coord find_direction(piece current_piece, uint8_t x, uint8_t y);60
+ 61
+62
+int main () {63
+ 64
+65
+ /* Setting up the seed */66
+ 67
+ srand(time(NULL));68
+69
+70
+ /* Setting up terminal with termios */71
+ 72
+ struct termios old, new;73
+74
+ tcgetattr(STDIN_FILENO, &old);75
+ new = old;76
+77
+ new.c_lflag &= ~(ECHO | ICANON);78
+ new.c_cc[VMIN] = 0;79
+ new.c_cc[VTIME] = 0;80
+81
+ tcsetattr(STDIN_FILENO, TCSANOW, &new);82
+83
+ struct winsize init_size, current_size;84
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &init_size);85
+ current_size = init_size;86
+87
+ printf("\033[?25l\033[?1049h");88
+89
+ /* Init */90
+91
+ init_field();92
+93
+94
+ /* Init the first piece */95
+96
+ bool is_piece = true;97
+98
+ piece current_piece = init_piece((rand() % Z_PIECE) + 1);99
+100
+101
+ uint16_t i;102
+103
+ for (i = 0;; i = (i + 1) % 20) {104
+105
+ int8_t move = 0;106
+ bool down = false;107
+ bool draw = false;108
+ bool rotate = false;109
+110
+ int8_t j, k;111
+112
+ if (!is_piece) {113
+ current_piece = init_piece((rand() % Z_PIECE) + 1);114
+ current_piece.rotation = rand() % (LEFT + 1);115
+ is_piece = true;116
+ draw = true;117
+ }118
+119
+120
+ /* Take care of the input */121
+122
+123
+ char buf[10] = {};124
+125
+ if (read(STDIN_FILENO, buf, sizeof(buf)) > 0) {126
+ if (buf[0] == 'q') {127
+ break;128
+ }129
+130
+ if (buf[0] == '\033' && buf[1] == '[') {131
+ 132
+ switch (buf[2]) {133
+ case 'A':134
+ rotate = true;135
+ break;136
+ case 'B':137
+ down = true;138
+ break;139
+ case 'C':140
+ move = 1;141
+ break;142
+ case 'D':143
+ move = -1;144
+ break;145
+ default:146
+ break;147
+ }148
+ }149
+ }150
+151
+152
+ /* Move piece */153
+154
+ if (move != 0) {155
+ if (156
+ current_piece.x + move >= 0 && 157
+ current_piece.x + move + ((current_piece.rotation % 2) ? current_piece.height : current_piece.width) <= FULL_WIDTH158
+ ) {159
+ 160
+ bool is_valid = true;161
+162
+163
+ for (j = 0; j < current_piece.height; j++) {164
+ for (k = 0; k < current_piece.width; k++) {165
+166
+ coord points = find_direction(current_piece, k, j);167
+168
+ if (169
+ current_piece.piece[j][k] && 170
+ playfield[current_piece.y + points.y][current_piece.x + points.x + move] != EMPTY171
+ ) {172
+ is_valid = false;173
+ }174
+ }175
+ }176
+177
+ if (is_valid) {178
+ current_piece.x += move;179
+ draw = true;180
+ }181
+ }182
+ }183
+184
+ /* Piece rotates */185
+186
+ /*187
+ if (rotate) {188
+ 189
+ direction new_direction = (current_piece.rotation + 1) % (LEFT + 1);190
+191
+ uint8_t actual_width = (new_direction % 2) ? current_piece.height : current_piece.width;192
+ uint8_t actual_height = (new_direction % 2) ? current_piece.width : current_piece.height;193
+194
+ coord new_position = {195
+196
+ }197
+ }198
+ */199
+200
+ /* Piece falls */201
+202
+ if (i == 0 || down) {203
+ current_piece.y++;204
+ i = 1;205
+ draw = true;206
+ }207
+208
+209
+ /* When a piece is stuck */210
+211
+ for(j = 0; j < current_piece.height; j++) {212
+ for (k = 0; k < current_piece.width; k++) {213
+ 214
+ coord points = find_direction(current_piece, k, j);215
+216
+ uint8_t x = current_piece.x + points.x;217
+ uint8_t y = current_piece.y + points.y;218
+219
+ if (220
+ y >= FULL_HEIGHT || 221
+ (playfield[y][x] != EMPTY && current_piece.piece[j][k])222
+ ) {223
+224
+ uint8_t l, m;225
+226
+ for (l = 0; l < current_piece.height; l++) {227
+ for (m = 0; m < current_piece.width; m++) {228
+ 229
+ if (current_piece.piece[l][m]) {230
+ 231
+ coord solid = find_direction(current_piece, m, l);232
+233
+ playfield[current_piece.y - 1 + solid.y][current_piece.x + solid.x] = current_piece.name;234
+ }235
+ }236
+ }237
+ is_piece = false;238
+ draw = true;239
+ }240
+ }241
+ }242
+243
+ /* Looks if there is a tetris */244
+245
+ for (j = FIELD_HEIGHT + TOP_GAP - 1; j >= 0; j--) {246
+247
+ uint8_t is_tetris = 0;248
+249
+ for (k = 0; k < FIELD_WIDTH; k++) {250
+ if (playfield[j][k + BORDER_WIDTH] != EMPTY)251
+ is_tetris++;252
+ }253
+254
+ if (is_tetris == 10) {255
+ 256
+ for (k = 0; k < 4; k++) {257
+ 258
+ draw_board(current_piece, (k % 2) ? -1 : j, is_piece);259
+260
+ usleep(300000);261
+ }262
+263
+ for (k = j; k > 0; k--) {264
+ 265
+ int8_t l;266
+ 267
+ for (l = 0; l < FIELD_WIDTH; l++) {268
+ playfield[k][l + BORDER_WIDTH] = playfield[k - 1][l + BORDER_WIDTH];269
+ }270
+ }271
+ 272
+ j++;273
+ }274
+ }275
+276
+277
+ /* Looks for game over */278
+279
+ for (j = 0; j < FIELD_WIDTH; j++) {280
+ if (playfield[TOP_GAP][j + BORDER_WIDTH] > 0) {281
+ printf("\033[2J\033[H");282
+ printf("HAHA LOSER\n");283
+ sleep(3);284
+ goto end;285
+ }286
+ }287
+288
+289
+ if (draw)290
+ draw_board(current_piece, -1, is_piece);291
+ usleep(10000);292
+ }293
+294
+end:295
+296
+ printf("\033[?1049l\033[?25h");297
+298
+ tcsetattr(STDIN_FILENO, TCSANOW, &old);299
+300
+ return 0;301
+}302
+303
+304
+305
+void init_field() {306
+ uint8_t i, j;307
+ for(i = 0; i < FULL_HEIGHT; i++) {308
+ for (j = 0; j < FULL_WIDTH; j++) {309
+ 310
+ if (311
+ j < BORDER_WIDTH || 312
+ j >= FULL_WIDTH - BORDER_WIDTH ||313
+ i >= FULL_HEIGHT - BORDER_WIDTH314
+ ) {315
+ playfield[i][j] = TETRIS; 316
+ } else {317
+ playfield[i][j] = EMPTY;318
+ }319
+ }320
+ }321
+}322
+323
+324
+325
+#define RED "\033[38;2;255;0;0m"326
+#define GREEN "\033[38;2;0;255;0m"327
+#define BLUE "\033[38;2;0;0;255m"328
+#define YELLOW "\033[38;2;255;255;0m"329
+#define MAGENTA "\033[38;2;255;0;255m"330
+#define TEAL "\033[38;2;0;255;255m"331
+#define PURPLE "\033[38;2;127;0;255m"332
+#define WHITE "\033[38;2;255;255;255m"333
+334
+void draw_color (tetromino current_square) {335
+ switch (current_square) {336
+ case I_PIECE:337
+ printf("%s", RED);338
+ break;339
+ case J_PIECE:340
+ printf("%s", GREEN);341
+ break;342
+ case L_PIECE:343
+ printf("%s", BLUE);344
+ break;345
+ case O_PIECE:346
+ printf("%s", YELLOW);347
+ break;348
+ case S_PIECE:349
+ printf("%s", MAGENTA);350
+ break;351
+ case T_PIECE:352
+ printf("%s", TEAL);353
+ break;354
+ case Z_PIECE:355
+ printf("%s", PURPLE);356
+ break;357
+ } 358
+}359
+360
+361
+void draw_board(piece current_piece, int8_t blink, bool is_piece) {362
+363
+ uint8_t i, j;364
+365
+366
+ printf("\033[2J\033[H");367
+ printf("┏");368
+ for (i = 0; i < FIELD_WIDTH; i++)369
+ printf("━━");370
+ printf("┓\n");371
+372
+373
+ for (i = 0; i < FIELD_HEIGHT; i++) {374
+ 375
+ printf("┃");376
+377
+ for (j = 0; j < FIELD_WIDTH; j++) {378
+ 379
+ if (i + TOP_GAP == blink) {380
+ 381
+ printf("%s", WHITE);382
+ } else {383
+384
+385
+ tetromino current_square = current_square = playfield[i + TOP_GAP][j + BORDER_WIDTH];386
+387
+ if (is_piece) {388
+389
+ uint8_t k, l;390
+ 391
+ for (k = 0; k < current_piece.height; k++) {392
+ for (l = 0; l < current_piece.width; l++) {393
+394
+ coord points = find_direction(current_piece, l, k);395
+396
+ if (397
+ i == current_piece.y + points.y - TOP_GAP && 398
+ j == current_piece.x + points.x - BORDER_WIDTH && 399
+ current_piece.piece[k][l]) 400
+ {401
+ current_square = current_piece.name;402
+ }403
+ }404
+ }405
+ }406
+407
+ if (current_square <= EMPTY || current_square > Z_PIECE) {408
+ printf("· ");409
+ continue;410
+ }411
+412
+ draw_color(current_square);413
+ }414
+ 415
+ printf("██\033[0m");416
+ }417
+ printf("┃\n");418
+ }419
+420
+ printf("┗");421
+ for (i = 0; i < FIELD_WIDTH; i++)422
+ printf("━━");423
+ printf("┛\n");424
+425
+}426
+427
+428
+piece init_piece(tetromino new_piece) {429
+ 430
+ piece current_piece = {};431
+432
+ current_piece.name = new_piece;433
+434
+ switch (current_piece.name) {435
+ case I_PIECE:436
+ current_piece.width = 4;437
+ current_piece.height = 4;438
+ 439
+ current_piece.piece[0][0] = false;440
+ current_piece.piece[0][1] = false;441
+ current_piece.piece[0][2] = false;442
+ current_piece.piece[0][3] = false;443
+444
+ current_piece.piece[1][0] = true;445
+ current_piece.piece[1][1] = true;446
+ current_piece.piece[1][2] = true;447
+ current_piece.piece[1][3] = true;448
+ 449
+ current_piece.piece[2][0] = false;450
+ current_piece.piece[2][1] = false;451
+ current_piece.piece[2][2] = false;452
+ current_piece.piece[2][3] = false;453
+ 454
+ current_piece.piece[3][0] = false;455
+ current_piece.piece[3][1] = false;456
+ current_piece.piece[3][2] = false;457
+ current_piece.piece[3][3] = false;458
+ 459
+ break;460
+461
+ case J_PIECE:462
+ current_piece.width = 3;463
+ current_piece.height = 3;464
+ 465
+ current_piece.piece[0][0] = true;466
+ current_piece.piece[0][1] = false;467
+ current_piece.piece[0][2] = false;468
+ 469
+ current_piece.piece[1][0] = true;470
+ current_piece.piece[1][1] = true;471
+ current_piece.piece[1][2] = true;472
+473
+ current_piece.piece[2][0] = false;474
+ current_piece.piece[2][1] = false;475
+ current_piece.piece[2][2] = false;476
+477
+ break;478
+479
+ case L_PIECE:480
+ current_piece.width = 3;481
+ current_piece.height = 3;482
+ 483
+ current_piece.piece[0][0] = false;484
+ current_piece.piece[0][1] = false;485
+ current_piece.piece[0][2] = true;486
+ 487
+ current_piece.piece[1][0] = true;488
+ current_piece.piece[1][1] = true;489
+ current_piece.piece[1][2] = true;490
+491
+ current_piece.piece[2][0] = false;492
+ current_piece.piece[2][1] = false;493
+ current_piece.piece[2][2] = false;494
+495
+ break;496
+497
+ case O_PIECE:498
+ current_piece.width = 2;499
+ current_piece.height = 2;500
+ 501
+ current_piece.piece[0][0] = true;502
+ current_piece.piece[0][1] = true;503
+504
+ current_piece.piece[1][0] = true;505
+ current_piece.piece[1][1] = true;506
+ 507
+ break;508
+509
+ case S_PIECE:510
+ current_piece.width = 3;511
+ current_piece.height = 3;512
+ 513
+ current_piece.piece[0][0] = false;514
+ current_piece.piece[0][1] = true;515
+ current_piece.piece[0][2] = true;516
+517
+ current_piece.piece[1][0] = true;518
+ current_piece.piece[1][1] = true;519
+ current_piece.piece[1][2] = false;520
+ 521
+ current_piece.piece[2][0] = false;522
+ current_piece.piece[2][1] = false;523
+ current_piece.piece[2][2] = false;524
+525
+ break;526
+527
+ case T_PIECE:528
+ current_piece.width = 3;529
+ current_piece.height = 3;530
+ 531
+ current_piece.piece[0][0] = false;532
+ current_piece.piece[0][1] = true;533
+ current_piece.piece[0][2] = false;534
+ 535
+ current_piece.piece[1][0] = true;536
+ current_piece.piece[1][1] = true;537
+ current_piece.piece[1][2] = true;538
+ 539
+ current_piece.piece[2][0] = false;540
+ current_piece.piece[2][1] = false;541
+ current_piece.piece[2][2] = false;542
+543
+ break;544
+ case Z_PIECE:545
+ current_piece.width = 3;546
+ current_piece.height = 3;547
+ 548
+ current_piece.piece[0][0] = true;549
+ current_piece.piece[0][1] = true;550
+ current_piece.piece[0][2] = false;551
+552
+ current_piece.piece[1][0] = false;553
+ current_piece.piece[1][1] = true;554
+ current_piece.piece[1][2] = true;555
+556
+ current_piece.piece[2][0] = false;557
+ current_piece.piece[2][1] = false;558
+ current_piece.piece[2][2] = false;559
+560
+ break;561
+ default:562
+ perror("Fuck you\n");563
+ break;564
+ }565
+566
+ current_piece.x = (FIELD_WIDTH >> 1) - (current_piece.width >> 1) + BORDER_WIDTH;567
+ current_piece.y = TOP_GAP;568
+ current_piece.rotation = TOP;569
+570
+ return current_piece;571
+}572
+573
+coord find_direction(piece current_piece, uint8_t x, uint8_t y) {574
+575
+ coord points = {576
+ x,577
+ y578
+ };579
+580
+ switch (current_piece.rotation) {581
+ case TOP:582
+ /*583
+ x = k;584
+ y = j;585
+ */586
+ break;587
+ case RIGHT:588
+ points.x = y;589
+ points.y = current_piece.width - (x + 1);590
+ break;591
+ case BOTTOM:592
+ points.x = current_piece.width - (x + 1);593
+ points.y = current_piece.height - (y + 1);594
+ break;595
+ case LEFT:596
+ points.x = current_piece.height - (y + 1);597
+ points.y = x;598
+ break;599
+ }600
+601
+ return points;602
+}Binary file not shown.