(linenum→info "unix/slp.c:2238")

bsd-games/2.17/tetris/tetris.c

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