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
Line 
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
38/** @addtogroup tetris Tetris
39 * @brief Tetris ported from OpenBSD
40 * @{
41 */
42/** @file
43 */
44
45static const char copyright[] =
46 "@(#) Copyright (c) 1992, 1993\n"
47 "\tThe Regents of the University of California. All rights reserved.\n";
48
49#include <sys/time.h>
50#include <sys/types.h>
51#include <err.h>
52#include <errno.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57#include <getopt.h>
58
59#include "input.h"
60#include "scores.h"
61#include "screen.h"
62#include "tetris.h"
63
64cell board[B_SIZE];
65
66int Rows;
67int Cols;
68
69const struct shape *curshape;
70const struct shape *nextshape;
71
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;
85
86/*
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
89 * right edges are set.
90 */
91static void setup_board(void)
92{
93 int i;
94 cell *p = board;
95
96 for (i = B_SIZE; i; i--)
97 *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 0x0000ff : 0x000000;
98}
99
100/*
101 * Elide any full active rows.
102 */
103static void elide(void)
104{
105 int rows = 0;
106 int i;
107 int j;
108 int base;
109 cell *p;
110
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) {
116 /* This row is to be elided */
117 rows++;
118 memset(&board[base], 0, sizeof(cell) * (B_COLS - 2));
119
120 scr_update();
121 tsleep();
122
123 while (--base != 0)
124 board[base + B_COLS] = board[base];
125
126 scr_update();
127 tsleep();
128
129 break;
130 }
131 }
132 }
133
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
152const struct shape *randshape(void)
153{
154 const struct shape *tmp = &shapes[random() % 7];
155 int i;
156 int j = random() % 4;
157
158 for (i = 0; i < j; i++)
159 tmp = &shapes[classic ? tmp->rotc : tmp->rot];
160
161 return (tmp);
162}
163
164static void srandomdev(void)
165{
166 struct timeval tv;
167
168 gettimeofday(&tv, NULL);
169 srandom(tv.tv_sec + tv.tv_usec / 100000);
170}
171
172static void tetris_menu_draw(int level)
173{
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);
192}
193
194static int tetris_menu(int *level)
195{
196 tetris_menu_draw(*level);
197 while (1) {
198 int i = getchar();
199
200 switch(i) {
201 case 'p':
202 showpreview = !showpreview;
203 moveto(9, 21);
204 if (showpreview)
205 printf("on ");
206 else
207 printf("off");
208 break;
209 case 'h':
210 loadscores();
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':
224 case '6':
225 case '7':
226 case '8':
227 case '9':
228 *level = i - '0';
229 moveto(8, 18);
230 printf("%d", *level);
231 break;
232 }
233 }
234}
235
236int main(int argc, char *argv[])
237{
238 int pos;
239 int c;
240 const char *keys;
241 int level = 2;
242 char key_write[6][10];
243 int i;
244 int j;
245 int ch;
246
247 keys = "jkl pq";
248
249 classic = 0;
250 showpreview = 1;
251
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
282 for (i = 0; i <= 5; i++) {
283 for (j = i + 1; j <= 5; j++) {
284 if (keys[i] == keys[j])
285 errx(1, "duplicate command keys specified.");
286 }
287
288 if (keys[i] == ' ')
289 str_cpy(key_write[i], sizeof(key_write[i]), "<space>");
290 else {
291 key_write[i][0] = keys[i];
292 key_write[i][1] = '\0';
293 }
294 }
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
301 scr_init();
302 if (loadscores() != EOK)
303 initscores();
304
305 while (tetris_menu(&level)) {
306 fallrate = 1000000 / level;
307
308 scr_clear();
309 setup_board();
310
311 srandomdev();
312 scr_set();
313
314 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
315 nextshape = randshape();
316 curshape = randshape();
317
318 scr_msg(key_msg, 1);
319
320 while (1) {
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 }
333
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();
341
342 /*
343 * Choose a new shape. If it does not fit,
344 * the game is over.
345 */
346 curshape = nextshape;
347 nextshape = randshape();
348 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
349
350 if (!fits_in(curshape, pos))
351 break;
352
353 continue;
354 }
355
356 /*
357 * Handle command keys.
358 */
359 if (c == keys[5]) {
360 /* quit */
361 break;
362 }
363
364 if (c == keys[4]) {
365 static char msg[] =
366 "paused - press RETURN to continue";
367
368 place(curshape, pos, 1);
369 do {
370 scr_update();
371 scr_msg(key_msg, 0);
372 scr_msg(msg, 1);
373 (void) fflush(stdout);
374 } while (rwait((struct timeval *) NULL) == -1);
375
376 scr_msg(msg, 0);
377 scr_msg(key_msg, 1);
378 place(curshape, pos, 0);
379 continue;
380 }
381
382 if (c == keys[0]) {
383 /* move left */
384 if (fits_in(curshape, pos - 1))
385 pos--;
386 continue;
387 }
388
389 if (c == keys[1]) {
390 /* turn */
391 const struct shape *new =
392 &shapes[classic ? curshape->rotc : curshape->rot];
393
394 if (fits_in(new, pos))
395 curshape = new;
396 continue;
397 }
398
399 if (c == keys[2]) {
400 /* move right */
401 if (fits_in(curshape, pos + 1))
402 pos++;
403 continue;
404 }
405
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 }
414
415 if (c == '\f') {
416 scr_clear();
417 scr_msg(key_msg, 1);
418 }
419 }
420
421 scr_clear();
422 loadscores();
423 insertscore(score, level);
424 savescores();
425 score = 0;
426 }
427
428 scr_clear();
429 printf("\nGame over.\n");
430 scr_end();
431
432 return 0;
433}
434
435void usage(void)
436{
437 fprintf(stderr, "usage: tetris [-ps] [-k keys]\n");
438 exit(1);
439}
440
441/** @}
442 */
Note: See TracBrowser for help on using the repository browser.