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 } 313