💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Tetris › files › a1476d178e22cfd7459ee6bd03e… captured on 2023-12-28 at 15:48:28. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-09-08)
-=-=-=-=-=-=-
0 /* See LICENSE file for copyright and license details. */
1 #include "config.h"
2 #include "backend.h"
3 #include <stdlib.h>
4 #include <string.h>
5 #include <time.h>
6 #include <math.h>
7 #include <unistd.h>
8
9 typedef struct Rect {
10 _uint x;
11 _uint y;
12 _uint w;
13 _uint h;
14 } Rect;
15
16 /* Drawing score */
17 uint8 number[10][7] = {
18 {1, 1, 1, 0, 1, 1, 1},
19 {0, 0, 1, 0, 0, 1, 0},
20 {1, 0, 1, 1, 1, 0, 1},
21 {1, 0, 1, 1, 0, 1, 1},
22 {0, 1, 1, 1, 0, 1, 0},
23 {1, 1, 0, 1, 0, 1, 1},
24 {1, 1, 0, 1, 1, 1, 1},
25 {1, 0, 1, 0, 0, 1, 0},
26 {1, 1, 1, 1, 1, 1, 1},
27 {1, 1, 1, 1, 0, 1, 1}
28 };
29
30 Rect offset[8] = {
31 {0, 0, WIDTHX, THICK},
32 {0, 0, THICK, WIDTHY},
33 {WIDTHX - THICK, 0, THICK, WIDTHY},
34 {0, WIDTHY, WIDTHX, THICK},
35 {0, WIDTHY, THICK, WIDTHY},
36 {WIDTHX - THICK, WIDTHY, THICK, WIDTHY},
37 {0, WIDTHY * 2, WIDTHX, THICK},
38 };
39
40 void drawDigit(_uint x, _uint y, _uint n) {
41 uint8 i = 0;
42 Rect r;
43 if (n >= 10) return;
44 for (; i < 7; i++) {
45 if (!number[n][i]) continue;
46 r = offset[i];
47 r.x += x;
48 r.y += y;
49 backend_fill(r.x, r.y, r.w, r.h, TEXT);
50 }
51 }
52
53 void drawNumber(_uint x, _uint y, _ulong n) {
54 _uint j = 0;
55 _uint i = n;
56 if (n == 0) {
57 drawDigit(x, y, 0);
58 return;
59 }
60 for(; i > 0; i /= 10)
61 j++;
62 i = n;
63 for(; i > 0; i /= 10) {
64 j--;
65 drawDigit(x + j * (WIDTHX + THICK * 2), y, i % 10);
66 }
67 }
68
69 /* Game logic */
70 _uint pieceX = SIZEX / 2;
71 _uint pieceY = 0;
72 uint8 pieceId = 0;
73 uint8 rotation = 0;
74
75 uint8 piecesLen[7][2] = {
76 {4, 0},
77 {3, 3},
78 {3, 3},
79 {2, 2},
80 {3, 3},
81 {3, 3},
82 {3, 3}
83 };
84
85 uint8 pieces[7][2][4] = {
86 {
87 { 1, 1, 1, 1 },
88 },
89 {
90 { 1, 0, 0 },
91 { 1, 1, 1 }
92 },
93 {
94 { 0, 0, 1 },
95 { 1, 1, 1 }
96 },
97 {
98 { 1, 1 },
99 { 1, 1 }
100 },
101 {
102 { 0, 1, 1 },
103 { 1, 1, 0 }
104 },
105 {
106 { 0, 1, 0 },
107 { 1, 1, 1 }
108 },
109 {
110 { 1, 1, 0 },
111 { 0, 1, 1 }
112 }
113 };
114
115 uint8 board[SIZEY * SIZEX];
116
117 _uint blocks[6][2];
118 uint8 getBlocks(_uint x, _uint y, uint8 c, uint8 r) {
119 _uint h = c == 0?1:2;
120 uint8 len = 0;
121 uint8 i = 0;
122 uint8 j = 0;
123 for (; i < h; j++) {
124 if (j >= piecesLen[c][i]) {
125 j = -1;
126 i++;
127 continue;
128 }
129 if (pieces[c][i][j] == 0) continue;
130 switch (r) {
131 case 0:
132 blocks[len][0] = x + i;
133 blocks[len][1] = y + j;
134 break;
135 case 1:
136 blocks[len][0] = x + j;
137 blocks[len][1] = y + i;
138 break;
139 case 2:
140 blocks[len][0] = x + h - i - 1;
141 blocks[len][1] = y + j;
142 break;
143 case 3:
144 blocks[len][0] = x + j;
145 blocks[len][1] = y + h - i - 1;
146 break;
147 }
148 len++;
149 }
150 return len;
151 }
152
153 void setPiece() {
154 uint8 len = getBlocks(pieceX, pieceY, pieceId, rotation);
155 uint8 i = 0;
156 for (; i < len; i++)
157 board[blocks[i][0] + blocks[i][1] * SIZEX] = pieceId + 1;
158 }
159
160 uint8 rotate() {
161 uint8 len = getBlocks(pieceX, pieceY, pieceId, (rotation+1)%4);
162 uint8 i = 0;
163 for (; i < len; i++)
164 if (blocks[i][1] >= SIZEY ||
165 blocks[i][0] >= SIZEX ||
166 board[SIZEX * blocks[i][1] + blocks[i][0]])
167 return 0;
168 rotation = (rotation + 1) % 4;
169 return 1;
170 }
171
172 int movePiece(_uint x, _uint y, uint8 m) {
173 uint8 len = getBlocks(x, y, pieceId, rotation);
174 uint8 i = 0;
175 for (; i < len; i++) {
176 if (blocks[i][1] >= SIZEY ||
177 blocks[i][0] >= SIZEX ||
178 board[SIZEX * (blocks[i][1]) + (blocks[i][0])])
179 return 0;
180 }
181 if (!m) return 1;
182 pieceX = x;
183 pieceY = y;
184 return 1;
185 }
186
187 void dropLine(_uint y) {
188 for (; y > 0; y--) {
189 _uint j = 0;
190 for (; j < SIZEX; j++)
191 board[y * SIZEX + j] = board[(y - 1) * SIZEX + j];
192 }
193 }
194
195 _uint checkLines() {
196 _uint l = 0;
197 _uint i = 0;
198 for (; i < SIZEY; i++) {
199 uint8 full = 1;
200 _uint j = 0;
201 for (; j < SIZEX; j++) {
202 if (board[i * SIZEX + j]) continue;
203 full = 0;
204 break;
205 }
206 if (!full) continue;
207 dropLine(i);
208 l++;
209 }
210 return l;
211 }
212
213 /* Rendering */
214 Rect rect;
215
216 #define RATIO rect.w / SIZEX
217 void drawBlock(int x, int y, int id) {
218 backend_fill(rect.x + x * RATIO, rect.y + y * RATIO,
219 RATIO, RATIO, id);
220 backend_draw(rect.x + x * RATIO, rect.y + y * RATIO,
221 RATIO, RATIO, id + 7);
222 }
223
224 void drawPiece() {
225 uint8 len = getBlocks(pieceX, pieceY, pieceId, rotation);
226 uint8 i = 0;
227 for (; i < len; i++)
228 drawBlock(blocks[i][0], blocks[i][1], pieceId);
229 }
230
231
232 int main() {
233 uint8 input = 0;
234 uint8 pressed = 0;
235 _uint tick = 0;
236 _ulong score = 0;
237
238 srand(time(0));
239 pieceId = rand() % 7;
240 memset(board, 0, SIZEY * SIZEX);
241
242 if (backend_init()) return -1;
243
244 while (1) {
245 _uint i = 0;
246 _uint width = backend_width - backend_width % SIZEX;
247 _uint height = backend_height - backend_height % SIZEY;
248 input = backend_input();
249 if (input & QUIT) break;
250 if (input & ROTATE) rotate();
251 if (input & LEFT) movePiece(pieceX - 1, pieceY, 1);
252 if (input & RIGHT) movePiece(pieceX + 1, pieceY, 1);
253 if (input & DOWN) {
254 while (movePiece(pieceX, pieceY + 1, 1))
255 pressed = 1;
256 if (!pressed)
257 tick = TICK * FPS / 1000 / 2;
258 }
259
260 tick++;
261 if (tick * 1000 / FPS >= TICK) {
262 _uint l;
263 tick = 0;
264 if (movePiece(pieceX, pieceY + 1, 1)) continue;
265 /* Piece on the ground */
266 setPiece();
267 score += 5;
268 l = checkLines();
269 score += l * l * 15;
270 pieceX = SIZEX / 2 - 1;
271 pieceY = 0;
272 pieceId = rand() % 7;
273 pressed = 0;
274 if (movePiece(pieceX, pieceY, 0)) continue;
275 /* Game over */
276 score = 0;
277 memset(board, 0, SIZEX * SIZEY);
278 }
279
280 if (backend_height * SIZEX / SIZEY - backend_width < 0) {
281 rect.x = (width - height * SIZEX / SIZEY) / 2;
282 rect.y = (backend_height - height) / 2;
283 rect.w = height * SIZEX / SIZEY;
284 rect.h = height * SIZEY / SIZEX / 2;
285 } else {
286 rect.x = (backend_width - width) / 2;
287 rect.y = (height - width * SIZEY / SIZEX) / 2;
288 rect.w = width * SIZEY / SIZEX / 2;
289 rect.h = width * SIZEY / SIZEX;
290 }
291
292 backend_fill(rect.x, rect.y, rect.w, rect.h + 1, BACKGROUND);
293
294 drawPiece();
295
296 for (; i < SIZEX * SIZEY; i++) {
297 if (!board[i]) continue;
298 drawBlock(i % SIZEX, i / SIZEX, board[i] - 1);
299 }
300
301 drawNumber((rect.x - WIDTHX * 15) > 0?i:THICK * 2,
302 rect.y + THICK * 4, score);
303
304 backend_refresh();
305 }
306
307 backend_clean();
308
309 return 0;
310 }
311