source: mainline/uspace/dist/src/c/demos/tetris/tetris.c@ 08e103d4

Last change on this file since 08e103d4 was 08e103d4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use clearer naming for string length functions

This and the following commit change the names of functions, as well as
their documentation, to use unambiguous terms "bytes" and "code points"
instead of ambiguous terms "size", "length", and "characters".

  • Property mode set to 100644
File size: 8.5 KB
Line 
1/*
2 * Copyright (c) 2011 Martin Decky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** Attributations
30 *
31 * tetris.c 8.1 (Berkeley) 5/31/93
32 * NetBSD: tetris.c,v 1.2 1995/04/22 07:42:47 cgd
33 * OpenBSD: tetris.c,v 1.21 2006/04/20 03:24:12 ray
34 *
35 * Based upon BSD Tetris
36 *
37 * Copyright (c) 1992, 1993
38 * The Regents of the University of California.
39 * Distributed under BSD license.
40 *
41 * This code is derived from software contributed to Berkeley by
42 * Chris Torek and Darren F. Provine.
43 *
44 */
45
46/** @addtogroup tetris Tetris
47 * @brief Tetris ported from OpenBSD
48 * @{
49 */
50/** @file
51 */
52
53static volatile const char copyright[] =
54 "@(#) Copyright (c) 1992, 1993\n"
55 "\tThe Regents of the University of California. All rights reserved.\n";
56
57#include <time.h>
58#include <err.h>
59#include <errno.h>
60#include <stdbool.h>
61#include <stdio.h>
62#include <stdlib.h>
63#include <stdint.h>
64#include <str.h>
65#include <getopt.h>
66#include "scores.h"
67#include "screen.h"
68#include "tetris.h"
69
70cell board[B_SIZE];
71
72int Rows;
73int Cols;
74
75const struct shape *curshape;
76const struct shape *nextshape;
77
78long fallrate;
79int score;
80char key_msg[100];
81int showpreview;
82int classic;
83
84static void elide(void);
85static void setup_board(void);
86static const struct shape *randshape(void);
87
88static void usage(void);
89
90static int firstgame = 1;
91
92/*
93 * Set up the initial board. The bottom display row is completely set,
94 * along with another (hidden) row underneath that. Also, the left and
95 * right edges are set.
96 */
97static void setup_board(void)
98{
99 int i;
100 cell *p = board;
101
102 for (i = B_SIZE; i; i--)
103 *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 0x0000ff : 0x000000;
104}
105
106/*
107 * Elide any full active rows.
108 */
109static void elide(void)
110{
111 int rows = 0;
112 int i;
113 int j;
114 int base;
115 cell *p;
116
117 for (i = A_FIRST; i < A_LAST; i++) {
118 base = i * B_COLS + 1;
119 p = &board[base];
120 j = B_COLS - 2;
121 while (*p++ != 0) {
122 if (--j <= 0) {
123 /* This row is to be elided */
124 rows++;
125 memset(&board[base], 0, sizeof(cell) * (B_COLS - 2));
126
127 scr_update();
128 tsleep();
129
130 while (--base != 0)
131 board[base + B_COLS] = board[base];
132
133 scr_update();
134 tsleep();
135
136 break;
137 }
138 }
139 }
140
141 switch (rows) {
142 case 1:
143 score += 10;
144 break;
145 case 2:
146 score += 30;
147 break;
148 case 3:
149 score += 70;
150 break;
151 case 4:
152 score += 150;
153 break;
154 default:
155 break;
156 }
157}
158
159const struct shape *randshape(void)
160{
161 const struct shape *tmp = &shapes[rand() % 7];
162 int i;
163 int j = rand() % 4;
164
165 for (i = 0; i < j; i++)
166 tmp = &shapes[classic ? tmp->rotc : tmp->rot];
167
168 return (tmp);
169}
170
171static void srandomdev(void)
172{
173 struct timespec ts;
174
175 getuptime(&ts);
176 srand(tv.tv_sec + tv.tv_nsec / 100000000);
177}
178
179static void tetris_menu_draw(int level)
180{
181 clear_screen();
182 moveto(5, 10);
183 puts("Tetris\n");
184
185 moveto(8, 10);
186 printf("Level = %d (press keys 1 - 9 to change)", level);
187 moveto(9, 10);
188 printf("Preview is %s (press 'p' to change)", (showpreview ? "on " : "off"));
189 moveto(12, 10);
190 printf("Press 'h' to show hiscore table.");
191 moveto(13, 10);
192 printf("Press 's' to start game.");
193 moveto(14, 10);
194 printf("Press 'q' to quit game.");
195 moveto(20, 10);
196 printf("In game controls:");
197 moveto(21, 0);
198 puts(key_msg);
199}
200
201static int tetris_menu(int *level)
202{
203 tetris_menu_draw(*level);
204 while (true) {
205 int i = getchar();
206
207 switch (i) {
208 case 'p':
209 showpreview = !showpreview;
210 moveto(9, 21);
211 if (showpreview)
212 printf("on ");
213 else
214 printf("off");
215 break;
216 case 'h':
217 loadscores();
218 showscores(firstgame);
219 tetris_menu_draw(*level);
220 break;
221 case 's':
222 firstgame = 0;
223 return 1;
224 case 'q':
225 return 0;
226 case '1':
227 case '2':
228 case '3':
229 case '4':
230 case '5':
231 case '6':
232 case '7':
233 case '8':
234 case '9':
235 *level = i - '0';
236 moveto(8, 18);
237 printf("%d", *level);
238 break;
239 }
240 }
241}
242
243int main(int argc, char *argv[])
244{
245 int pos;
246 int c;
247 const char *keys;
248 int level = 2;
249 char key_write[6][10];
250 int i;
251 int j;
252 int ch;
253
254 console = console_init(stdin, stdout);
255
256 keys = "jkl pq";
257
258 classic = 0;
259 showpreview = 1;
260
261 while ((ch = getopt(argc, argv, "ck:ps")) != -1)
262 switch (ch) {
263 case 'c':
264 /*
265 * this means:
266 * - rotate the other way
267 * - no reverse video
268 */
269 classic = 1;
270 break;
271 case 'k':
272 if (str_bytes(keys = optarg) != 6)
273 usage();
274 break;
275 case 'p':
276 showpreview = 1;
277 break;
278 case 's':
279 showscores(0);
280 exit(0);
281 default:
282 usage();
283 }
284
285 argc -= optind;
286 argv += optind;
287
288 if (argc)
289 usage();
290
291 for (i = 0; i <= 5; i++) {
292 for (j = i + 1; j <= 5; j++) {
293 if (keys[i] == keys[j])
294 errx(1, "%s", "duplicate command keys specified.");
295 }
296
297 if (keys[i] == ' ')
298 str_cpy(key_write[i], sizeof(key_write[i]), "<space>");
299 else {
300 key_write[i][0] = keys[i];
301 key_write[i][1] = '\0';
302 }
303 }
304
305 snprintf(key_msg, sizeof(key_msg),
306 "%s - left %s - rotate %s - right %s - drop %s - pause %s - quit",
307 key_write[0], key_write[1], key_write[2], key_write[3],
308 key_write[4], key_write[5]);
309
310 scr_init();
311 if (loadscores() != EOK)
312 initscores();
313
314 while (tetris_menu(&level)) {
315 fallrate = 1000000 / level;
316
317 scr_clear();
318 setup_board();
319
320 srandomdev();
321 scr_set();
322
323 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
324 nextshape = randshape();
325 curshape = randshape();
326
327 scr_msg(key_msg, 1);
328
329 while (true) {
330 place(curshape, pos, 1);
331 scr_update();
332 place(curshape, pos, 0);
333 c = tgetchar();
334 if (c < 0) {
335 /*
336 * Timeout. Move down if possible.
337 */
338 if (fits_in(curshape, pos + B_COLS)) {
339 pos += B_COLS;
340 continue;
341 }
342
343 /*
344 * Put up the current shape `permanently',
345 * bump score, and elide any full rows.
346 */
347 place(curshape, pos, 1);
348 score++;
349 elide();
350
351 /*
352 * Choose a new shape. If it does not fit,
353 * the game is over.
354 */
355 curshape = nextshape;
356 nextshape = randshape();
357 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
358
359 if (!fits_in(curshape, pos))
360 break;
361
362 continue;
363 }
364
365 /*
366 * Handle command keys.
367 */
368 if (c == keys[5]) {
369 /* quit */
370 break;
371 }
372
373 if (c == keys[4]) {
374 static char msg[] =
375 "paused - press RETURN to continue";
376
377 place(curshape, pos, 1);
378 do {
379 scr_update();
380 scr_msg(key_msg, 0);
381 scr_msg(msg, 1);
382 console_flush(console);
383 } while (!twait());
384
385 scr_msg(msg, 0);
386 scr_msg(key_msg, 1);
387 place(curshape, pos, 0);
388 continue;
389 }
390
391 if (c == keys[0]) {
392 /* move left */
393 if (fits_in(curshape, pos - 1))
394 pos--;
395 continue;
396 }
397
398 if (c == keys[1]) {
399 /* turn */
400 const struct shape *new =
401 &shapes[classic ? curshape->rotc : curshape->rot];
402
403 if (fits_in(new, pos))
404 curshape = new;
405 continue;
406 }
407
408 if (c == keys[2]) {
409 /* move right */
410 if (fits_in(curshape, pos + 1))
411 pos++;
412 continue;
413 }
414
415 if (c == keys[3]) {
416 /* move to bottom */
417 while (fits_in(curshape, pos + B_COLS)) {
418 pos += B_COLS;
419 score++;
420 }
421 continue;
422 }
423
424 if (c == '\f') {
425 scr_clear();
426 scr_msg(key_msg, 1);
427 }
428 }
429
430 scr_clear();
431 loadscores();
432 insertscore(score, level);
433 savescores();
434 score = 0;
435 }
436
437 scr_clear();
438 printf("\nGame over.\n");
439 scr_end();
440
441 return 0;
442}
443
444void usage(void)
445{
446 fprintf(stderr, "usage: tetris [-ps] [-k keys]\n");
447 exit(1);
448}
449
450/** @}
451 */
Note: See TracBrowser for help on using the repository browser.