jag

tetoris_c

public

Small block game in C

Star0
Watch0
6ba226e1f90b274eb418fcef864202476db12552
1
ssh://git@git.jaglekon.de:30/jag/tetoris_c.git
source/main.cC380 lines6.6 KB
1
#include "main.h"
2
3
4
tetromino playfield[FULL_HEIGHT][FULL_WIDTH] = {};
5
6
uint8_t graying[FULL_HEIGHT][FULL_WIDTH] = {};
7
8
9
int main () {
10
  
11
12
  /* Setting up the seed */
13
  
14
  srand(time(NULL));
15
16
17
  /* Setting up terminal with termios */
18
  
19
  struct termios old, new;
20
21
  tcgetattr(STDIN_FILENO, &old);
22
  new = old;
23
24
  new.c_lflag &= ~(ECHO | ICANON);
25
  new.c_cc[VMIN] = 0;
26
  new.c_cc[VTIME] = 0;
27
28
  tcsetattr(STDIN_FILENO, TCSANOW, &new);
29
30
  struct winsize init_size, current_size;
31
  ioctl(STDOUT_FILENO, TIOCGWINSZ, &init_size);
32
  current_size = init_size;
33
34
  printf("\033[?25l\033[?1049h\033[2J\033[H");
35
36
37
  /* Polling */
38
39
  struct pollfd polling[1];
40
41
  polling[0].fd = 0;
42
  polling[0].events = POLLIN;
43
44
45
  /* Init */
46
47
  init_field();
48
49
  bool blink[FIELD_HEIGHT] = {};
50
51
  bool is_piece = false;
52
53
  bool paused = false;
54
55
  piece current_piece = {};
56
  piece next_piece = init_piece((rand() % Z_PIECE) + 1);
57
58
59
  /* Time keeping */
60
61
  struct timespec start, current;
62
  clock_gettime(CLOCK_MONOTONIC_RAW, &start);
63
64
  uint64_t time_acc = 0;
65
66
  uint16_t tick_fall = 0;
67
  uint16_t tick_blink = 0;
68
  uint16_t tick_spin = 0;
69
  uint16_t tick_gray = 0;
70
71
  uint8_t i;
72
  bool is_tetris = false;
73
74
  /* Game Loop */
75
76
  while (true) {
77
78
    int8_t move = 0;
79
    bool down = false;
80
    bool draw = false;
81
    bool rotate = false;
82
83
84
    /* Polling for input */
85
86
    int is_poll = poll(polling, 1, paused ? -1 : 17);
87
88
89
    /* Dealing with Ticks */
90
91
    uint16_t ticks = 0;
92
93
    {
94
95
      clock_gettime(CLOCK_MONOTONIC_RAW, &current);
96
97
      uint64_t time_diff = 
98
        (current.tv_sec - start.tv_sec) * 1000000000ULL + 
99
        (current.tv_nsec - start.tv_nsec) + time_acc;
100
101
      if (!paused) {
102
103
        while (time_diff >= FRAME) {
104
105
          time_diff -= FRAME;
106
          ticks++;
107
        }
108
109
        time_acc = time_diff;
110
      }
111
112
      start = current;
113
    }
114
115
116
    /* Take care of the input */
117
118
    if (is_poll > 0 && polling[0].revents & POLLIN) {
119
120
      char buf[10] = {};
121
122
      if (read(STDIN_FILENO, buf, sizeof(buf)) > 0) {
123
        
124
        if (tolower(buf[0]) == 'q') {
125
          break;
126
        }
127
128
        if (tolower(buf[0]) == 'p') {
129
          if (paused) {
130
131
132
            paused = false;
133
          } else {
134
135
136
            draw_pause();
137
138
            paused = true;
139
          }
140
        }
141
142
143
        if (buf[0] == '\033' && buf[1] == '[') {
144
          
145
          switch (buf[2]) {
146
            case 'A':
147
              rotate = true;
148
              break;
149
            case 'B':
150
              down = true;
151
              break;
152
            case 'C':
153
              move = 1;
154
              break;
155
            case 'D':
156
              move = -1;
157
              break;
158
            default:
159
              break;
160
          }
161
        }
162
      }
163
    }
164
165
166
    if (paused)
167
      continue;
168
169
170
171
    /* Dealing with cleared Lines */
172
173
    if (is_tetris) {
174
175
      tick_blink += ticks;
176
177
      while (tick_blink >= BLINK && i < 4) { 
178
 
179
        tick_blink -= BLINK;
180
181
        draw_board(current_piece, next_piece, (i % 2 == 0) ? blink : NULL, is_piece);
182
        i++;
183
      }
184
      
185
186
      if (i == 4) {
187
      
188
        int8_t j, k;
189
190
        for (j = 0; j < FIELD_HEIGHT; j++) {
191
          if (blink[j]) {
192
193
            for (k = j; k > 0; k--) {
194
              int8_t l;
195
          
196
              for (l = 0; l < FIELD_WIDTH; l++) {
197
                playfield[k][l + BORDER_WIDTH] = playfield[k - 1][l + BORDER_WIDTH];
198
                graying[k][l + BORDER_WIDTH] = graying[k - 1][l + BORDER_WIDTH];
199
200
              }
201
            }
202
          }
203
        }
204
205
        i = 0;
206
        is_tetris = false;
207
      }
208
209
      continue;
210
    }
211
212
213
214
    /* Creates new piece */
215
216
    if (!is_piece) {
217
      current_piece = next_piece;
218
      next_piece = init_piece((rand() % Z_PIECE) + 1);
219
      is_piece = true;
220
      draw = true;
221
222
      tick_fall = tick_blink = tick_spin = 0;
223
    }
224
225
226
    /* Move piece */
227
228
    if (move != 0) {
229
      if (
230
        current_piece.x + move >= 0 && 
231
        current_piece.x + move + current_piece.size <= FULL_WIDTH
232
      ) {
233
       
234
        piece moved_piece = current_piece;
235
        moved_piece.x += move;
236
237
        if (valid_position(moved_piece)) {
238
          current_piece.x += move;
239
          draw = true;
240
        }
241
      }
242
    }
243
244
245
    /* Piece rotates */
246
247
    if (tick_spin < SPIN)
248
      tick_spin += ticks;
249
250
    if (rotate && current_piece.positions > 1 && tick_spin >= SPIN) {
251
      
252
      piece rotated = current_piece;
253
254
      rotated.rotation = (current_piece.rotation + 1) % (current_piece.positions);
255
      
256
      if (valid_position(rotated)) {
257
        current_piece = rotated;
258
        draw = true;
259
      }
260
261
      tick_spin = 0;
262
    } 
263
    
264
265
    /* Piece falls */
266
267
    tick_fall += ticks;
268
269
    while (tick_fall >= FALL || down) {
270
      current_piece.y++;
271
      
272
273
      if (tick_fall >= FALL)
274
        tick_fall -= FALL;
275
      
276
      down = false;
277
278
      draw = true;
279
    }
280
    
281
282
283
    /* When a piece is stuck */
284
285
    if (!valid_position(current_piece)) {
286
287
      int8_t j, k;
288
289
      for (j = 0; j < current_piece.size; j++) {
290
        for (k = 0; k < current_piece.size; k++) {
291
          
292
          if (current_piece.piece[j][k]) {
293
            
294
            coord solid = find_direction(current_piece, k, j);
295
296
            playfield[current_piece.y - 1 + solid.y][current_piece.x + solid.x] = current_piece.name;
297
          }
298
        }
299
      }
300
      is_piece = false;
301
      draw = true;
302
    }
303
304
305
    /* Looks if there is a tetris */
306
307
    int8_t j, k;
308
309
    for (j = FIELD_HEIGHT - 1; j >= 0; j--) {
310
311
      uint8_t blocked = 0;
312
313
      for (k = 0; k < FIELD_WIDTH; k++) {
314
        if (playfield[j][k + BORDER_WIDTH] != EMPTY)
315
          blocked++;
316
      }
317
318
      if (blocked == 10) {
319
        
320
        blink[j] = true;
321
        is_tetris = true;  
322
      } else {
323
        blink[j] = false;
324
      }
325
    }
326
327
328
    /* Looks for game over */
329
330
    for (j = 0; j < FIELD_WIDTH; j++) {
331
      if (playfield[TOP_GAP][j + BORDER_WIDTH] > 0) {
332
        draw_board(current_piece, next_piece, NULL, is_piece);
333
        sleep(2);
334
        printf("\033[2J\033[H");
335
        printf("HAHA LOSER\n");
336
        sleep(1);
337
        goto end;
338
      }
339
    }
340
341
    /* Graying out of old pieces */
342
343
    tick_gray += ticks;
344
345
    while (tick_gray >= GRAY){
346
      
347
348
      uint8_t j, k;
349
350
      for (j = 0; j < FULL_HEIGHT; j++) {
351
        for (k = 0; k < FULL_WIDTH; k++) {
352
          if (playfield[j][k] != EMPTY) {
353
            
354
            if (graying[j][k] < 255) {
355
              graying[j][k] += 1;
356
            }
357
358
          } else {
359
            graying[j][k] = 0;
360
          }
361
362
        }
363
      }
364
365
      tick_gray -= GRAY;
366
    }
367
368
369
    if (draw)
370
      draw_board(current_piece, next_piece, NULL, is_piece);
371
  }
372
373
end:
374
375
  printf("\033[?1049l\033[?25h");
376
377
  tcsetattr(STDIN_FILENO, TCSANOW, &old);
378
379
  return 0;
380
}