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