diff options
Diffstat (limited to 'keyboards/clueboard/66/keymaps/tetris/tetris_text.c')
-rw-r--r-- | keyboards/clueboard/66/keymaps/tetris/tetris_text.c | 505 |
1 files changed, 505 insertions, 0 deletions
diff --git a/keyboards/clueboard/66/keymaps/tetris/tetris_text.c b/keyboards/clueboard/66/keymaps/tetris/tetris_text.c new file mode 100644 index 000000000..1376ead00 --- /dev/null +++ b/keyboards/clueboard/66/keymaps/tetris/tetris_text.c | |||
@@ -0,0 +1,505 @@ | |||
1 | /* Copyright 2017 Dan Amlund Thomsen | ||
2 | * | ||
3 | * This program is free software: you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License as published by | ||
5 | * the Free Software Foundation, either version 2 of the License, or | ||
6 | * (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | #include <stdio.h> | ||
17 | #include <stdlib.h> | ||
18 | #include <stdarg.h> | ||
19 | #include <stdint.h> | ||
20 | |||
21 | #include "tetris_text.h" | ||
22 | |||
23 | static char empty_piece[7][7] = { { 0, 0, 0, 0, 0, 0, 0 }, | ||
24 | { 0, 0, 0, 0, 0, 0, 0 }, | ||
25 | { 0, 0, 0, 0, 0, 0, 0 }, | ||
26 | { 0, 0, 0, 0, 0, 0, 0 }, | ||
27 | { 0, 0, 0, 0, 0, 0, 0 }, | ||
28 | { 0, 0, 0, 0, 0, 0, 0 }, | ||
29 | { 0, 0, 0, 0, 0, 0, 0 } }; | ||
30 | |||
31 | static char temp_piece[7][7]; | ||
32 | |||
33 | static int curx = 0; | ||
34 | static int cury = 0; | ||
35 | |||
36 | static void clear_piece(char piece[7][7]) { | ||
37 | for (int y = 0; y < 7; y++) { | ||
38 | for (int x = 0; x < 7; x++) { | ||
39 | piece[x][y] = 0; | ||
40 | } | ||
41 | } | ||
42 | } | ||
43 | |||
44 | static void copy_piece_from_to(char from[7][7], char to[7][7]) { | ||
45 | for (int y = 0; y < 7; y++) { | ||
46 | for (int x = 0; x < 7; x++) { | ||
47 | to[x][y] = from[x][y]; | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | |||
52 | static void rotate_piece(char piece[7][7]) { | ||
53 | // transpose | ||
54 | for (int y = 0; y < 7; y++) { | ||
55 | for (int x = y + 1; x < 7; x++) { | ||
56 | char tmp = piece[y][x]; | ||
57 | piece[y][x] = piece[x][y]; | ||
58 | piece[x][y] = tmp; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | // reverse rows | ||
63 | for (int y = 0; y < 7; y++) { | ||
64 | for (int x = 0; x < 3; x++) { | ||
65 | char tmp = piece[y][6 - x]; | ||
66 | piece[y][6 - x] = piece[y][x]; | ||
67 | piece[y][x] = tmp; | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | |||
72 | static char get_shape_char(int shape) { | ||
73 | switch (shape) { | ||
74 | case 0: return 'I'; | ||
75 | case 1: return 'J'; | ||
76 | case 2: return 'L'; | ||
77 | case 3: return 'O'; | ||
78 | case 4: return 'S'; | ||
79 | case 5: return 'T'; | ||
80 | case 6: return 'Z'; | ||
81 | } | ||
82 | return 'Q'; | ||
83 | } | ||
84 | |||
85 | static void set_piece(char piece[7][7], int shape, int rotation) { | ||
86 | clear_piece(piece); | ||
87 | switch (shape) { | ||
88 | case 0: | ||
89 | if (rotation % 2 == 0) { | ||
90 | // xxXx | ||
91 | piece[3][1] = 1; | ||
92 | piece[3][2] = 1; | ||
93 | piece[3][3] = 1; | ||
94 | piece[3][4] = 1; | ||
95 | } else { | ||
96 | // x | ||
97 | // x | ||
98 | // X | ||
99 | // x | ||
100 | piece[1][3] = 1; | ||
101 | piece[2][3] = 1; | ||
102 | piece[3][3] = 1; | ||
103 | piece[4][3] = 1; | ||
104 | } | ||
105 | break; | ||
106 | case 1: | ||
107 | // xXx | ||
108 | // x | ||
109 | piece[3][2] = 1; | ||
110 | piece[3][3] = 1; | ||
111 | piece[3][4] = 1; | ||
112 | piece[4][4] = 1; | ||
113 | for (int i = 0; i < rotation; i++) { | ||
114 | rotate_piece(piece); | ||
115 | } | ||
116 | break; | ||
117 | case 2: | ||
118 | // xXx | ||
119 | // x | ||
120 | piece[3][2] = 1; | ||
121 | piece[3][3] = 1; | ||
122 | piece[3][4] = 1; | ||
123 | piece[4][2] = 1; | ||
124 | for (int i = 0; i < rotation; i++) { | ||
125 | rotate_piece(piece); | ||
126 | } | ||
127 | break; | ||
128 | case 3: | ||
129 | // xX | ||
130 | // xx | ||
131 | piece[3][2] = 1; | ||
132 | piece[3][3] = 1; | ||
133 | piece[4][2] = 1; | ||
134 | piece[4][3] = 1; | ||
135 | break; | ||
136 | case 4: | ||
137 | if (rotation % 2 == 0) { | ||
138 | // xX | ||
139 | // xx | ||
140 | piece[3][2] = 1; | ||
141 | piece[3][3] = 1; | ||
142 | piece[4][3] = 1; | ||
143 | piece[4][4] = 1; | ||
144 | } else { | ||
145 | // x | ||
146 | // xX | ||
147 | // x | ||
148 | piece[2][3] = 1; | ||
149 | piece[3][2] = 1; | ||
150 | piece[3][3] = 1; | ||
151 | piece[4][2] = 1; | ||
152 | } | ||
153 | break; | ||
154 | case 5: | ||
155 | // xXx | ||
156 | // x | ||
157 | piece[3][2] = 1; | ||
158 | piece[3][3] = 1; | ||
159 | piece[3][4] = 1; | ||
160 | piece[4][3] = 1; | ||
161 | for (int i = 0; i < rotation; i++) { | ||
162 | rotate_piece(piece); | ||
163 | } | ||
164 | break; | ||
165 | case 6: | ||
166 | if (rotation % 2 == 0) { | ||
167 | // Xx | ||
168 | // xx | ||
169 | piece[3][3] = 1; | ||
170 | piece[3][4] = 1; | ||
171 | piece[4][2] = 1; | ||
172 | piece[4][3] = 1; | ||
173 | } else { | ||
174 | // x | ||
175 | // Xx | ||
176 | // x | ||
177 | piece[2][3] = 1; | ||
178 | piece[3][3] = 1; | ||
179 | piece[3][4] = 1; | ||
180 | piece[4][4] = 1; | ||
181 | } | ||
182 | break; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | static void send_deletes(int deletes) { | ||
187 | for (int i = 0; i < deletes; i++) { | ||
188 | tetris_send_delete(); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | static void send_backspaces(int backspaces) { | ||
193 | for (int i = 0; i < backspaces; i++) { | ||
194 | tetris_send_backspace(); | ||
195 | curx--; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | static void send_goto_xy(int x, int y) { | ||
200 | while (curx < x) { | ||
201 | tetris_send_right(); | ||
202 | curx++; | ||
203 | } | ||
204 | while (curx > x) { | ||
205 | tetris_send_left(); | ||
206 | curx--; | ||
207 | } | ||
208 | while (cury < y) { | ||
209 | tetris_send_down(); | ||
210 | cury++; | ||
211 | } | ||
212 | while (cury > y) { | ||
213 | tetris_send_up(); | ||
214 | cury--; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | static void draw_row(char c, const char oldrow[7], const char newrow[7], int x, int y) { | ||
219 | char str[2] = { c, 0 }; | ||
220 | char row_is_del[7] = { 0 }; | ||
221 | int first = -1; | ||
222 | int last = -1; | ||
223 | for (int px = 0; px < 7; px++) { | ||
224 | if (oldrow[px] && !newrow[px]) { | ||
225 | row_is_del[px] = 1; | ||
226 | } | ||
227 | if (newrow[px] || oldrow[px]) { | ||
228 | if (first == -1) first = px; | ||
229 | last = px; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | if (first >= 0) { | ||
234 | if (curx > x + last + 1) { | ||
235 | send_goto_xy(x + last + 1, cury); | ||
236 | } | ||
237 | if (curx < x + first) { | ||
238 | send_goto_xy(x + first, cury); | ||
239 | } | ||
240 | send_goto_xy(curx, y); | ||
241 | send_deletes((x + last + 1) - curx); | ||
242 | send_backspaces(curx - (x + first)); | ||
243 | for (int i = first; i <= last; i++) { | ||
244 | if (row_is_del[i]) { | ||
245 | tetris_send_string("."); | ||
246 | } else { | ||
247 | tetris_send_string(str); | ||
248 | } | ||
249 | curx++; | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | |||
254 | static void move_piece_from_to(char from[7][7], char to[7][7], int xadd, int yadd) { | ||
255 | for (int y = 0; y < 7; y++) { | ||
256 | for (int x = 0; x < 7; x++) { | ||
257 | if (x + xadd >= 0 && x + xadd < 7 && y + yadd >= 0 && y + yadd < 7) { | ||
258 | to[y][x] = from[y + yadd][x + xadd]; | ||
259 | } else { | ||
260 | to[y][x] = 0; | ||
261 | } | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | |||
266 | static void draw_piece(char c, int x, int y, char oldpiece[7][7], char piece[7][7]) { | ||
267 | for (int py = 0; py < 7; py++) { | ||
268 | draw_row(c, oldpiece[py], piece[py], x, y + py); | ||
269 | } | ||
270 | } | ||
271 | |||
272 | static void draw_piece_moved(char c, int x, int y, char piece[7][7], int oldxadd, int oldyadd) { | ||
273 | move_piece_from_to(piece, temp_piece, oldxadd, oldyadd); | ||
274 | draw_piece(c, x, y, temp_piece, piece); | ||
275 | } | ||
276 | |||
277 | static int is_piece_hitting(char board[20][10], char piece[7][7], int x, int y) { | ||
278 | for (int py = 0; py < 7; py++) { | ||
279 | for (int px = 0; px < 7; px++) { | ||
280 | if (piece[py][px] && | ||
281 | (px + x >= 10 || px + x < 0 | ||
282 | || py + y >= 20 || py + y < 0 | ||
283 | || board[py + y][px + x])) { | ||
284 | return 1; | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static void add_piece_to_board(char piece[7][7], char board[20][10], int x, int y) { | ||
292 | for (int py = 0; py < 7; py++) { | ||
293 | for (int px = 0; px < 7; px++) { | ||
294 | if (piece[py][px]) { | ||
295 | board[py + y][px + x] = piece[py][px]; | ||
296 | } | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | |||
301 | static void draw_board_line(void) { | ||
302 | //send_string("l l"); | ||
303 | tetris_send_string("l..........l"); | ||
304 | tetris_send_newline(); | ||
305 | } | ||
306 | static void init(void) { | ||
307 | for (int i = 0; i < 20; i++) { | ||
308 | draw_board_line(); | ||
309 | } | ||
310 | tetris_send_string("doooooooooob"); | ||
311 | curx = 12; | ||
312 | cury = 20; | ||
313 | } | ||
314 | |||
315 | static int get_piece_min_y(char piece[7][7]) { | ||
316 | for (int y = 0; y < 7; y++) { | ||
317 | for (int x = 0; x < 7; x++) { | ||
318 | if (piece[y][x]) | ||
319 | return y; | ||
320 | } | ||
321 | } | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int clear_lines(char board[20][10]) { | ||
326 | int cleared_lines = 0; | ||
327 | for (int y = 19; y >= 0; y--) { | ||
328 | char isfull = 1; | ||
329 | for (int x = 0; x < 10; x++) { | ||
330 | if (!board[y][x]) { | ||
331 | isfull = 0; | ||
332 | } | ||
333 | } | ||
334 | if (isfull) { | ||
335 | // delete clear line | ||
336 | send_goto_xy(12, y); | ||
337 | send_backspaces(12); // delete line contents | ||
338 | // delete newline | ||
339 | tetris_send_backspace(); | ||
340 | cury--; | ||
341 | curx = 12; | ||
342 | cleared_lines++; | ||
343 | } else { | ||
344 | if (cleared_lines > 0) { | ||
345 | // move cleared lines down on board | ||
346 | for (int x = 0; x < 10; x++) { | ||
347 | board[y + cleared_lines][x] = board[y][x]; | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | } | ||
352 | // clear cleared top lines | ||
353 | for (int y = 0; y < cleared_lines; y++) { | ||
354 | for (int x = 0; x < 10; x++) { | ||
355 | board[y][x] = 0; | ||
356 | } | ||
357 | } | ||
358 | if (cleared_lines > 0) { | ||
359 | send_goto_xy(0, 0); | ||
360 | for (int i = 0; i < cleared_lines; i++) { | ||
361 | draw_board_line(); | ||
362 | curx = 0; | ||
363 | cury++; | ||
364 | } | ||
365 | } | ||
366 | return cleared_lines; | ||
367 | } | ||
368 | |||
369 | static uint8_t myrandom(uint8_t seed) { | ||
370 | uint8_t out = seed >> 1; | ||
371 | if (seed & 1) { | ||
372 | out = out ^ 0xB8; | ||
373 | } | ||
374 | return out; | ||
375 | } | ||
376 | |||
377 | static char piece[7][7]; | ||
378 | static char board[20][10]; | ||
379 | static uint8_t r; | ||
380 | static int score; | ||
381 | static int x; | ||
382 | static int y; | ||
383 | static int shape; | ||
384 | static int rotation; | ||
385 | static int time; | ||
386 | static int next_down; | ||
387 | static int down_delay; | ||
388 | static int first_run; | ||
389 | static int game_over; | ||
390 | |||
391 | void tetris_start(uint8_t seed) { | ||
392 | for (int y = 0; y < 20; y++) { | ||
393 | for (int x = 0; x < 10; x++) { | ||
394 | board[y][x] = 0; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | clear_piece(piece); | ||
399 | |||
400 | init(); | ||
401 | |||
402 | game_over = 0; | ||
403 | |||
404 | r = seed; | ||
405 | score = 0; | ||
406 | |||
407 | copy_piece_from_to(empty_piece, piece); | ||
408 | x = 0; | ||
409 | y = 0; | ||
410 | shape = 0; | ||
411 | rotation = 0; | ||
412 | time = 0; | ||
413 | next_down = 0; | ||
414 | down_delay = -1; | ||
415 | first_run = 1; | ||
416 | } | ||
417 | |||
418 | int tetris_tick(int ms_since_previous_tick) { | ||
419 | if (game_over) { | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | time += ms_since_previous_tick; | ||
424 | |||
425 | if (first_run || time > next_down) { | ||
426 | if (first_run || is_piece_hitting(board, piece, x, y + 1)) { | ||
427 | first_run = 0; | ||
428 | add_piece_to_board(piece, board, x, y); | ||
429 | |||
430 | score += clear_lines(board); | ||
431 | |||
432 | down_delay = 500 - score * 10; | ||
433 | if (down_delay < 100) { | ||
434 | down_delay = 100; | ||
435 | } | ||
436 | |||
437 | rotation = 0; | ||
438 | shape = r % 7; | ||
439 | r = myrandom(r); | ||
440 | set_piece(piece, shape, rotation); | ||
441 | |||
442 | x = 1; | ||
443 | y = - get_piece_min_y(piece); | ||
444 | draw_piece_moved(get_shape_char(shape), 1 + x, y, piece, 0, 0); | ||
445 | |||
446 | if (is_piece_hitting(board, piece, x, y)) { | ||
447 | game_over = 1; | ||
448 | send_goto_xy(12, 10); | ||
449 | tetris_send_string(" game over"); | ||
450 | tetris_send_down(); | ||
451 | tetris_send_string(" score "); | ||
452 | char tmp[10]; | ||
453 | sprintf(tmp, "%d", score); | ||
454 | tetris_send_string(tmp); | ||
455 | return 0; | ||
456 | } | ||
457 | } else { | ||
458 | y++; | ||
459 | draw_piece_moved(get_shape_char(shape), 1 + x, y, piece, 0, +1); | ||
460 | } | ||
461 | next_down = time + down_delay; | ||
462 | } else { | ||
463 | |||
464 | switch (tetris_get_keypress()) { | ||
465 | case 1: { // up | ||
466 | int oldrotation = rotation; | ||
467 | rotation = (rotation + 1) % 4; | ||
468 | copy_piece_from_to(piece, temp_piece); | ||
469 | set_piece(piece, shape, rotation); | ||
470 | if (is_piece_hitting(board, piece, x, y)) { | ||
471 | rotation = oldrotation; | ||
472 | set_piece(piece, shape, rotation); | ||
473 | } else { | ||
474 | draw_piece(get_shape_char(shape), 1 + x, y, temp_piece, piece); | ||
475 | } | ||
476 | break; | ||
477 | } | ||
478 | case 2: // left | ||
479 | if (!is_piece_hitting(board, piece, x - 1, y)) { | ||
480 | x--; | ||
481 | draw_piece_moved(get_shape_char(shape), 1 + x, y, piece, -1, 0); | ||
482 | } | ||
483 | break; | ||
484 | case 3: {// down | ||
485 | int starty = y; | ||
486 | while (!is_piece_hitting(board, piece, x, y + 1)) { | ||
487 | y++; | ||
488 | } | ||
489 | |||
490 | draw_piece(get_shape_char(shape), x + 1, starty, piece, empty_piece); | ||
491 | draw_piece(get_shape_char(shape), x + 1, y, empty_piece, piece); | ||
492 | |||
493 | next_down = time + down_delay; | ||
494 | break; | ||
495 | } | ||
496 | case 4: // right | ||
497 | if (!is_piece_hitting(board, piece, x + 1, y)) { | ||
498 | x++; | ||
499 | draw_piece_moved(get_shape_char(shape), 1 + x, y, piece, 1, 0); | ||
500 | } | ||
501 | break; | ||
502 | } | ||
503 | } | ||
504 | return 1; | ||
505 | } | ||