source: mainline/uspace/app/tetris/tetris.c@ a405563

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a405563 was a405563, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

Fix some warnings.

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