Remove unistd.h
[helenos.git] / uspace / dist / src / c / demos / tetris / tetris.c
blobb48f62a95d5b755a820681575e2436fecb1f2723
1 /*
2 * Copyright (c) 2011 Martin Decky
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
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.
29 /** Attributations
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
35 * Based upon BSD Tetris
37 * Copyright (c) 1992, 1993
38 * The Regents of the University of California.
39 * Distributed under BSD license.
41 * This code is derived from software contributed to Berkeley by
42 * Chris Torek and Darren F. Provine.
46 /** @addtogroup tetris Tetris
47 * @brief Tetris ported from OpenBSD
48 * @{
50 /** @file
53 static volatile const char copyright[] =
54 "@(#) Copyright (c) 1992, 1993\n"
55 "\tThe Regents of the University of California. All rights reserved.\n";
57 #include <sys/time.h>
58 #include <sys/types.h>
59 #include <err.h>
60 #include <errno.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"
70 cell board[B_SIZE];
72 int Rows;
73 int Cols;
75 const struct shape *curshape;
76 const struct shape *nextshape;
78 long fallrate;
79 int score;
80 char key_msg[100];
81 int showpreview;
82 int classic;
84 static void elide(void);
85 static void setup_board(void);
86 static const struct shape *randshape(void);
88 static void usage(void);
90 static int firstgame = 1;
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.
97 static void setup_board(void)
99 int i;
100 cell *p = board;
102 for (i = B_SIZE; i; i--)
103 *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 0x0000ff : 0x000000;
107 * Elide any full active rows.
109 static void elide(void)
111 int rows = 0;
112 int i;
113 int j;
114 int base;
115 cell *p;
117 for (i = A_FIRST; i < A_LAST; i++) {
118 base = i * B_COLS + 1;
119 p = &board[base];
120 for (j = B_COLS - 2; *p++ != 0;) {
121 if (--j <= 0) {
122 /* This row is to be elided */
123 rows++;
124 memset(&board[base], 0, sizeof(cell) * (B_COLS - 2));
126 scr_update();
127 tsleep();
129 while (--base != 0)
130 board[base + B_COLS] = board[base];
132 scr_update();
133 tsleep();
135 break;
140 switch (rows) {
141 case 1:
142 score += 10;
143 break;
144 case 2:
145 score += 30;
146 break;
147 case 3:
148 score += 70;
149 break;
150 case 4:
151 score += 150;
152 break;
153 default:
154 break;
158 const struct shape *randshape(void)
160 const struct shape *tmp = &shapes[random() % 7];
161 int i;
162 int j = random() % 4;
164 for (i = 0; i < j; i++)
165 tmp = &shapes[classic ? tmp->rotc : tmp->rot];
167 return (tmp);
170 static void srandomdev(void)
172 struct timeval tv;
174 gettimeofday(&tv, NULL);
175 srandom(tv.tv_sec + tv.tv_usec / 100000);
178 static void tetris_menu_draw(int level)
180 clear_screen();
181 moveto(5, 10);
182 puts("Tetris\n\n");
184 moveto(8, 10);
185 printf("Level = %d (press keys 1 - 9 to change)", level);
186 moveto(9, 10);
187 printf("Preview is %s (press 'p' to change)", (showpreview ? "on ": "off"));
188 moveto(12, 10);
189 printf("Press 'h' to show hiscore table.");
190 moveto(13, 10);
191 printf("Press 's' to start game.");
192 moveto(14, 10);
193 printf("Press 'q' to quit game.");
194 moveto(20, 10);
195 printf("In game controls:");
196 moveto(21, 0);
197 puts(key_msg);
200 static int tetris_menu(int *level)
202 tetris_menu_draw(*level);
203 while (1) {
204 int i = getchar();
206 switch(i) {
207 case 'p':
208 showpreview = !showpreview;
209 moveto(9, 21);
210 if (showpreview)
211 printf("on ");
212 else
213 printf("off");
214 break;
215 case 'h':
216 loadscores();
217 showscores(firstgame);
218 tetris_menu_draw(*level);
219 break;
220 case 's':
221 firstgame = 0;
222 return 1;
223 case 'q':
224 return 0;
225 case '1':
226 case '2':
227 case '3':
228 case '4':
229 case '5':
230 case '6':
231 case '7':
232 case '8':
233 case '9':
234 *level = i - '0';
235 moveto(8, 18);
236 printf("%d", *level);
237 break;
242 int main(int argc, char *argv[])
244 int pos;
245 int c;
246 const char *keys;
247 int level = 2;
248 char key_write[6][10];
249 int i;
250 int j;
251 int ch;
253 console = console_init(stdin, stdout);
255 keys = "jkl pq";
257 classic = 0;
258 showpreview = 1;
260 while ((ch = getopt(argc, argv, "ck:ps")) != -1)
261 switch(ch) {
262 case 'c':
264 * this means:
265 * - rotate the other way
266 * - no reverse video
268 classic = 1;
269 break;
270 case 'k':
271 if (str_size(keys = optarg) != 6)
272 usage();
273 break;
274 case 'p':
275 showpreview = 1;
276 break;
277 case 's':
278 showscores(0);
279 exit(0);
280 default:
281 usage();
284 argc -= optind;
285 argv += optind;
287 if (argc)
288 usage();
290 for (i = 0; i <= 5; i++) {
291 for (j = i + 1; j <= 5; j++) {
292 if (keys[i] == keys[j])
293 errx(1, "%s", "duplicate command keys specified.");
296 if (keys[i] == ' ')
297 str_cpy(key_write[i], sizeof(key_write[i]), "<space>");
298 else {
299 key_write[i][0] = keys[i];
300 key_write[i][1] = '\0';
304 snprintf(key_msg, sizeof(key_msg),
305 "%s - left %s - rotate %s - right %s - drop %s - pause %s - quit",
306 key_write[0], key_write[1], key_write[2], key_write[3],
307 key_write[4], key_write[5]);
309 scr_init();
310 if (loadscores() != EOK)
311 initscores();
313 while (tetris_menu(&level)) {
314 fallrate = 1000000 / level;
316 scr_clear();
317 setup_board();
319 srandomdev();
320 scr_set();
322 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
323 nextshape = randshape();
324 curshape = randshape();
326 scr_msg(key_msg, 1);
328 while (1) {
329 place(curshape, pos, 1);
330 scr_update();
331 place(curshape, pos, 0);
332 c = tgetchar();
333 if (c < 0) {
335 * Timeout. Move down if possible.
337 if (fits_in(curshape, pos + B_COLS)) {
338 pos += B_COLS;
339 continue;
343 * Put up the current shape `permanently',
344 * bump score, and elide any full rows.
346 place(curshape, pos, 1);
347 score++;
348 elide();
351 * Choose a new shape. If it does not fit,
352 * the game is over.
354 curshape = nextshape;
355 nextshape = randshape();
356 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
358 if (!fits_in(curshape, pos))
359 break;
361 continue;
365 * Handle command keys.
367 if (c == keys[5]) {
368 /* quit */
369 break;
372 if (c == keys[4]) {
373 static char msg[] =
374 "paused - press RETURN to continue";
376 place(curshape, pos, 1);
377 do {
378 scr_update();
379 scr_msg(key_msg, 0);
380 scr_msg(msg, 1);
381 console_flush(console);
382 } while (!twait());
384 scr_msg(msg, 0);
385 scr_msg(key_msg, 1);
386 place(curshape, pos, 0);
387 continue;
390 if (c == keys[0]) {
391 /* move left */
392 if (fits_in(curshape, pos - 1))
393 pos--;
394 continue;
397 if (c == keys[1]) {
398 /* turn */
399 const struct shape *new =
400 &shapes[classic ? curshape->rotc : curshape->rot];
402 if (fits_in(new, pos))
403 curshape = new;
404 continue;
407 if (c == keys[2]) {
408 /* move right */
409 if (fits_in(curshape, pos + 1))
410 pos++;
411 continue;
414 if (c == keys[3]) {
415 /* move to bottom */
416 while (fits_in(curshape, pos + B_COLS)) {
417 pos += B_COLS;
418 score++;
420 continue;
423 if (c == '\f') {
424 scr_clear();
425 scr_msg(key_msg, 1);
429 scr_clear();
430 loadscores();
431 insertscore(score, level);
432 savescores();
433 score = 0;
436 scr_clear();
437 printf("\nGame over.\n");
438 scr_end();
440 return 0;
443 void usage(void)
445 fprintf(stderr, "usage: tetris [-ps] [-k keys]\n");
446 exit(1);
449 /** @}