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
RevLine 
[3508000]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
[582a0b8]53static volatile const char copyright[] =
[1433ecda]54 "@(#) Copyright (c) 1992, 1993\n"
55 "\tThe Regents of the University of California. All rights reserved.\n";
[3508000]56
[bd41ac52]57#include <time.h>
[3508000]58#include <err.h>
59#include <errno.h>
[76d0981d]60#include <stdbool.h>
[3508000]61#include <stdio.h>
62#include <stdlib.h>
[582a0b8]63#include <stdint.h>
[3508000]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;
[a35b458]101
[3508000]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;
[a35b458]116
[3508000]117 for (i = A_FIRST; i < A_LAST; i++) {
118 base = i * B_COLS + 1;
119 p = &board[base];
[84239b1]120 j = B_COLS - 2;
121 while (*p++ != 0) {
[3508000]122 if (--j <= 0) {
123 /* This row is to be elided */
124 rows++;
[3bacee1]125 memset(&board[base], 0, sizeof(cell) * (B_COLS - 2));
[a35b458]126
[3508000]127 scr_update();
128 tsleep();
[a35b458]129
[3508000]130 while (--base != 0)
131 board[base + B_COLS] = board[base];
[a35b458]132
[3508000]133 scr_update();
134 tsleep();
[a35b458]135
[3508000]136 break;
137 }
138 }
139 }
[a35b458]140
[3508000]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{
[c718bda]161 const struct shape *tmp = &shapes[rand() % 7];
[3508000]162 int i;
[c718bda]163 int j = rand() % 4;
[a35b458]164
[3508000]165 for (i = 0; i < j; i++)
166 tmp = &shapes[classic ? tmp->rotc : tmp->rot];
[a35b458]167
[3508000]168 return (tmp);
169}
170
171static void srandomdev(void)
172{
[bd41ac52]173 struct timespec ts;
[a35b458]174
[bd41ac52]175 getuptime(&ts);
176 srand(tv.tv_sec + tv.tv_nsec / 100000000);
[3508000]177}
178
[1b20da0]179static void tetris_menu_draw(int level)
[3508000]180{
181 clear_screen();
182 moveto(5, 10);
[1abcf1d]183 puts("Tetris\n");
[a35b458]184
[3508000]185 moveto(8, 10);
186 printf("Level = %d (press keys 1 - 9 to change)", level);
187 moveto(9, 10);
[1433ecda]188 printf("Preview is %s (press 'p' to change)", (showpreview ? "on " : "off"));
[3508000]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);
[76d0981d]204 while (true) {
[3508000]205 int i = getchar();
[a35b458]206
[1433ecda]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;
[3508000]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;
[a35b458]253
[3508000]254 console = console_init(stdin, stdout);
[a35b458]255
[3508000]256 keys = "jkl pq";
[a35b458]257
[3508000]258 classic = 0;
259 showpreview = 1;
[a35b458]260
[3508000]261 while ((ch = getopt(argc, argv, "ck:ps")) != -1)
[1433ecda]262 switch (ch) {
[3508000]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':
[08e103d4]272 if (str_bytes(keys = optarg) != 6)
[3508000]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 }
[a35b458]284
[3508000]285 argc -= optind;
286 argv += optind;
[a35b458]287
[3508000]288 if (argc)
289 usage();
[a35b458]290
[3508000]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 }
[a35b458]296
[3508000]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 }
[a35b458]304
[3508000]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]);
[a35b458]309
[3508000]310 scr_init();
311 if (loadscores() != EOK)
312 initscores();
313
314 while (tetris_menu(&level)) {
315 fallrate = 1000000 / level;
[a35b458]316
[3508000]317 scr_clear();
318 setup_board();
[a35b458]319
[3508000]320 srandomdev();
321 scr_set();
[a35b458]322
[3508000]323 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
324 nextshape = randshape();
325 curshape = randshape();
[a35b458]326
[3508000]327 scr_msg(key_msg, 1);
[a35b458]328
[76d0981d]329 while (true) {
[3508000]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 }
[a35b458]342
[3508000]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();
[a35b458]350
[3508000]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;
[a35b458]358
[3508000]359 if (!fits_in(curshape, pos))
360 break;
[a35b458]361
[3508000]362 continue;
363 }
[a35b458]364
[3508000]365 /*
366 * Handle command keys.
367 */
368 if (c == keys[5]) {
369 /* quit */
370 break;
371 }
[a35b458]372
[3508000]373 if (c == keys[4]) {
374 static char msg[] =
375 "paused - press RETURN to continue";
[a35b458]376
[3508000]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());
[a35b458]384
[3508000]385 scr_msg(msg, 0);
386 scr_msg(key_msg, 1);
387 place(curshape, pos, 0);
388 continue;
389 }
[a35b458]390
[3508000]391 if (c == keys[0]) {
392 /* move left */
393 if (fits_in(curshape, pos - 1))
394 pos--;
395 continue;
396 }
[a35b458]397
[3508000]398 if (c == keys[1]) {
399 /* turn */
400 const struct shape *new =
401 &shapes[classic ? curshape->rotc : curshape->rot];
[a35b458]402
[3508000]403 if (fits_in(new, pos))
404 curshape = new;
405 continue;
406 }
[a35b458]407
[3508000]408 if (c == keys[2]) {
409 /* move right */
410 if (fits_in(curshape, pos + 1))
411 pos++;
412 continue;
413 }
[a35b458]414
[3508000]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 }
[a35b458]423
[3508000]424 if (c == '\f') {
425 scr_clear();
426 scr_msg(key_msg, 1);
427 }
428 }
[a35b458]429
[3508000]430 scr_clear();
431 loadscores();
432 insertscore(score, level);
433 savescores();
434 score = 0;
435 }
[a35b458]436
[3508000]437 scr_clear();
438 printf("\nGame over.\n");
439 scr_end();
[a35b458]440
[3508000]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.