jag

tetoris_c

public

Small block game in C

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