Subversion Repositories HelenOS

Rev

Rev 4668 | 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. /** @addtogroup tetris Tetris
  39.  * @brief Tetris ported from OpenBSD
  40.  * @{
  41.  */
  42. /** @file
  43.  */
  44.  
  45. static const char copyright[] =
  46.     "@(#) Copyright (c) 1992, 1993\n"
  47.     "\tThe Regents of the University of California.  All rights reserved.\n";
  48.  
  49. #include <sys/time.h>
  50. #include <sys/types.h>
  51. #include <err.h>
  52. #include <errno.h>
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55. #include <string.h>
  56. #include <unistd.h>
  57. #include <getopt.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.  
  66. int Rows;
  67. int Cols;
  68.  
  69. const struct shape *curshape;
  70. const struct shape *nextshape;
  71.  
  72. long fallrate;
  73. int score;
  74. char key_msg[100];
  75. int showpreview;
  76. int classic;
  77.  
  78. static void elide(void);
  79. static void setup_board(void);
  80. static const struct shape *randshape(void);
  81.  
  82. static void usage(void);
  83.  
  84. static int firstgame = 1;
  85.  
  86. /*
  87.  * Set up the initial board. The bottom display row is completely set,
  88.  * along with another (hidden) row underneath that. Also, the left and
  89.  * right edges are set.
  90.  */
  91. static void setup_board(void)
  92. {
  93.     int i;
  94.     cell *p = board;
  95.    
  96.     for (i = B_SIZE; i; i--)
  97.         *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 0x0000ff : 0x000000;
  98. }
  99.  
  100. /*
  101.  * Elide any full active rows.
  102.  */
  103. static void elide(void)
  104. {
  105.     int rows = 0;
  106.     int i;
  107.     int j;
  108.     int base;
  109.     cell *p;
  110.    
  111.     for (i = A_FIRST; i < A_LAST; i++) {
  112.         base = i * B_COLS + 1;
  113.         p = &board[base];
  114.         for (j = B_COLS - 2; *p++ != 0;) {
  115.             if (--j <= 0) {
  116.                 /* This row is to be elided */
  117.                 rows++;
  118.                 memset(&board[base], 0, sizeof(cell) * (B_COLS - 2));
  119.                
  120.                 scr_update();
  121.                 tsleep();
  122.                
  123.                 while (--base != 0)
  124.                     board[base + B_COLS] = board[base];
  125.                
  126.                 scr_update();
  127.                 tsleep();
  128.                
  129.                 break;
  130.             }
  131.         }
  132.     }
  133.    
  134.     switch (rows) {
  135.     case 1:
  136.         score += 10;
  137.         break;
  138.     case 2:
  139.         score += 30;
  140.         break;
  141.     case 3:
  142.         score += 70;
  143.         break;
  144.     case 4:
  145.         score += 150;
  146.         break;
  147.     default:
  148.         break;
  149.     }
  150. }
  151.  
  152. const struct shape *randshape(void)
  153. {
  154.     const struct shape *tmp = &shapes[random() % 7];
  155.     int i;
  156.     int j = random() % 4;
  157.    
  158.     for (i = 0; i < j; i++)
  159.         tmp = &shapes[classic ? tmp->rotc : tmp->rot];
  160.    
  161.     return (tmp);
  162. }
  163.  
  164. static void srandomdev(void)
  165. {
  166.     struct timeval tv;
  167.    
  168.     gettimeofday(&tv, NULL);
  169.     srandom(tv.tv_sec + tv.tv_usec / 100000);
  170. }
  171.  
  172. static void tetris_menu_draw(int level)
  173. {
  174.     clear_screen();
  175.     moveto(5, 10);
  176.     puts("Tetris\n\n");
  177.    
  178.     moveto(8, 10);
  179.     printf("Level = %d (press keys 1 - 9 to change)", level);
  180.     moveto(9, 10);
  181.     printf("Preview is %s (press 'p' to change)", (showpreview ? "on ": "off"));
  182.     moveto(12, 10);
  183.     printf("Press 'h' to show hiscore table.");
  184.     moveto(13, 10);
  185.     printf("Press 's' to start game.");
  186.     moveto(14, 10);
  187.     printf("Press 'q' to quit game.");
  188.     moveto(20, 10);
  189.     printf("In game controls:");
  190.     moveto(21, 0);
  191.     puts(key_msg);
  192. }
  193.  
  194. static int tetris_menu(int *level)
  195. {
  196.     tetris_menu_draw(*level);
  197.     while (1) {
  198.         int i = getchar();
  199.        
  200.         switch(i) {
  201.             case 'p':
  202.                 showpreview = !showpreview;
  203.                 moveto(9, 21);
  204.                 if (showpreview)
  205.                     printf("on ");
  206.                 else
  207.                     printf("off");
  208.                 break;
  209.             case 'h':
  210.                 loadscores();
  211.                 showscores(firstgame);
  212.                 tetris_menu_draw(*level);
  213.                 break;
  214.             case 's':
  215.                 firstgame = 0;
  216.                 return 1;
  217.             case 'q':
  218.                 return 0;
  219.             case '1':
  220.             case '2':
  221.             case '3':
  222.             case '4':
  223.             case '5':
  224.             case '6':
  225.             case '7':
  226.             case '8':
  227.             case '9':
  228.                 *level = i - '0';
  229.                 moveto(8, 18);
  230.                 printf("%d", *level);
  231.                 break;
  232.         }
  233.     }
  234. }
  235.  
  236. int main(int argc, char *argv[])
  237. {
  238.     int pos;
  239.     int c;
  240.     const char *keys;
  241.     int level = 2;
  242.     char key_write[6][10];
  243.     int i;
  244.     int j;
  245.     int ch;
  246.    
  247.     keys = "jkl pq";
  248.    
  249.     classic = 0;
  250.     showpreview = 1;
  251.    
  252.     while ((ch = getopt(argc, argv, "ck:ps")) != -1)
  253.         switch(ch) {
  254.         case 'c':
  255.             /*
  256.              * this means:
  257.              *  - rotate the other way
  258.              *  - no reverse video
  259.              */
  260.             classic = 1;
  261.             break;
  262.         case 'k':
  263.             if (str_size(keys = optarg) != 6)
  264.                 usage();
  265.             break;
  266.         case 'p':
  267.             showpreview = 1;
  268.             break;
  269.         case 's':
  270.             showscores(0);
  271.             exit(0);
  272.         default:
  273.             usage();
  274.         }
  275.    
  276.     argc -= optind;
  277.     argv += optind;
  278.    
  279.     if (argc)
  280.         usage();
  281.    
  282.     for (i = 0; i <= 5; i++) {
  283.         for (j = i + 1; j <= 5; j++) {
  284.             if (keys[i] == keys[j])
  285.                 errx(1, "duplicate command keys specified.");
  286.         }
  287.        
  288.         if (keys[i] == ' ')
  289.             str_cpy(key_write[i], sizeof(key_write[i]), "<space>");
  290.         else {
  291.             key_write[i][0] = keys[i];
  292.             key_write[i][1] = '\0';
  293.         }
  294.     }
  295.    
  296.     snprintf(key_msg, sizeof(key_msg),
  297.         "%s - left   %s - rotate   %s - right   %s - drop   %s - pause   %s - quit",
  298.         key_write[0], key_write[1], key_write[2], key_write[3],
  299.         key_write[4], key_write[5]);
  300.    
  301.     scr_init();
  302.     if (loadscores() != EOK)
  303.         initscores();
  304.  
  305.     while (tetris_menu(&level)) {
  306.         fallrate = 1000000 / level;
  307.        
  308.         scr_clear();
  309.         setup_board();
  310.        
  311.         srandomdev();
  312.         scr_set();
  313.        
  314.         pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
  315.         nextshape = randshape();
  316.         curshape = randshape();
  317.        
  318.         scr_msg(key_msg, 1);
  319.        
  320.         while (1) {
  321.             place(curshape, pos, 1);
  322.             scr_update();
  323.             place(curshape, pos, 0);
  324.             c = tgetchar();
  325.             if (c < 0) {
  326.                 /*
  327.                  * Timeout.  Move down if possible.
  328.                  */
  329.                 if (fits_in(curshape, pos + B_COLS)) {
  330.                     pos += B_COLS;
  331.                     continue;
  332.                 }
  333.                
  334.                 /*
  335.                  * Put up the current shape `permanently',
  336.                  * bump score, and elide any full rows.
  337.                  */
  338.                 place(curshape, pos, 1);
  339.                 score++;
  340.                 elide();
  341.                
  342.                 /*
  343.                  * Choose a new shape.  If it does not fit,
  344.                  * the game is over.
  345.                  */
  346.                 curshape = nextshape;
  347.                 nextshape = randshape();
  348.                 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
  349.                
  350.                 if (!fits_in(curshape, pos))
  351.                     break;
  352.                
  353.                 continue;
  354.             }
  355.            
  356.             /*
  357.              * Handle command keys.
  358.              */
  359.             if (c == keys[5]) {
  360.                 /* quit */
  361.                 break;
  362.             }
  363.            
  364.             if (c == keys[4]) {
  365.                 static char msg[] =
  366.                     "paused - press RETURN to continue";
  367.                
  368.                 place(curshape, pos, 1);
  369.                 do {
  370.                     scr_update();
  371.                     scr_msg(key_msg, 0);
  372.                     scr_msg(msg, 1);
  373.                     (void) fflush(stdout);
  374.                 } while (rwait((struct timeval *) NULL) == -1);
  375.                
  376.                 scr_msg(msg, 0);
  377.                 scr_msg(key_msg, 1);
  378.                 place(curshape, pos, 0);
  379.                 continue;
  380.             }
  381.            
  382.             if (c == keys[0]) {
  383.                 /* move left */
  384.                 if (fits_in(curshape, pos - 1))
  385.                     pos--;
  386.                 continue;
  387.             }
  388.            
  389.             if (c == keys[1]) {
  390.                 /* turn */
  391.                 const struct shape *new =
  392.                     &shapes[classic ? curshape->rotc : curshape->rot];
  393.                
  394.                 if (fits_in(new, pos))
  395.                     curshape = new;
  396.                 continue;
  397.             }
  398.            
  399.             if (c == keys[2]) {
  400.                 /* move right */
  401.                 if (fits_in(curshape, pos + 1))
  402.                     pos++;
  403.                 continue;
  404.             }
  405.            
  406.             if (c == keys[3]) {
  407.                 /* move to bottom */
  408.                 while (fits_in(curshape, pos + B_COLS)) {
  409.                     pos += B_COLS;
  410.                     score++;
  411.                 }
  412.                 continue;
  413.             }
  414.            
  415.             if (c == '\f') {
  416.                 scr_clear();
  417.                 scr_msg(key_msg, 1);
  418.             }
  419.         }
  420.        
  421.         scr_clear();
  422.         loadscores();
  423.         insertscore(score, level);
  424.         savescores();
  425.         score = 0;
  426.     }
  427.    
  428.     scr_clear();
  429.     printf("\nGame over.\n");
  430.     scr_end();
  431.    
  432.     return 0;
  433. }
  434.  
  435. void usage(void)
  436. {
  437.     fprintf(stderr, "usage: tetris [-ps] [-k keys]\n");
  438.     exit(1);
  439. }
  440.  
  441. /** @}
  442.  */
  443.