Subversion Repositories HelenOS-historic

Rev

Rev 1449 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*  $OpenBSD: tetris.c,v 1.21 2006/04/20 03:24:12 ray 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. #ifndef lint
  39. static const char copyright[] =
  40. "@(#) Copyright (c) 1992, 1993\n\
  41.     The Regents of the University of California.  All rights reserved.\n";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * Tetris (or however it is spelled).
  46.  */
  47.  
  48. #include <sys/param.h>
  49. #include <sys/time.h>
  50. #include <sys/types.h>
  51.  
  52. #include <err.h>
  53. #include <signal.h>
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. #include <string.h>
  57. #include <unistd.h>
  58.  
  59. #include "input.h"
  60. #include "scores.h"
  61. #include "screen.h"
  62. #include "tetris.h"
  63.  
  64. cell    board[B_SIZE];
  65. int Rows, Cols;
  66. const struct shape *curshape;
  67. const struct shape *nextshape;
  68. long    fallrate;
  69. int score;
  70. gid_t   gid, egid;
  71. char    key_msg[100];
  72. int showpreview, classic;
  73.  
  74. static void elide(void);
  75. static void setup_board(void);
  76. const struct shape *randshape(void);
  77. void    onintr(int);
  78. void    usage(void);
  79.  
  80. /*
  81.  * Set up the initial board.  The bottom display row is completely set,
  82.  * along with another (hidden) row underneath that.  Also, the left and
  83.  * right edges are set.
  84.  */
  85. static void
  86. setup_board(void)
  87. {
  88.     int i;
  89.     cell *p;
  90.  
  91.     p = board;
  92.     for (i = B_SIZE; i; i--)
  93.         *p++ = i <= (2 * B_COLS) || (i % B_COLS) < 2;
  94. }
  95.  
  96. /*
  97.  * Elide any full active rows.
  98.  */
  99. static void
  100. elide(void)
  101. {
  102.     int rows = 0;
  103.     int i, j, base;
  104.     cell *p;
  105.  
  106.     for (i = A_FIRST; i < A_LAST; i++) {
  107.         base = i * B_COLS + 1;
  108.         p = &board[base];
  109.         for (j = B_COLS - 2; *p++ != 0;) {
  110.             if (--j <= 0) {
  111.                 /* this row is to be elided */
  112.                 rows++;
  113.                 memset(&board[base], 0, B_COLS - 2);
  114.                 scr_update();
  115.                 tsleep();
  116.                 while (--base != 0)
  117.                     board[base + B_COLS] = board[base];
  118.                 scr_update();
  119.                 tsleep();
  120.                 break;
  121.             }
  122.         }
  123.     }
  124.     switch (rows) {
  125.     case 1:
  126.         score += 10;
  127.         break;
  128.     case 2:
  129.         score += 30;
  130.         break;
  131.     case 3:
  132.         score += 70;
  133.         break;
  134.     case 4:
  135.         score += 150;
  136.         break;
  137.     default:
  138.         break;
  139.     }
  140. }
  141.  
  142. const struct shape *
  143. randshape(void)
  144. {
  145.     const struct shape *tmp;
  146.     int i, j;
  147.  
  148.     tmp = &shapes[random() % 7];
  149.     j = random() % 4;
  150.     for (i = 0; i < j; i++)
  151.         tmp = &shapes[classic? tmp->rotc : tmp->rot];
  152.     return (tmp);
  153. }
  154.    
  155.  
  156. int
  157. main(int argc, char *argv[])
  158. {
  159.     int pos, c;
  160.     char *keys;
  161.     int level = 2;
  162.     char key_write[6][10];
  163.     const char *errstr;
  164.     int ch, i, j;
  165.  
  166.     keys = "jkl pq";
  167.  
  168.     gid = getgid();
  169.     egid = getegid();
  170.     setegid(gid);
  171.  
  172.     classic = showpreview = 0;
  173.     while ((ch = getopt(argc, argv, "ck:l:ps")) != -1)
  174.         switch(ch) {
  175.         case 'c':
  176.             /*
  177.              * this means:
  178.              *  - rotate the other way;
  179.              *  - no reverse video.
  180.              */
  181.             classic = 1;
  182.             break;
  183.         case 'k':
  184.             if (strlen(keys = optarg) != 6)
  185.                 usage();
  186.             break;
  187.         case 'l':
  188.             level = (int)strtonum(optarg, MINLEVEL, MAXLEVEL,
  189.                 &errstr);
  190.             if (errstr)
  191.                 errx(1, "level must be from %d to %d",
  192.                     MINLEVEL, MAXLEVEL);
  193.             break;
  194.         case 'p':
  195.             showpreview = 1;
  196.             break;
  197.         case 's':
  198.             showscores(0);
  199.             exit(0);
  200.         default:
  201.             usage();
  202.         }
  203.  
  204.     argc -= optind;
  205.     argv += optind;
  206.  
  207.     if (argc)
  208.         usage();
  209.  
  210.     fallrate = 1000000 / level;
  211.  
  212.     for (i = 0; i <= 5; i++) {
  213.         for (j = i+1; j <= 5; j++) {
  214.             if (keys[i] == keys[j])
  215.                 errx(1, "duplicate command keys specified.");
  216.         }
  217.         if (keys[i] == ' ')
  218.             strlcpy(key_write[i], "<space>", sizeof key_write[i]);
  219.         else {
  220.             key_write[i][0] = keys[i];
  221.             key_write[i][1] = '\0';
  222.         }
  223.     }
  224.  
  225.     snprintf(key_msg, sizeof key_msg,
  226. "%s - left   %s - rotate   %s - right   %s - drop   %s - pause   %s - quit",
  227.         key_write[0], key_write[1], key_write[2], key_write[3],
  228.         key_write[4], key_write[5]);
  229.  
  230.     (void)signal(SIGINT, onintr);
  231.     scr_init();
  232.     setup_board();
  233.  
  234.     srandomdev();
  235.     scr_set();
  236.  
  237.     pos = A_FIRST*B_COLS + (B_COLS/2)-1;
  238.     nextshape = randshape();
  239.     curshape = randshape();
  240.  
  241.     scr_msg(key_msg, 1);
  242.  
  243.     for (;;) {
  244.         place(curshape, pos, 1);
  245.         scr_update();
  246.         place(curshape, pos, 0);
  247.         c = tgetchar();
  248.         if (c < 0) {
  249.             /*
  250.              * Timeout.  Move down if possible.
  251.              */
  252.             if (fits_in(curshape, pos + B_COLS)) {
  253.                 pos += B_COLS;
  254.                 continue;
  255.             }
  256.  
  257.             /*
  258.              * Put up the current shape `permanently',
  259.              * bump score, and elide any full rows.
  260.              */
  261.             place(curshape, pos, 1);
  262.             score++;
  263.             elide();
  264.  
  265.             /*
  266.              * Choose a new shape.  If it does not fit,
  267.              * the game is over.
  268.              */
  269.             curshape = nextshape;
  270.             nextshape = randshape();
  271.             pos = A_FIRST*B_COLS + (B_COLS/2)-1;
  272.             if (!fits_in(curshape, pos))
  273.                 break;
  274.             continue;
  275.         }
  276.  
  277.         /*
  278.          * Handle command keys.
  279.          */
  280.         if (c == keys[5]) {
  281.             /* quit */
  282.             break;
  283.         }
  284.         if (c == keys[4]) {
  285.             static char msg[] =
  286.                 "paused - press RETURN to continue";
  287.  
  288.             place(curshape, pos, 1);
  289.             do {
  290.                 scr_update();
  291.                 scr_msg(key_msg, 0);
  292.                 scr_msg(msg, 1);
  293.                 (void) fflush(stdout);
  294.             } while (rwait((struct timeval *)NULL) == -1);
  295.             scr_msg(msg, 0);
  296.             scr_msg(key_msg, 1);
  297.             place(curshape, pos, 0);
  298.             continue;
  299.         }
  300.         if (c == keys[0]) {
  301.             /* move left */
  302.             if (fits_in(curshape, pos - 1))
  303.                 pos--;
  304.             continue;
  305.         }
  306.         if (c == keys[1]) {
  307.             /* turn */
  308.             const struct shape *new = &shapes[
  309.                 classic? curshape->rotc : curshape->rot];
  310.  
  311.             if (fits_in(new, pos))
  312.                 curshape = new;
  313.             continue;
  314.         }
  315.         if (c == keys[2]) {
  316.             /* move right */
  317.             if (fits_in(curshape, pos + 1))
  318.                 pos++;
  319.             continue;
  320.         }
  321.         if (c == keys[3]) {
  322.             /* move to bottom */
  323.             while (fits_in(curshape, pos + B_COLS)) {
  324.                 pos += B_COLS;
  325.                 score++;
  326.             }
  327.             continue;
  328.         }
  329.         if (c == '\f') {
  330.             scr_clear();
  331.             scr_msg(key_msg, 1);
  332.         }
  333.     }
  334.  
  335.     scr_clear();
  336.     scr_end();
  337.  
  338.     if (showpreview == 0)
  339.         (void)printf("Your score:  %d point%s  x  level %d  =  %d\n",
  340.             score, score == 1 ? "" : "s", level, score * level);
  341.     else {
  342.         (void)printf("Your score:  %d point%s x level %d x preview penalty %0.3f = %d\n",
  343.             score, score == 1 ? "" : "s", level, (double)PRE_PENALTY,
  344.             (int)(score * level * PRE_PENALTY));
  345.         score = score * PRE_PENALTY;
  346.     }
  347.     savescore(level);
  348.  
  349.     printf("\nHit RETURN to see high scores, ^C to skip.\n");
  350.  
  351.     while ((i = getchar()) != '\n')
  352.         if (i == EOF)
  353.             break;
  354.  
  355.     showscores(level);
  356.  
  357.     exit(0);
  358. }
  359.  
  360. void
  361. onintr(int signo)
  362. {
  363.     scr_clear();        /* XXX signal race */
  364.     scr_end();      /* XXX signal race */
  365.     _exit(0);
  366. }
  367.  
  368. void
  369. usage(void)
  370. {
  371.     (void)fprintf(stderr, "usage: tetris [-ps] [-k keys] [-l level]\n");
  372.     exit(1);
  373. }
  374.