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