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