compositor: fix the over operator
[helenos.git] / uspace / app / tetris / tetris.c
blob15dfcc7a4fa29e96087e387f592a9fbef3754c9a
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
47 * @{
49 /** @file
52 static volatile const char copyright[] =
53 "@(#) Copyright (c) 1992, 1993\n"
54 "\tThe Regents of the University of California. All rights reserved.\n";
56 #include <time.h>
57 #include <errno.h>
58 #include <stdbool.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <stdint.h>
62 #include <str.h>
63 #include <getopt.h>
64 #include "scores.h"
65 #include "screen.h"
66 #include "tetris.h"
68 cell board[B_SIZE];
70 int Rows;
71 int Cols;
73 const struct shape *curshape;
74 const struct shape *nextshape;
76 long fallrate;
77 int score;
78 char key_msg[116];
79 int showpreview;
80 int classic;
82 static void elide(void);
83 static void setup_board(void);
84 static const struct shape *randshape(void);
86 static void usage(void);
88 static int firstgame = 1;
91 * Set up the initial board. The bottom display row is completely set,
92 * along with another (hidden) row underneath that. Also, the left and
93 * right edges are set.
95 static void setup_board(void)
97 int i;
98 cell *p = board;
100 for (i = B_SIZE; i; i--)
101 *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 0x0000ff : 0x000000;
105 * Elide any full active rows.
107 static void elide(void)
109 int rows = 0;
110 int i;
111 int j;
112 int base;
113 cell *p;
115 for (i = A_FIRST; i < A_LAST; i++) {
116 base = i * B_COLS + 1;
117 p = &board[base];
118 j = B_COLS - 2;
119 while (*p++ != 0) {
120 if (--j <= 0) {
121 /* This row is to be elided */
122 rows++;
123 memset(&board[base], 0, sizeof(cell) * (B_COLS - 2));
125 scr_update();
126 tsleep();
128 while (--base != 0)
129 board[base + B_COLS] = board[base];
131 scr_update();
132 tsleep();
134 break;
139 switch (rows) {
140 case 1:
141 score += 10;
142 break;
143 case 2:
144 score += 30;
145 break;
146 case 3:
147 score += 70;
148 break;
149 case 4:
150 score += 150;
151 break;
152 default:
153 break;
157 const struct shape *randshape(void)
159 const struct shape *tmp = &shapes[rand() % 7];
160 int i;
161 int j = rand() % 4;
163 for (i = 0; i < j; i++)
164 tmp = &shapes[classic ? tmp->rotc : tmp->rot];
166 return (tmp);
169 static void srandomdev(void)
171 struct timespec ts;
173 getrealtime(&ts);
174 srand(ts.tv_sec + ts.tv_nsec / 100000000);
177 static void tetris_menu_draw(int level)
179 clear_screen();
180 moveto(5, 10);
181 puts("Tetris\n");
183 moveto(8, 10);
184 printf("Level = %d (press keys 1 - 9 to change)", level);
185 moveto(9, 10);
186 printf("Preview is %s (press 'p' to change)", (showpreview ? "on " : "off"));
187 moveto(12, 10);
188 printf("Press 'h' to show hiscore table.");
189 moveto(13, 10);
190 printf("Press 's' to start game.");
191 moveto(14, 10);
192 printf("Press 'q' to quit game.");
193 moveto(20, 10);
194 printf("In game controls:");
195 moveto(21, 0);
196 printf("%s", key_msg);
199 static int tetris_menu(int *level)
201 tetris_menu_draw(*level);
202 while (true) {
203 int i = getchar();
205 switch (i) {
206 case 'p':
207 showpreview = !showpreview;
208 moveto(9, 21);
209 if (showpreview)
210 printf("on ");
211 else
212 printf("off");
213 break;
214 case 'h':
215 loadscores();
216 showscores(firstgame);
217 tetris_menu_draw(*level);
218 break;
219 case 's':
220 firstgame = 0;
221 return 1;
222 case 'q':
223 return 0;
224 case '1':
225 case '2':
226 case '3':
227 case '4':
228 case '5':
229 case '6':
230 case '7':
231 case '8':
232 case '9':
233 *level = i - '0';
234 moveto(8, 18);
235 printf("%d", *level);
236 break;
241 int main(int argc, char *argv[])
243 int pos;
244 int c;
245 const char *keys;
246 int level = 2;
247 char key_write[6][10];
248 int i;
249 int j;
250 int ch;
252 console = console_init(stdin, stdout);
254 keys = "jkl pq";
256 classic = 0;
257 showpreview = 1;
259 while ((ch = getopt(argc, argv, "ck:ps")) != -1)
260 switch (ch) {
261 case 'c':
263 * this means:
264 * - rotate the other way
265 * - no reverse video
267 classic = 1;
268 break;
269 case 'k':
270 if (str_size(keys = optarg) != 6)
271 usage();
272 break;
273 case 'p':
274 showpreview = 1;
275 break;
276 case 's':
277 showscores(0);
278 exit(0);
279 default:
280 usage();
283 argc -= optind;
284 argv += optind;
286 if (argc)
287 usage();
289 for (i = 0; i <= 5; i++) {
290 for (j = i + 1; j <= 5; j++) {
291 if (keys[i] == keys[j]) {
292 fprintf(stderr, "duplicate command keys specified.");
293 abort();
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';
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]);
310 scr_init();
311 if (loadscores() != EOK)
312 initscores();
314 while (tetris_menu(&level)) {
315 fallrate = 1000000 / level;
317 scr_clear();
318 setup_board();
320 srandomdev();
321 scr_set();
323 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
324 nextshape = randshape();
325 curshape = randshape();
327 scr_msg(key_msg, 1);
329 while (true) {
330 place(curshape, pos, 1);
331 scr_update();
332 place(curshape, pos, 0);
333 c = tgetchar();
334 if (c < 0) {
336 * Timeout. Move down if possible.
338 if (fits_in(curshape, pos + B_COLS)) {
339 pos += B_COLS;
340 continue;
344 * Put up the current shape `permanently',
345 * bump score, and elide any full rows.
347 place(curshape, pos, 1);
348 score++;
349 elide();
352 * Choose a new shape. If it does not fit,
353 * the game is over.
355 curshape = nextshape;
356 nextshape = randshape();
357 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
359 if (!fits_in(curshape, pos))
360 break;
362 continue;
366 * Handle command keys.
368 if (c == keys[5]) {
369 /* quit */
370 break;
373 if (c == keys[4]) {
374 static char msg[] =
375 "paused - press RETURN to continue";
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());
385 scr_msg(msg, 0);
386 scr_msg(key_msg, 1);
387 place(curshape, pos, 0);
388 continue;
391 if (c == keys[0]) {
392 /* move left */
393 if (fits_in(curshape, pos - 1))
394 pos--;
395 continue;
398 if (c == keys[1]) {
399 /* turn */
400 const struct shape *new =
401 &shapes[classic ? curshape->rotc : curshape->rot];
403 if (fits_in(new, pos))
404 curshape = new;
405 continue;
408 if (c == keys[2]) {
409 /* move right */
410 if (fits_in(curshape, pos + 1))
411 pos++;
412 continue;
415 if (c == keys[3]) {
416 /* move to bottom */
417 while (fits_in(curshape, pos + B_COLS)) {
418 pos += B_COLS;
419 score++;
421 continue;
424 if (c == '\f') {
425 scr_clear();
426 scr_msg(key_msg, 1);
430 scr_clear();
431 loadscores();
432 insertscore(score, level);
433 savescores();
434 score = 0;
437 scr_clear();
438 printf("\nGame over.\n");
439 scr_end();
441 return 0;
444 void usage(void)
446 fprintf(stderr, "%s", copyright);
447 fprintf(stderr, "usage: tetris [-ps] [-k keys]\n");
448 exit(1);
451 /** @}