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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ebe70f1 was ebe70f1, checked in by Martin Decky <martin@…>, 16 years ago

slightly cleanup the horrible mess of tetris
introduce colors

  • Property mode set to 100644
File size: 8.5 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>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <unistd.h>
[ebe70f1]56#include <getopt.h>
[e9a3c52]57
58#include "input.h"
59#include "scores.h"
60#include "screen.h"
61#include "tetris.h"
62
[ebe70f1]63cell board[B_SIZE];
64
65int Rows;
66int Cols;
67
[e9a3c52]68const struct shape *curshape;
69const struct shape *nextshape;
70
[ebe70f1]71long fallrate;
72int score;
73char key_msg[100];
74int showpreview;
75int classic;
76
77static void elide(void);
78static void setup_board(void);
79static const struct shape *randshape(void);
80
81static void usage(void);
82
83static int firstgame = 1;
[e9a3c52]84
85/*
[ebe70f1]86 * Set up the initial board. The bottom display row is completely set,
87 * along with another (hidden) row underneath that. Also, the left and
[e9a3c52]88 * right edges are set.
89 */
[ebe70f1]90static void setup_board(void)
[e9a3c52]91{
92 int i;
[ebe70f1]93 cell *p = board;
94
[e9a3c52]95 for (i = B_SIZE; i; i--)
[ebe70f1]96 *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 0x0000ff : 0x000000;
[e9a3c52]97}
98
99/*
100 * Elide any full active rows.
101 */
[ebe70f1]102static void elide(void)
[e9a3c52]103{
104 int rows = 0;
[ebe70f1]105 int i;
106 int j;
107 int base;
[e9a3c52]108 cell *p;
[ebe70f1]109
[e9a3c52]110 for (i = A_FIRST; i < A_LAST; i++) {
111 base = i * B_COLS + 1;
112 p = &board[base];
113 for (j = B_COLS - 2; *p++ != 0;) {
114 if (--j <= 0) {
[ebe70f1]115 /* This row is to be elided */
[e9a3c52]116 rows++;
[ebe70f1]117 memset(&board[base], 0, sizeof(cell) * (B_COLS - 2));
118
[e9a3c52]119 scr_update();
120 tsleep();
[ebe70f1]121
[e9a3c52]122 while (--base != 0)
123 board[base + B_COLS] = board[base];
[ebe70f1]124
[e9a3c52]125 scr_update();
126 tsleep();
[ebe70f1]127
[e9a3c52]128 break;
129 }
130 }
131 }
[ebe70f1]132
[e9a3c52]133 switch (rows) {
134 case 1:
135 score += 10;
136 break;
137 case 2:
138 score += 30;
139 break;
140 case 3:
141 score += 70;
142 break;
143 case 4:
144 score += 150;
145 break;
146 default:
147 break;
148 }
149}
150
[ebe70f1]151const struct shape *randshape(void)
[e9a3c52]152{
[ebe70f1]153 const struct shape *tmp = &shapes[random() % 7];
154 int i;
155 int j = random() % 4;
156
[e9a3c52]157 for (i = 0; i < j; i++)
[ebe70f1]158 tmp = &shapes[classic ? tmp->rotc : tmp->rot];
159
[e9a3c52]160 return (tmp);
161}
[c594489]162
163static void srandomdev(void)
164{
165 struct timeval tv;
[ebe70f1]166
[c594489]167 gettimeofday(&tv, NULL);
168 srandom(tv.tv_sec + tv.tv_usec / 100000);
169}
[e9a3c52]170
[9996ed5]171static void tetris_menu_draw(int level)
172{
[ebe70f1]173 clear_screen();
174 moveto(5, 10);
175 puts("Tetris\n\n");
176
177 moveto(8, 10);
178 printf("Level = %d (press keys 1 - 9 to change)", level);
179 moveto(9, 10);
180 printf("Preview is %s (press 'p' to change)", (showpreview ? "on ": "off"));
181 moveto(12, 10);
182 printf("Press 'h' to show hiscore table.");
183 moveto(13, 10);
184 printf("Press 's' to start game.");
185 moveto(14, 10);
186 printf("Press 'q' to quit game.");
187 moveto(20, 10);
188 printf("In game controls:");
189 moveto(21, 0);
190 puts(key_msg);
[9996ed5]191}
192
[ebe70f1]193static int tetris_menu(int *level)
[9996ed5]194{
195 tetris_menu_draw(*level);
196 while (1) {
[ebe70f1]197 int i = getchar();
[9996ed5]198
199 switch(i) {
200 case 'p':
201 showpreview = !showpreview;
[ebe70f1]202 moveto(9, 21);
[9996ed5]203 if (showpreview)
204 printf("on ");
205 else
206 printf("off");
207 break;
208 case 'h':
209 showscores(firstgame);
210 tetris_menu_draw(*level);
211 break;
212 case 's':
213 firstgame = 0;
214 return 1;
215 case 'q':
216 return 0;
217 case '1':
218 case '2':
219 case '3':
220 case '4':
221 case '5':
[ebe70f1]222 case '6':
[9996ed5]223 case '7':
224 case '8':
225 case '9':
226 *level = i - '0';
[ebe70f1]227 moveto(8, 18);
[9996ed5]228 printf("%d", *level);
229 break;
230 }
231 }
232}
233
[ebe70f1]234int main(int argc, char *argv[])
[e9a3c52]235{
[ebe70f1]236 int pos;
237 int c;
[e9a3c52]238 char *keys;
239 int level = 2;
240 char key_write[6][10];
[ebe70f1]241 int i;
242 int j;
243 int ch;
244
[e9a3c52]245 keys = "jkl pq";
[ebe70f1]246
[9996ed5]247 classic = 0;
248 showpreview = 1;
[237867d]249
[ebe70f1]250 while ((ch = getopt(argc, argv, "ck:ps")) != -1)
251 switch(ch) {
252 case 'c':
253 /*
254 * this means:
255 * - rotate the other way
256 * - no reverse video
257 */
258 classic = 1;
259 break;
260 case 'k':
261 if (str_size(keys = optarg) != 6)
262 usage();
263 break;
264 case 'p':
265 showpreview = 1;
266 break;
267 case 's':
268 showscores(0);
269 exit(0);
270 default:
271 usage();
272 }
273
274 argc -= optind;
275 argv += optind;
276
277 if (argc)
278 usage();
279
[e9a3c52]280 for (i = 0; i <= 5; i++) {
[ebe70f1]281 for (j = i + 1; j <= 5; j++) {
[e9a3c52]282 if (keys[i] == keys[j])
283 errx(1, "duplicate command keys specified.");
284 }
[ebe70f1]285
[e9a3c52]286 if (keys[i] == ' ')
[ebe70f1]287 str_cpy(key_write[i], sizeof(key_write[i]), "<space>");
[e9a3c52]288 else {
289 key_write[i][0] = keys[i];
290 key_write[i][1] = '\0';
291 }
292 }
[ebe70f1]293
294 snprintf(key_msg, sizeof(key_msg),
295 "%s - left %s - rotate %s - right %s - drop %s - pause %s - quit",
296 key_write[0], key_write[1], key_write[2], key_write[3],
297 key_write[4], key_write[5]);
298
[9996ed5]299 scr_init();
300 initscores();
301 while (tetris_menu(&level)) {
[237867d]302 fallrate = 1000000 / level;
303
[9996ed5]304 scr_clear();
305 setup_board();
[ebe70f1]306
[9996ed5]307 srandomdev();
308 scr_set();
[ebe70f1]309
310 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
[9996ed5]311 nextshape = randshape();
312 curshape = randshape();
[ebe70f1]313
[9996ed5]314 scr_msg(key_msg, 1);
[ebe70f1]315
316 while (1) {
[9996ed5]317 place(curshape, pos, 1);
318 scr_update();
319 place(curshape, pos, 0);
320 c = tgetchar();
321 if (c < 0) {
322 /*
323 * Timeout. Move down if possible.
324 */
325 if (fits_in(curshape, pos + B_COLS)) {
326 pos += B_COLS;
327 continue;
328 }
[ebe70f1]329
[9996ed5]330 /*
331 * Put up the current shape `permanently',
332 * bump score, and elide any full rows.
333 */
334 place(curshape, pos, 1);
335 score++;
336 elide();
[ebe70f1]337
[9996ed5]338 /*
339 * Choose a new shape. If it does not fit,
340 * the game is over.
341 */
342 curshape = nextshape;
343 nextshape = randshape();
[ebe70f1]344 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
345
[9996ed5]346 if (!fits_in(curshape, pos))
347 break;
[ebe70f1]348
[e9a3c52]349 continue;
350 }
[ebe70f1]351
[e9a3c52]352 /*
[9996ed5]353 * Handle command keys.
[e9a3c52]354 */
[9996ed5]355 if (c == keys[5]) {
356 /* quit */
[e9a3c52]357 break;
358 }
[ebe70f1]359
[9996ed5]360 if (c == keys[4]) {
361 static char msg[] =
362 "paused - press RETURN to continue";
[ebe70f1]363
[9996ed5]364 place(curshape, pos, 1);
365 do {
366 scr_update();
367 scr_msg(key_msg, 0);
368 scr_msg(msg, 1);
[d2cc7e1]369 (void) fflush(stdout);
[ebe70f1]370 } while (rwait((struct timeval *) NULL) == -1);
371
[9996ed5]372 scr_msg(msg, 0);
373 scr_msg(key_msg, 1);
374 place(curshape, pos, 0);
375 continue;
376 }
[ebe70f1]377
[9996ed5]378 if (c == keys[0]) {
379 /* move left */
380 if (fits_in(curshape, pos - 1))
381 pos--;
382 continue;
383 }
[ebe70f1]384
[9996ed5]385 if (c == keys[1]) {
386 /* turn */
[ebe70f1]387 const struct shape *new =
388 &shapes[classic ? curshape->rotc : curshape->rot];
389
[9996ed5]390 if (fits_in(new, pos))
391 curshape = new;
392 continue;
393 }
[ebe70f1]394
[9996ed5]395 if (c == keys[2]) {
396 /* move right */
397 if (fits_in(curshape, pos + 1))
398 pos++;
399 continue;
400 }
[ebe70f1]401
[9996ed5]402 if (c == keys[3]) {
403 /* move to bottom */
404 while (fits_in(curshape, pos + B_COLS)) {
405 pos += B_COLS;
406 score++;
407 }
408 continue;
409 }
[ebe70f1]410
[9996ed5]411 if (c == '\f') {
412 scr_clear();
413 scr_msg(key_msg, 1);
414 }
415 }
416
417 scr_clear();
418 insertscore(score, level);
[ebe70f1]419 score = 0;
[0aa024b1]420 }
421
422 scr_clear();
[ebe70f1]423 printf("\nGame over.\n");
[9996ed5]424 scr_end();
[ebe70f1]425
[501a8ba]426 return 0;
[e9a3c52]427}
428
[ebe70f1]429void usage(void)
[e9a3c52]430{
[ebe70f1]431 fprintf(stderr, "usage: tetris [-ps] [-k keys]\n");
[e9a3c52]432 exit(1);
433}
[b2951e2]434
435/** @}
436 */
Note: See TracBrowser for help on using the repository browser.