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