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