source: mainline/uspace/dist/src/c/demos/tetris/tetris.c@ 205f1add

Last change on this file since 205f1add was 205f1add, checked in by Jakub Jermar <jakub@…>, 7 years ago

Get rid of sys/time.h

This commit moves the POSIX-like time functionality from libc's
sys/time.h to libposix and introduces C99-like or HelenOS-specific
interfaces to libc.

Specifically, use of sys/time.h, struct timeval, suseconds_t and
gettimeofday is replaced by time.h (C99), struct timespec (C99),
usec_t (HelenOS) and getuptime / getrealtime (HelenOS).

  • 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
[205f1add]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{
[205f1add]173 struct timespec ts;
[a35b458]174
[205f1add]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':
272 if (str_size(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 }
[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.