]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - tetris/tetris.c
Newline and usage cosmetics from Soren S. Jorvang <soren@t.dk> PR7205
[bsdgames-darwin.git] / tetris / tetris.c
1 /* $NetBSD: tetris.c,v 1.9 1999/03/22 06:12:23 abs 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. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)tetris.c 8.1 (Berkeley) 5/31/93
39 */
40
41 #include <sys/cdefs.h>
42 #ifndef lint
43 __COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\
44 The Regents of the University of California. All rights reserved.\n");
45 #endif /* not lint */
46
47 /*
48 * Tetris (or however it is spelled).
49 */
50
51 #include <sys/time.h>
52
53 #include <signal.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58
59 #include "input.h"
60 #include "scores.h"
61 #include "screen.h"
62 #include "tetris.h"
63
64 static void elide __P((void));
65 static void setup_board __P((void));
66 int main __P((int, char **));
67 void onintr __P((int)) __attribute__((__noreturn__));
68 void usage __P((void)) __attribute__((__noreturn__));
69
70 /*
71 * Set up the initial board. The bottom display row is completely set,
72 * along with another (hidden) row underneath that. Also, the left and
73 * right edges are set.
74 */
75 static void
76 setup_board()
77 {
78 register int i;
79 register cell *p;
80
81 p = board;
82 for (i = B_SIZE; i; i--)
83 *p++ = i <= (2 * B_COLS) || (i % B_COLS) < 2;
84 }
85
86 /*
87 * Elide any full active rows.
88 */
89 static void
90 elide()
91 {
92 register int i, j, base;
93 register cell *p;
94
95 for (i = A_FIRST; i < A_LAST; i++) {
96 base = i * B_COLS + 1;
97 p = &board[base];
98 for (j = B_COLS - 2; *p++ != 0;) {
99 if (--j <= 0) {
100 /* this row is to be elided */
101 memset(&board[base], 0, B_COLS - 2);
102 scr_update();
103 tsleep();
104 while (--base != 0)
105 board[base + B_COLS] = board[base];
106 scr_update();
107 tsleep();
108 break;
109 }
110 }
111 }
112 }
113
114 int
115 main(argc, argv)
116 int argc;
117 char *argv[];
118 {
119 register int pos, c;
120 register char *keys;
121 register int level = 2;
122 char key_write[6][10];
123 int ch, i, j;
124
125 keys = "jkl pq";
126
127 while ((ch = getopt(argc, argv, "k:l:ps")) != -1)
128 switch(ch) {
129 case 'k':
130 if (strlen(keys = optarg) != 6)
131 usage();
132 break;
133 case 'l':
134 level = atoi(optarg);
135 if (level < MINLEVEL || level > MAXLEVEL) {
136 (void)fprintf(stderr,
137 "tetris: level must be from %d to %d\n",
138 MINLEVEL, MAXLEVEL);
139 exit(1);
140 }
141 break;
142 case 'p':
143 showpreview = 1;
144 break;
145 case 's':
146 showscores(0);
147 exit(0);
148 case '?':
149 default:
150 usage();
151 }
152
153 argc -= optind;
154 argv += optind;
155
156 if (argc)
157 usage();
158
159 fallrate = 1000000 / level;
160
161 for (i = 0; i <= 5; i++) {
162 for (j = i+1; j <= 5; j++) {
163 if (keys[i] == keys[j]) {
164 (void)fprintf(stderr,
165 "%s: duplicate command keys specified.\n",
166 argv[0]);
167 exit (1);
168 }
169 }
170 if (keys[i] == ' ')
171 strcpy(key_write[i], "<space>");
172 else {
173 key_write[i][0] = keys[i];
174 key_write[i][1] = '\0';
175 }
176 }
177
178 sprintf(key_msg,
179 "%s - left %s - rotate %s - right %s - drop %s - pause %s - quit",
180 key_write[0], key_write[1], key_write[2], key_write[3],
181 key_write[4], key_write[5]);
182
183 (void)signal(SIGINT, onintr);
184 scr_init();
185 setup_board();
186
187 srandom(getpid());
188 scr_set();
189
190 pos = A_FIRST*B_COLS + (B_COLS/2)-1;
191 nextshape = randshape();
192 curshape = randshape();
193
194 scr_msg(key_msg, 1);
195
196 for (;;) {
197 place(curshape, pos, 1);
198 scr_update();
199 place(curshape, pos, 0);
200 c = tgetchar();
201 if (c < 0) {
202 /*
203 * Timeout. Move down if possible.
204 */
205 if (fits_in(curshape, pos + B_COLS)) {
206 pos += B_COLS;
207 continue;
208 }
209
210 /*
211 * Put up the current shape `permanently',
212 * bump score, and elide any full rows.
213 */
214 place(curshape, pos, 1);
215 score++;
216 elide();
217
218 /*
219 * Choose a new shape. If it does not fit,
220 * the game is over.
221 */
222 curshape = nextshape;
223 nextshape = randshape();
224 pos = A_FIRST*B_COLS + (B_COLS/2)-1;
225 if (!fits_in(curshape, pos))
226 break;
227 continue;
228 }
229
230 /*
231 * Handle command keys.
232 */
233 if (c == keys[5]) {
234 /* quit */
235 break;
236 }
237 if (c == keys[4]) {
238 static char msg[] =
239 "paused - press RETURN to continue";
240
241 place(curshape, pos, 1);
242 do {
243 scr_update();
244 scr_msg(key_msg, 0);
245 scr_msg(msg, 1);
246 (void) fflush(stdout);
247 } while (rwait((struct timeval *)NULL) == -1);
248 scr_msg(msg, 0);
249 scr_msg(key_msg, 1);
250 place(curshape, pos, 0);
251 continue;
252 }
253 if (c == keys[0]) {
254 /* move left */
255 if (fits_in(curshape, pos - 1))
256 pos--;
257 continue;
258 }
259 if (c == keys[1]) {
260 /* turn */
261 struct shape *new = &shapes[curshape->rot];
262
263 if (fits_in(new, pos))
264 curshape = new;
265 continue;
266 }
267 if (c == keys[2]) {
268 /* move right */
269 if (fits_in(curshape, pos + 1))
270 pos++;
271 continue;
272 }
273 if (c == keys[3]) {
274 /* move to bottom */
275 while (fits_in(curshape, pos + B_COLS)) {
276 pos += B_COLS;
277 score++;
278 }
279 continue;
280 }
281 if (c == '\f') {
282 scr_clear();
283 scr_msg(key_msg, 1);
284 }
285 }
286
287 scr_clear();
288 scr_end();
289
290 (void)printf("Your score: %d point%s x level %d = %d\n",
291 score, score == 1 ? "" : "s", level, score * level);
292 savescore(level);
293
294 printf("\nHit RETURN to see high scores, ^C to skip.\n");
295
296 while ((i = getchar()) != '\n')
297 if (i == EOF)
298 break;
299
300 showscores(level);
301
302 exit(0);
303 }
304
305 void
306 onintr(signo)
307 int signo;
308 {
309 scr_clear();
310 scr_end();
311 exit(0);
312 }
313
314 void
315 usage()
316 {
317 (void)fprintf(stderr, "usage: tetris [-ps] [-k keys] [-l level]\n");
318 exit(1);
319 }