💾 Archived View for gemini.rmf-dev.com › repo › Vaati › RXTetris › files › 6f2ea6cf1d60387e5b970a041… captured on 2022-07-16 at 17:11:45. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
0 /* See LICENSE for license details. */
1 #include "config.h"
2 #include <X11/X.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <time.h>
6 #include <math.h>
7 #include <X11/Xlib.h>
8 #include <X11/Xutil.h>
9 #include <X11/Xos.h>
10
11 Display *dis;
12 int screen;
13 Window win;
14 Pixmap buffer;
15 GC gc;
16
17 typedef struct Rect {
18 int x;
19 int y;
20 int w;
21 int h;
22 } Rect;
23
24 int colors[] = {
25 I_BLOCK,
26 J_BLOCK,
27 L_BLOCK,
28 SQ_BLOCK,
29 S_BLOCK,
30 T_BLOCK,
31 Z_BLOCK
32 };
33
34 int borderColors[6];
35
36 Rect gameRect;
37
38 int pieceX = SIZEX/2;
39 int pieceY = 0;
40 int pieceId = 0;
41 int rotation = 0;
42
43 unsigned char pLen[7][2] = {
44 {4,0},
45 {3,3},
46 {3,3},
47 {2,2},
48 {3,3},
49 {3,3},
50 {3,3}
51 };
52
53 char pieces[7][2][4] = {
54 {
55 { 1, 1, 1, 1 },
56 },
57 {
58 { 1, 0, 0 },
59 { 1, 1, 1 }
60 },
61 {
62 { 0, 0, 1 },
63 { 1, 1, 1 }
64 },
65 {
66 { 1, 1 },
67 { 1, 1 }
68 },
69 {
70 { 0, 1, 1 },
71 { 1, 1, 0 }
72 },
73 {
74 { 0, 1, 0 },
75 { 1, 1, 1 }
76 },
77 {
78 { 1, 1, 0 },
79 { 0, 1, 1 }
80 }
81 };
82
83 unsigned char game[SIZEY*SIZEX];
84
85 void drawBlock(int x, int y, int c) {
86 float s = ceil((float)gameRect.w/SIZEX);
87 Rect rect = {gameRect.x+x*s, gameRect.y+y*s, s, s};
88 XSetForeground(dis, gc, colors[c]);
89 XFillRectangle(dis, buffer, gc, rect.x, rect.y, rect.w, rect.h);
90 XSetForeground(dis, gc, borderColors[c]);
91 XDrawRectangle(dis, buffer, gc, rect.x, rect.y, rect.w, rect.h);
92 }
93
94 int blocks[6][2];
95 int getBlocks(int x, int y, int c, int r) {
96 int bLen = 0;
97 int h = c==0?1:2;
98 for (unsigned char i=0; i<h; i++) {
99 for (unsigned char j=0; j<pLen[c][i]; j++) {
100 if (pieces[c][i][j]==0) continue;
101 switch (r) {
102 case 0:
103 blocks[bLen][0] = x+i;
104 blocks[bLen][1] = y+j;
105 break;
106 case 1:
107 blocks[bLen][0] = x+j;
108 blocks[bLen][1] = y+i;
109 break;
110 case 2:
111 blocks[bLen][0] = x+h-i-1;
112 blocks[bLen][1] = y+j;
113 break;
114 case 3:
115 blocks[bLen][0] = x+j;
116 blocks[bLen][1] = y+h-i-1;
117 break;
118 }
119 bLen++;
120 }
121 }
122 return bLen;
123 }
124
125 void setPiece() {
126 int bLen = getBlocks(pieceX, pieceY, pieceId, rotation);
127 for (int i=0; i<bLen; i++)
128 game[blocks[i][0]+blocks[i][1]*SIZEX]=pieceId+1;
129 }
130
131 void drawPiece() {
132 int bLen = getBlocks(pieceX, pieceY, pieceId, rotation);
133 for (int i=0; i<bLen; i++)
134 drawBlock(blocks[i][0], blocks[i][1], pieceId);
135 }
136
137 int rotate() {
138 int bLen = getBlocks(pieceX, pieceY, pieceId, (rotation+1)%!)(MISSING);
139 for (int i=0; i<bLen; i++)
140 if (blocks[i][1]>=SIZEY||blocks[i][0]<0||blocks[i][0]>=SIZEX||game[SIZEX*blocks[i][1]+blocks[i][0]]!=0)
141 return 0;
142 rotation = (rotation+1)%!;(MISSING)
143 return 1;
144 }
145
146 int movePiece(int x, int y, int m) {
147 int bLen = getBlocks(x, y, pieceId, rotation);
148 for (int i=0; i<bLen; i++)
149 if (blocks[i][1]>=SIZEY||blocks[i][0]<0||blocks[i][0]>=SIZEX||game[SIZEX*(blocks[i][1])+(blocks[i][0])]!=0)
150 return 0;
151 if (m!=0) {
152 pieceX = x;
153 pieceY = y;
154 }
155 return 1;
156 }
157
158 void dropLine(int y) {
159 for (int i=y; i>0; i--) {
160 for (int j=0; j<SIZEX; j++)
161 game[i*SIZEX+j]=game[(i-1)*SIZEX+j];
162 }
163 }
164
165 int checkLine() {
166 int l=0;
167 for (int i=0; i<SIZEY; i++) {
168 int t=1;
169 for (int j=0; j<SIZEX; j++)
170 if (game[i*SIZEX+j]==0) t=0;
171 if (t==1) {
172 dropLine(i);
173 l++;
174 }
175 }
176 return l;
177 }
178
179 int main() {
180
181 srand(time(0));
182
183 int winW=640;
184 int winH=480;
185 pieceId = rand()%!;(MISSING)
186
187 memset(game, 0, SIZEY*SIZEX);
188
189 dis = XOpenDisplay((char*)0);
190 screen = DefaultScreen(dis);
191 win = XCreateSimpleWindow(dis, DefaultRootWindow(dis), 0, 0, winW, winH, 0, WhitePixel(dis, screen), BlackPixel(dis, screen));
192 XSetStandardProperties(dis, win, "Tetris", "Tetris", None, NULL, 0, NULL);
193 XSelectInput(dis, win, ExposureMask|ButtonPressMask|KeyPressMask|ButtonReleaseMask);
194 gc = XCreateGC(dis, win, 0,0);
195 XSetBackground(dis, gc, 0);
196 XSetForeground(dis, gc, 0);
197 XClearWindow(dis, win);
198 XMapRaised(dis, win);
199
200 int close = 0;
201 int tick = 0;
202 unsigned int score = 0;
203 XEvent event;
204 KeySym key;
205 char text[255];
206
207 for (int i=0; i<sizeof(colors)/sizeof(int); i++) {
208 unsigned char* bytes = (unsigned char*)&colors[i];
209 borderColors[i] = bytes[0]*0.75+((int)(bytes[1]*0.75)<<8)+((int)(bytes[2]*0.75)<<16);
210 }
211
212 Atom WM_DELETE_WINDOW = XInternAtom(dis, "WM_DELETE_WINDOW", 0);
213 XSetWMProtocols(dis, win, &WM_DELETE_WINDOW, 1);
214 int pressed = 0;
215 XWindowAttributes attr;
216 buffer = XCreatePixmap(dis, win, winW, winH, 24);
217 while (!close) {
218 while (XPending(dis)) {
219 XNextEvent(dis, &event);
220 switch (event.type) {
221 case ClientMessage:
222 if ((Atom)event.xclient.data.l[0]==WM_DELETE_WINDOW)
223 close=1;
224 break;
225 case Expose:
226 XClearWindow(dis, win);
227 XGetWindowAttributes(dis, win, &attr);
228 winW = attr.width;
229 winH = attr.height;
230 XFreePixmap(dis, buffer);
231 buffer = XCreatePixmap(dis, win, winW, winH, 24);
232 break;
233 case KeyPress:
234 switch (XLookupKeysym(&event.xkey, 0)) {
235 case XK_Escape:
236 close = 1;
237 break;
238 case XK_r:
239 case XK_space:
240 rotate();
241 break;
242 case XK_a:
243 case XK_Left:
244 movePiece(pieceX-1, pieceY, 1);
245 break;
246 case XK_d:
247 case XK_Right:
248 movePiece(pieceX+1, pieceY, 1);
249 break;
250 case XK_s:
251 case XK_Down:
252 while (movePiece(pieceX, pieceY+1, 1)) pressed++;
253 if (!pressed)
254 tick=TICK*FPS/1000/2;
255 break;
256 }
257 break;
258 }
259 }
260
261 tick++;
262 if (tick*1000/FPS>=TICK) {
263 tick = 0;
264 if (movePiece(pieceX, pieceY+1, 1)==0) {
265 setPiece();
266 score+=5;
267 int l = checkLine();
268 score+=l*l*15;
269 pieceX = SIZEX/2-1;
270 pieceY = 0;
271 pieceId = rand()%!;(MISSING)
272 pressed = 0;
273 if (movePiece(pieceX, pieceY, 0)==0) {
274 score = 0;
275 memset(game, 0, SIZEX*SIZEY);
276 }
277 }
278 }
279
280 Rect rect = gameRect;
281 int _winW = winW-winW%!S(MISSING)IZEX;
282 int _winH = winH-winH%!S(MISSING)IZEY;
283 if (winH*SIZEX/SIZEY-winW<0) {
284 Rect r = {(_winW-_winH*SIZEX/SIZEY)/2, (winH-_winH)/2, _winH*SIZEX/SIZEY, _winH*SIZEY/SIZEX/2};
285 rect = gameRect = r;
286 rect.w = ceil((float)gameRect.w/SIZEX)*SIZEX;
287 } else {
288 Rect r = {(winW-_winW)/2, (_winH-_winW*SIZEY/SIZEX)/2, _winW*SIZEY/SIZEX/2, _winW*SIZEY/SIZEX};
289 rect = gameRect = r;
290 rect.h = ceil((float)gameRect.w/SIZEX)*SIZEY;
291 }
292
293 XSetForeground(dis, gc, 0);
294 XFillRectangle(dis, buffer, gc, 0, 0, winW, winH);
295
296 XSetForeground(dis, gc, BACKGROUND);
297 XFillRectangle(dis, buffer, gc, rect.x, rect.y, rect.w+1, rect.h);
298
299 drawPiece();
300
301 for (int i=0; i<SIZEX*SIZEY; i++) {
302 if (game[i]!=0)
303 drawBlock(i%!S(MISSING)IZEX,i/SIZEX,game[i]-1);
304 }
305
306 XSetForeground(dis, gc, TEXT);
307 XTextItem ti = {text, strnlen(text, 255), 0, None};
308 snprintf(text, 255, "Score : %!u(MISSING)", score);
309 XDrawText(dis, buffer, gc, 8, 16, &ti, 1);
310
311 XCopyArea(dis, buffer, win, gc, 0, 0, winW, winH, 0, 0);
312
313 usleep(1000*1000/FPS);
314 }
315
316 XFreeGC(dis, gc);
317 XDestroyWindow(dis, win);
318 XCloseDisplay(dis);
319
320 return 0;
321 }
322