xref: /csrg-svn/games/tetris/tetris.c (revision 57276)
1 /*-
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)tetris.c	5.1 (Berkeley) 12/22/92
8  */
9 
10 #ifndef lint
11 char copyright[] =
12 "@(#) Copyright (c) 1992 The Regents of the University of California.\n\
13  All rights reserved.\n";
14 #endif /* not lint */
15 
16 /*
17  * Tetris (or however it is spelled).
18  */
19 
20 #include <sys/time.h>
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include "input.h"
28 #include "scores.h"
29 #include "screen.h"
30 #include "tetris.h"
31 
32 /*
33  * Set up the initial board.
34  * The bottom display row is completely set,
35  * along with another (hidden) row underneath that.
36  * Also, the left and right edges are set.
37  */
38 static void
39 setup_board()
40 {
41 	register int i;
42 	register cell *p;
43 
44 	p = board;
45 	for (i = B_SIZE; i; i--)
46 #ifndef mips
47 		*p++ = i <= (2 * B_COLS) || (i % B_COLS) < 2;
48 #else /* work around compiler bug */
49 		*p++ = i <= (2 * B_COLS) || (i % B_COLS) < 2 ? 1 : 0;
50 #endif
51 }
52 
53 /*
54  * Elide any full active rows.
55  */
56 static void
57 elide()
58 {
59 	register int i, j, base;
60 	register cell *p;
61 
62 	for (i = A_FIRST; i < A_LAST; i++) {
63 		base = i * B_COLS + 1;
64 		p = &board[base];
65 		for (j = B_COLS - 2; *p++ != 0;) {
66 			if (--j <= 0) {
67 				/* this row is to be elided */
68 				bzero(&board[base], B_COLS - 2);
69 				scr_update();
70 				tsleep();
71 				while (--base != 0)
72 					board[base + B_COLS] = board[base];
73 				scr_update();
74 				tsleep();
75 				break;
76 			}
77 		}
78 	}
79 }
80 
81 int
82 main(argc, argv)
83 	int argc;
84 	char **argv;
85 {
86 	register int pos, c;
87 	register struct shape *curshape;
88 	register char *keys;
89 	register int level = 2;
90 	char key_write[6][10];
91 	int i, j;
92 
93 	keys = "jkl pq";
94 
95 	if (argc > 3)
96 		goto usage;
97 
98 	while (argc-- >= 2)
99 		switch (argv[argc][0]) {
100 
101 		case '-':
102 			keys = argv[argc];
103 			keys++;
104 			if (strlen(keys) < 6) {
105 	usage:
106 				(void)fprintf(stderr,
107 				    "usage: %s [level] [-keys]\n",
108 				    argv[0]);
109 				exit(1);
110 			}
111 			break;
112 
113 		default:
114 			level = atoi(argv[argc]);
115 			if (level < MINLEVEL) {
116 				showscores(level);
117 				exit(0);
118 			}
119 			if (level > MAXLEVEL)
120 				level = MAXLEVEL;
121 		}
122 
123 	fallrate = 1000000 / level;
124 
125 	for (i = 0; i <= 5; i++) {
126 		for (j = i+1; j <= 5; j++) {
127 			if (keys[i] == keys[j]) {
128 				(void)fprintf(stderr,
129 				    "%s: Duplicate command keys specified.\n",
130 				    argv[0]);
131 				exit (1);
132 			}
133 		}
134 		if (keys[i] == ' ')
135 			strcpy(key_write[i], "<space>");
136 		else {
137 			key_write[i][0] = keys[i];
138 			key_write[i][1] = '\0';
139 		}
140 	}
141 
142 	sprintf(key_msg,
143 "%s - left   %s - rotate   %s - right   %s - drop   %s - pause   %s - quit",
144 		key_write[0], key_write[1], key_write[2], key_write[3],
145 		key_write[4], key_write[5]);
146 
147 	scr_init();
148 	setup_board();
149 
150 	srandom(getpid());
151 	scr_set();
152 
153 	pos = A_FIRST*B_COLS + (B_COLS/2)-1;
154 	curshape = randshape();
155 
156 	scr_msg(key_msg, 1);
157 
158 	for (;;) {
159 		place(curshape, pos, 1);
160 		scr_update();
161 		place(curshape, pos, 0);
162 		c = tgetchar();
163 		if (c < 0) {
164 			/*
165 			 * Timeout.  Move down if possible.
166 			 */
167 			if (fits_in(curshape, pos + B_COLS)) {
168 				pos += B_COLS;
169 				continue;
170 			}
171 
172 			/*
173 			 * Put up the current shape `permanently',
174 			 * bump score, and elide any full rows.
175 			 */
176 			place(curshape, pos, 1);
177 			score++;
178 			elide();
179 
180 			/*
181 			 * Choose a new shape.  If it does not fit,
182 			 * the game is over.
183 			 */
184 			curshape = randshape();
185 			pos = A_FIRST*B_COLS + (B_COLS/2)-1;
186 			if (!fits_in(curshape, pos))
187 				break;
188 			continue;
189 		}
190 
191 		/*
192 		 * Handle command keys.
193 		 */
194 		if (c == keys[5]) {
195 			/* quit */
196 			break;
197 		}
198 		if (c == keys[4]) {
199 			static char msg[] =
200 			    "paused - press RETURN to continue";
201 
202 			place(curshape, pos, 1);
203 			do {
204 				scr_update();
205 				scr_msg(key_msg, 0);
206 				scr_msg(msg, 1);
207 				(void) fflush(stdout);
208 			} while (rwait((struct timeval *)NULL) == -1);
209 			scr_msg(msg, 0);
210 			scr_msg(key_msg, 1);
211 			place(curshape, pos, 0);
212 			continue;
213 		}
214 		if (c == keys[0]) {
215 			/* move left */
216 			if (fits_in(curshape, pos - 1))
217 				pos--;
218 			continue;
219 		}
220 		if (c == keys[1]) {
221 			/* turn */
222 			struct shape *new = &shapes[curshape->rot];
223 
224 			if (fits_in(new, pos))
225 				curshape = new;
226 			continue;
227 		}
228 		if (c == keys[2]) {
229 			/* move right */
230 			if (fits_in(curshape, pos + 1))
231 				pos++;
232 			continue;
233 		}
234 		if (c == keys[3]) {
235 			/* move to bottom */
236 			while (fits_in(curshape, pos + B_COLS)) {
237 				pos += B_COLS;
238 				score++;
239 			}
240 			continue;
241 		}
242 		if (c == '\f')
243 			scr_clear();
244 	}
245 
246 	scr_clear();
247 	scr_end();
248 
249 	(void)printf("Your score:  %d point%s  x  level %d  =  %d\n",
250 	    score, score == 1 ? "" : "s", level, score * level);
251 	savescore(level);
252 
253 	printf("\nHit RETURN to see high scores, ^C to skip.\n");
254 
255 	while ((i = getchar()) != '\n')
256 		if (i == EOF)
257 			break;
258 
259 	showscores(level);
260 
261 	exit(0);
262 }
263