]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - tetris/tetris.c
expand the internal consistency checks in truedirec() to avoid
[bsdgames-darwin.git] / tetris / tetris.c
1 /* $NetBSD: tetris.c,v 1.32 2016/03/03 21:38:55 nat Exp $ */
2
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.
18 * 3. Neither the name of the University nor the names of its contributors
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
37 #include <sys/cdefs.h>
38 #ifndef lint
39 __COPYRIGHT("@(#) Copyright (c) 1992, 1993\
40 The Regents of the University of California. All rights reserved.");
41 #endif /* not lint */
42
43 /*
44 * Tetris (or however it is spelled).
45 */
46
47 #include <sys/time.h>
48
49 #include <err.h>
50 #include <fcntl.h>
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
62 cell board[B_SIZE]; /* 1 => occupied, 0 => empty */
63
64 int Rows, Cols; /* current screen size */
65 int Offset; /* used to center board & shapes */
66
67 static const struct shape *curshape;
68 const struct shape *nextshape;
69
70 long fallrate; /* less than 1 million; smaller => faster */
71
72 int score; /* the obvious thing */
73 gid_t gid, egid;
74
75 char key_msg[100];
76 int showpreview;
77 int nocolor;
78
79 static void elide(void);
80 static void setup_board(void);
81 static void onintr(int) __dead;
82 static void usage(void) __dead;
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
90 setup_board(void)
91 {
92 int i;
93 cell *p;
94
95 p = board;
96 for (i = B_SIZE; i; i--)
97 *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 7 : 0;
98 }
99
100 /*
101 * Elide any full active rows.
102 */
103 static void
104 elide(void)
105 {
106 int i, j, base;
107 cell *p;
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 */
115 memset(&board[base], 0, B_COLS - 2);
116 scr_update();
117 tsleep();
118 while (--base != 0)
119 board[base + B_COLS] = board[base];
120 /* don't forget to clear 0th row */
121 memset(&board[1], 0, B_COLS - 2);
122 scr_update();
123 tsleep();
124 break;
125 }
126 }
127 }
128 }
129
130 int
131 main(int argc, char *argv[])
132 {
133 int pos, c;
134 const char *keys;
135 int level = 2;
136 #define NUMKEYS 7
137 char key_write[NUMKEYS][10];
138 int ch, i, j;
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);
149
150 keys = "jkl pqn";
151
152 while ((ch = getopt(argc, argv, "bk:l:ps")) != -1)
153 switch(ch) {
154 case 'b':
155 nocolor = 1;
156 break;
157 case 'k':
158 if (strlen(keys = optarg) != NUMKEYS)
159 usage();
160 break;
161 case 'l':
162 level = atoi(optarg);
163 if (level < MINLEVEL || level > MAXLEVEL) {
164 errx(1, "level must be from %d to %d",
165 MINLEVEL, MAXLEVEL);
166 }
167 break;
168 case 'p':
169 showpreview = 1;
170 break;
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
187 for (i = 0; i <= (NUMKEYS-1); i++) {
188 for (j = i+1; j <= (NUMKEYS-1); j++) {
189 if (keys[i] == keys[j]) {
190 errx(1, "duplicate command keys specified.");
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
201 snprintf(key_msg, sizeof(key_msg),
202 "%s - left %s - rotate %s - right %s - drop %s - pause %s - quit %s - down",
203 key_write[0], key_write[1], key_write[2], key_write[3],
204 key_write[4], key_write[5], key_write[6]);
205
206 (void)signal(SIGINT, onintr);
207 scr_init();
208 setup_board();
209
210 srandom(getpid());
211 scr_set();
212
213 pos = A_FIRST*B_COLS + (B_COLS/2)-1;
214 nextshape = randshape();
215 curshape = randshape();
216
217 scr_msg(key_msg, 1);
218
219 for (;;) {
220 place(curshape, pos, 1);
221 scr_update();
222 place(curshape, pos, 0);
223 c = tgetchar();
224 if (c < 0) {
225 /*
226 * Timeout. Move down if possible.
227 */
228 if (fits_in(curshape, pos + B_COLS)) {
229 pos += B_COLS;
230 continue;
231 }
232
233 /*
234 * Put up the current shape `permanently',
235 * bump score, and elide any full rows.
236 */
237 place(curshape, pos, 1);
238 score++;
239 elide();
240
241 /*
242 * Choose a new shape. If it does not fit,
243 * the game is over.
244 */
245 curshape = nextshape;
246 nextshape = randshape();
247 pos = A_FIRST*B_COLS + (B_COLS/2)-1;
248 if (!fits_in(curshape, pos))
249 break;
250 continue;
251 }
252
253 /*
254 * Handle command keys.
255 */
256 if (c == keys[5]) {
257 /* quit */
258 break;
259 }
260 if (c == keys[4]) {
261 static char msg[] =
262 "paused - press RETURN to continue";
263
264 place(curshape, pos, 1);
265 do {
266 scr_update();
267 scr_msg(key_msg, 0);
268 scr_msg(msg, 1);
269 (void) fflush(stdout);
270 } while (rwait(NULL) == -1);
271 scr_msg(msg, 0);
272 scr_msg(key_msg, 1);
273 place(curshape, pos, 0);
274 continue;
275 }
276 if (c == keys[0]) {
277 /* move left */
278 if (fits_in(curshape, pos - 1))
279 pos--;
280 continue;
281 }
282 if (c == keys[1]) {
283 /* turn */
284 const struct shape *new = &shapes[curshape->rot];
285
286 if (fits_in(new, pos))
287 curshape = new;
288 continue;
289 }
290 if (c == keys[2]) {
291 /* move right */
292 if (fits_in(curshape, pos + 1))
293 pos++;
294 continue;
295 }
296 if (c == keys[3]) {
297 /* move to bottom */
298 while (fits_in(curshape, pos + B_COLS)) {
299 pos += B_COLS;
300 score++;
301 }
302 continue;
303 }
304 if (c == keys[6]) {
305 /* move down */
306 if (fits_in(curshape, pos + B_COLS)) {
307 pos += B_COLS;
308 score++;
309 }
310 continue;
311 }
312 if (c == '\f') {
313 scr_clear();
314 scr_msg(key_msg, 1);
315 }
316 }
317
318 scr_clear();
319 scr_end();
320
321 (void)printf("Your score: %d point%s x level %d = %d\n",
322 score, score == 1 ? "" : "s", level, score * level);
323 savescore(level);
324
325 printf("\nHit RETURN to see high scores, ^C to skip.\n");
326
327 while ((i = getchar()) != '\n')
328 if (i == EOF)
329 break;
330
331 showscores(level);
332
333 exit(0);
334 }
335
336 static void
337 onintr(int signo __unused)
338 {
339 scr_clear();
340 scr_end();
341 exit(0);
342 }
343
344 static void
345 usage(void)
346 {
347 (void)fprintf(stderr, "usage: %s [-bps] [-k keys] [-l level]\n",
348 getprogname());
349 exit(1);
350 }