Annotation of src/games/tetris/tetris.c, Revision 1.33
1.33 ! nia 1: /* $NetBSD: tetris.c,v 1.32 2016/03/03 21:38:55 nat Exp $ */
1.2 cgd 2:
1.1 cgd 3: /*-
4: * Copyright (c) 1992, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * This code is derived from software contributed to Berkeley by
8: * Chris Torek and Darren F. Provine.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
1.16 agc 18: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: *
34: * @(#)tetris.c 8.1 (Berkeley) 5/31/93
35: */
36:
1.3 lukem 37: #include <sys/cdefs.h>
1.1 cgd 38: #ifndef lint
1.19 lukem 39: __COPYRIGHT("@(#) Copyright (c) 1992, 1993\
40: The Regents of the University of California. All rights reserved.");
1.1 cgd 41: #endif /* not lint */
42:
43: /*
44: * Tetris (or however it is spelled).
45: */
46:
47: #include <sys/time.h>
48:
1.14 jsm 49: #include <err.h>
1.12 jsm 50: #include <fcntl.h>
1.1 cgd 51: #include <signal.h>
52: #include <stdio.h>
53: #include <stdlib.h>
54: #include <string.h>
55: #include <unistd.h>
56:
57: #include "input.h"
58: #include "scores.h"
59: #include "screen.h"
60: #include "tetris.h"
61:
1.13 jsm 62: cell board[B_SIZE]; /* 1 => occupied, 0 => empty */
63:
64: int Rows, Cols; /* current screen size */
1.32 nat 65: int Offset; /* used to center board & shapes */
1.13 jsm 66:
1.22 dholland 67: static const struct shape *curshape;
1.13 jsm 68: const struct shape *nextshape;
69:
70: long fallrate; /* less than 1 million; smaller => faster */
71:
72: int score; /* the obvious thing */
1.12 jsm 73: gid_t gid, egid;
1.13 jsm 74:
75: char key_msg[100];
76: int showpreview;
1.26 pgoyette 77: int nocolor;
1.12 jsm 78:
1.22 dholland 79: static void elide(void);
80: static void setup_board(void);
81: static void onintr(int) __dead;
82: static void usage(void) __dead;
1.1 cgd 83:
84: /*
85: * Set up the initial board. The bottom display row is completely set,
86: * along with another (hidden) row underneath that. Also, the left and
87: * right edges are set.
88: */
89: static void
1.21 dholland 90: setup_board(void)
1.1 cgd 91: {
1.15 wiz 92: int i;
93: cell *p;
1.1 cgd 94:
95: p = board;
96: for (i = B_SIZE; i; i--)
1.25 christos 97: *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 7 : 0;
1.1 cgd 98: }
99:
100: /*
101: * Elide any full active rows.
102: */
103: static void
1.21 dholland 104: elide(void)
1.1 cgd 105: {
1.15 wiz 106: int i, j, base;
107: cell *p;
1.1 cgd 108:
109: for (i = A_FIRST; i < A_LAST; i++) {
110: base = i * B_COLS + 1;
111: p = &board[base];
112: for (j = B_COLS - 2; *p++ != 0;) {
113: if (--j <= 0) {
114: /* this row is to be elided */
1.4 perry 115: memset(&board[base], 0, B_COLS - 2);
1.1 cgd 116: scr_update();
117: tsleep();
118: while (--base != 0)
119: board[base + B_COLS] = board[base];
1.31 christos 120: /* don't forget to clear 0th row */
121: memset(&board[1], 0, B_COLS - 2);
1.1 cgd 122: scr_update();
123: tsleep();
124: break;
125: }
126: }
127: }
128: }
129:
130: int
1.21 dholland 131: main(int argc, char *argv[])
1.1 cgd 132: {
1.15 wiz 133: int pos, c;
134: const char *keys;
135: int level = 2;
1.28 mrg 136: #define NUMKEYS 7
137: char key_write[NUMKEYS][10];
1.1 cgd 138: int ch, i, j;
1.12 jsm 139: int fd;
140:
141: gid = getgid();
142: egid = getegid();
143: setegid(gid);
144:
145: fd = open("/dev/null", O_RDONLY);
146: if (fd < 3)
147: exit(1);
148: close(fd);
1.1 cgd 149:
1.28 mrg 150: keys = "jkl pqn";
1.1 cgd 151:
1.27 pgoyette 152: while ((ch = getopt(argc, argv, "bk:l:ps")) != -1)
1.1 cgd 153: switch(ch) {
1.27 pgoyette 154: case 'b':
1.26 pgoyette 155: nocolor = 1;
156: break;
1.1 cgd 157: case 'k':
1.28 mrg 158: if (strlen(keys = optarg) != NUMKEYS)
1.1 cgd 159: usage();
160: break;
161: case 'l':
162: level = atoi(optarg);
163: if (level < MINLEVEL || level > MAXLEVEL) {
1.14 jsm 164: errx(1, "level must be from %d to %d",
165: MINLEVEL, MAXLEVEL);
1.1 cgd 166: }
167: break;
1.7 hubertf 168: case 'p':
169: showpreview = 1;
170: break;
1.1 cgd 171: case 's':
172: showscores(0);
173: exit(0);
174: case '?':
175: default:
176: usage();
177: }
178:
179: argc -= optind;
180: argv += optind;
181:
182: if (argc)
183: usage();
184:
185: fallrate = 1000000 / level;
186:
1.28 mrg 187: for (i = 0; i <= (NUMKEYS-1); i++) {
188: for (j = i+1; j <= (NUMKEYS-1); j++) {
1.1 cgd 189: if (keys[i] == keys[j]) {
1.14 jsm 190: errx(1, "duplicate command keys specified.");
1.1 cgd 191: }
192: }
193: if (keys[i] == ' ')
194: strcpy(key_write[i], "<space>");
195: else {
196: key_write[i][0] = keys[i];
197: key_write[i][1] = '\0';
198: }
199: }
200:
1.20 dholland 201: snprintf(key_msg, sizeof(key_msg),
1.29 dholland 202: "%s - left %s - rotate %s - right %s - drop %s - pause %s - quit %s - down",
1.1 cgd 203: key_write[0], key_write[1], key_write[2], key_write[3],
1.28 mrg 204: key_write[4], key_write[5], key_write[6]);
1.1 cgd 205:
206: (void)signal(SIGINT, onintr);
207: scr_init();
208: setup_board();
209:
210: scr_set();
211:
212: pos = A_FIRST*B_COLS + (B_COLS/2)-1;
1.6 hubertf 213: nextshape = randshape();
1.1 cgd 214: curshape = randshape();
215:
216: scr_msg(key_msg, 1);
217:
218: for (;;) {
219: place(curshape, pos, 1);
220: scr_update();
221: place(curshape, pos, 0);
222: c = tgetchar();
223: if (c < 0) {
224: /*
225: * Timeout. Move down if possible.
226: */
227: if (fits_in(curshape, pos + B_COLS)) {
228: pos += B_COLS;
229: continue;
230: }
231:
232: /*
233: * Put up the current shape `permanently',
234: * bump score, and elide any full rows.
235: */
236: place(curshape, pos, 1);
237: score++;
238: elide();
239:
240: /*
241: * Choose a new shape. If it does not fit,
242: * the game is over.
243: */
1.6 hubertf 244: curshape = nextshape;
245: nextshape = randshape();
1.1 cgd 246: pos = A_FIRST*B_COLS + (B_COLS/2)-1;
247: if (!fits_in(curshape, pos))
248: break;
249: continue;
250: }
251:
252: /*
253: * Handle command keys.
254: */
255: if (c == keys[5]) {
256: /* quit */
257: break;
258: }
259: if (c == keys[4]) {
260: static char msg[] =
261: "paused - press RETURN to continue";
262:
263: place(curshape, pos, 1);
264: do {
265: scr_update();
266: scr_msg(key_msg, 0);
267: scr_msg(msg, 1);
268: (void) fflush(stdout);
1.24 plunky 269: } while (rwait(NULL) == -1);
1.1 cgd 270: scr_msg(msg, 0);
271: scr_msg(key_msg, 1);
272: place(curshape, pos, 0);
273: continue;
274: }
275: if (c == keys[0]) {
276: /* move left */
277: if (fits_in(curshape, pos - 1))
278: pos--;
279: continue;
280: }
281: if (c == keys[1]) {
282: /* turn */
1.10 jsm 283: const struct shape *new = &shapes[curshape->rot];
1.1 cgd 284:
285: if (fits_in(new, pos))
286: curshape = new;
287: continue;
288: }
289: if (c == keys[2]) {
290: /* move right */
291: if (fits_in(curshape, pos + 1))
292: pos++;
293: continue;
294: }
295: if (c == keys[3]) {
296: /* move to bottom */
297: while (fits_in(curshape, pos + B_COLS)) {
298: pos += B_COLS;
299: score++;
300: }
301: continue;
302: }
1.28 mrg 303: if (c == keys[6]) {
304: /* move down */
305: if (fits_in(curshape, pos + B_COLS)) {
306: pos += B_COLS;
307: score++;
308: }
309: continue;
310: }
1.6 hubertf 311: if (c == '\f') {
1.1 cgd 312: scr_clear();
1.6 hubertf 313: scr_msg(key_msg, 1);
314: }
1.1 cgd 315: }
316:
317: scr_clear();
318: scr_end();
319:
320: (void)printf("Your score: %d point%s x level %d = %d\n",
321: score, score == 1 ? "" : "s", level, score * level);
322: savescore(level);
323:
324: printf("\nHit RETURN to see high scores, ^C to skip.\n");
325:
326: while ((i = getchar()) != '\n')
327: if (i == EOF)
328: break;
329:
330: showscores(level);
331:
332: exit(0);
333: }
334:
1.22 dholland 335: static void
1.21 dholland 336: onintr(int signo __unused)
1.1 cgd 337: {
338: scr_clear();
339: scr_end();
340: exit(0);
341: }
342:
1.22 dholland 343: static void
1.21 dholland 344: usage(void)
1.1 cgd 345: {
1.30 dholland 346: (void)fprintf(stderr, "usage: %s [-bps] [-k keys] [-l level]\n",
1.23 pgoyette 347: getprogname());
1.1 cgd 348: exit(1);
349: }
CVSweb <webmaster@jp.NetBSD.org>