tetris.c

Go to the documentation of this file.
00001 /*      $OpenBSD: tetris.c,v 1.21 2006/04/20 03:24:12 ray Exp $ */
00002 /*      $NetBSD: tetris.c,v 1.2 1995/04/22 07:42:47 cgd Exp $   */
00003 
00004 /*-
00005  * Copyright (c) 1992, 1993
00006  *      The Regents of the University of California.  All rights reserved.
00007  *
00008  * This code is derived from software contributed to Berkeley by
00009  * Chris Torek and Darren F. Provine.
00010  *
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions
00013  * are met:
00014  * 1. Redistributions of source code must retain the above copyright
00015  *    notice, this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright
00017  *    notice, this list of conditions and the following disclaimer in the
00018  *    documentation and/or other materials provided with the distribution.
00019  * 3. Neither the name of the University nor the names of its contributors
00020  *    may be used to endorse or promote products derived from this software
00021  *    without specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00024  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00027  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00028  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00029  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00032  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00033  * SUCH DAMAGE.
00034  *
00035  *      @(#)tetris.c    8.1 (Berkeley) 5/31/93
00036  */
00037 
00045 static const char copyright[] =
00046         "@(#) Copyright (c) 1992, 1993\n"
00047         "\tThe Regents of the University of California.  All rights reserved.\n";
00048 
00049 #include <sys/time.h>
00050 #include <sys/types.h>
00051 #include <err.h>
00052 #include <errno.h>
00053 #include <stdio.h>
00054 #include <stdlib.h>
00055 #include <str.h>
00056 #include <unistd.h>
00057 #include <getopt.h>
00058 
00059 #include "input.h"
00060 #include "scores.h"
00061 #include "screen.h"
00062 #include "tetris.h"
00063 
00064 cell board[B_SIZE];
00065 
00066 int Rows;
00067 int Cols;
00068 
00069 const struct shape *curshape;
00070 const struct shape *nextshape;
00071 
00072 long fallrate;
00073 int score;
00074 char key_msg[100];
00075 int showpreview;
00076 int classic;
00077 
00078 static void elide(void);
00079 static void setup_board(void);
00080 static const struct shape *randshape(void);
00081 
00082 static void usage(void);
00083 
00084 static int firstgame = 1;
00085 
00086 /*
00087  * Set up the initial board. The bottom display row is completely set,
00088  * along with another (hidden) row underneath that. Also, the left and
00089  * right edges are set.
00090  */
00091 static void setup_board(void)
00092 {
00093         int i;
00094         cell *p = board;
00095         
00096         for (i = B_SIZE; i; i--)
00097                 *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 0x0000ff : 0x000000;
00098 }
00099 
00100 /*
00101  * Elide any full active rows.
00102  */
00103 static void elide(void)
00104 {
00105         int rows = 0;
00106         int i;
00107         int j;
00108         int base;
00109         cell *p;
00110         
00111         for (i = A_FIRST; i < A_LAST; i++) {
00112                 base = i * B_COLS + 1;
00113                 p = &board[base];
00114                 for (j = B_COLS - 2; *p++ != 0;) {
00115                         if (--j <= 0) {
00116                                 /* This row is to be elided */
00117                                 rows++;
00118                                 memset(&board[base], 0, sizeof(cell) * (B_COLS - 2));
00119                                 
00120                                 scr_update();
00121                                 tsleep();
00122                                 
00123                                 while (--base != 0)
00124                                         board[base + B_COLS] = board[base];
00125                                 
00126                                 scr_update();
00127                                 tsleep();
00128                                 
00129                                 break;
00130                         }
00131                 }
00132         }
00133         
00134         switch (rows) {
00135         case 1:
00136                 score += 10;
00137                 break;
00138         case 2:
00139                 score += 30;
00140                 break;
00141         case 3:
00142                 score += 70;
00143                 break;
00144         case 4:
00145                 score += 150;
00146                 break;
00147         default:
00148                 break;
00149         }
00150 }
00151 
00152 const struct shape *randshape(void)
00153 {
00154         const struct shape *tmp = &shapes[random() % 7];
00155         int i;
00156         int j = random() % 4;
00157         
00158         for (i = 0; i < j; i++)
00159                 tmp = &shapes[classic ? tmp->rotc : tmp->rot];
00160         
00161         return (tmp);
00162 }
00163 
00164 static void srandomdev(void)
00165 {
00166         struct timeval tv;
00167         
00168         gettimeofday(&tv, NULL);
00169         srandom(tv.tv_sec + tv.tv_usec / 100000);
00170 }
00171 
00172 static void tetris_menu_draw(int level) 
00173 {
00174         clear_screen();
00175         moveto(5, 10);
00176         puts("Tetris\n\n");
00177         
00178         moveto(8, 10);
00179         printf("Level = %d (press keys 1 - 9 to change)", level);
00180         moveto(9, 10);
00181         printf("Preview is %s (press 'p' to change)", (showpreview ? "on ": "off"));
00182         moveto(12, 10);
00183         printf("Press 'h' to show hiscore table.");
00184         moveto(13, 10);
00185         printf("Press 's' to start game.");
00186         moveto(14, 10);
00187         printf("Press 'q' to quit game.");
00188         moveto(20, 10);
00189         printf("In game controls:");
00190         moveto(21, 0);
00191         puts(key_msg);
00192 }
00193 
00194 static int tetris_menu(int *level)
00195 {
00196         tetris_menu_draw(*level);
00197         while (1) {
00198                 int i = getchar();
00199                 
00200                 switch(i) {
00201                         case 'p':
00202                                 showpreview = !showpreview;
00203                                 moveto(9, 21);
00204                                 if (showpreview)
00205                                         printf("on ");
00206                                 else
00207                                         printf("off");
00208                                 break;
00209                         case 'h':
00210                                 loadscores();
00211                                 showscores(firstgame);
00212                                 tetris_menu_draw(*level);
00213                                 break;
00214                         case 's':
00215                                 firstgame = 0;
00216                                 return 1;
00217                         case 'q':
00218                                 return 0;
00219                         case '1':
00220                         case '2':
00221                         case '3':
00222                         case '4':
00223                         case '5':
00224                         case '6':
00225                         case '7':
00226                         case '8':
00227                         case '9':
00228                                 *level = i - '0';
00229                                 moveto(8, 18);
00230                                 printf("%d", *level);
00231                                 break;
00232                 }
00233         }
00234 }
00235 
00236 int main(int argc, char *argv[])
00237 {
00238         int pos;
00239         int c;
00240         const char *keys;
00241         int level = 2;
00242         char key_write[6][10];
00243         int i;
00244         int j;
00245         int ch;
00246         
00247         keys = "jkl pq";
00248         
00249         classic = 0;
00250         showpreview = 1; 
00251         
00252         while ((ch = getopt(argc, argv, "ck:ps")) != -1)
00253                 switch(ch) {
00254                 case 'c':
00255                         /*
00256                          * this means:
00257                          *  - rotate the other way
00258                          *  - no reverse video
00259                          */
00260                         classic = 1;
00261                         break;
00262                 case 'k':
00263                         if (str_size(keys = optarg) != 6)
00264                                 usage();
00265                         break;
00266                 case 'p':
00267                         showpreview = 1;
00268                         break;
00269                 case 's':
00270                         showscores(0);
00271                         exit(0);
00272                 default:
00273                         usage();
00274                 }
00275         
00276         argc -= optind;
00277         argv += optind;
00278         
00279         if (argc)
00280                 usage();
00281         
00282         for (i = 0; i <= 5; i++) {
00283                 for (j = i + 1; j <= 5; j++) {
00284                         if (keys[i] == keys[j])
00285                                 errx(1, "duplicate command keys specified.");
00286                 }
00287                 
00288                 if (keys[i] == ' ')
00289                         str_cpy(key_write[i], sizeof(key_write[i]), "<space>");
00290                 else {
00291                         key_write[i][0] = keys[i];
00292                         key_write[i][1] = '\0';
00293                 }
00294         }
00295         
00296         snprintf(key_msg, sizeof(key_msg),
00297             "%s - left   %s - rotate   %s - right   %s - drop   %s - pause   %s - quit",
00298             key_write[0], key_write[1], key_write[2], key_write[3],
00299             key_write[4], key_write[5]);
00300         
00301         scr_init();
00302         if (loadscores() != EOK)
00303                 initscores();
00304 
00305         while (tetris_menu(&level)) {
00306                 fallrate = 1000000 / level;
00307                 
00308                 scr_clear();
00309                 setup_board();
00310                 
00311                 srandomdev();
00312                 scr_set();
00313                 
00314                 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
00315                 nextshape = randshape();
00316                 curshape = randshape();
00317                 
00318                 scr_msg(key_msg, 1);
00319                 
00320                 while (1) {
00321                         place(curshape, pos, 1);
00322                         scr_update();
00323                         place(curshape, pos, 0);
00324                         c = tgetchar();
00325                         if (c < 0) {
00326                                 /*
00327                                  * Timeout.  Move down if possible.
00328                                  */
00329                                 if (fits_in(curshape, pos + B_COLS)) {
00330                                         pos += B_COLS;
00331                                         continue;
00332                                 }
00333                                 
00334                                 /*
00335                                  * Put up the current shape `permanently',
00336                                  * bump score, and elide any full rows.
00337                                  */
00338                                 place(curshape, pos, 1);
00339                                 score++;
00340                                 elide();
00341                                 
00342                                 /*
00343                                  * Choose a new shape.  If it does not fit,
00344                                  * the game is over.
00345                                  */
00346                                 curshape = nextshape;
00347                                 nextshape = randshape();
00348                                 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
00349                                 
00350                                 if (!fits_in(curshape, pos))
00351                                         break;
00352                                 
00353                                 continue;
00354                         }
00355                         
00356                         /*
00357                          * Handle command keys.
00358                          */
00359                         if (c == keys[5]) {
00360                                 /* quit */
00361                                 break;
00362                         }
00363                         
00364                         if (c == keys[4]) {
00365                                 static char msg[] =
00366                                     "paused - press RETURN to continue";
00367                                 
00368                                 place(curshape, pos, 1);
00369                                 do {
00370                                         scr_update();
00371                                         scr_msg(key_msg, 0);
00372                                         scr_msg(msg, 1);
00373                                         (void) fflush(stdout);
00374                                 } while (rwait((struct timeval *) NULL) == -1);
00375                                 
00376                                 scr_msg(msg, 0);
00377                                 scr_msg(key_msg, 1);
00378                                 place(curshape, pos, 0);
00379                                 continue;
00380                         }
00381                         
00382                         if (c == keys[0]) {
00383                                 /* move left */
00384                                 if (fits_in(curshape, pos - 1))
00385                                         pos--;
00386                                 continue;
00387                         }
00388                         
00389                         if (c == keys[1]) {
00390                                 /* turn */
00391                                 const struct shape *new =
00392                                     &shapes[classic ? curshape->rotc : curshape->rot];
00393                                 
00394                                 if (fits_in(new, pos))
00395                                         curshape = new;
00396                                 continue;
00397                         }
00398                         
00399                         if (c == keys[2]) {
00400                                 /* move right */
00401                                 if (fits_in(curshape, pos + 1))
00402                                         pos++;
00403                                 continue;
00404                         }
00405                         
00406                         if (c == keys[3]) {
00407                                 /* move to bottom */
00408                                 while (fits_in(curshape, pos + B_COLS)) {
00409                                         pos += B_COLS;
00410                                         score++;
00411                                 }
00412                                 continue;
00413                         }
00414                         
00415                         if (c == '\f') {
00416                                 scr_clear();
00417                                 scr_msg(key_msg, 1);
00418                         }
00419                 }
00420                 
00421                 scr_clear();
00422                 loadscores();
00423                 insertscore(score, level);
00424                 savescores();
00425                 score = 0;
00426         }
00427         
00428         scr_clear();
00429         printf("\nGame over.\n");
00430         scr_end();
00431         
00432         return 0;
00433 }
00434 
00435 void usage(void)
00436 {
00437         fprintf(stderr, "usage: tetris [-ps] [-k keys]\n");
00438         exit(1);
00439 }
00440 

Generated on Thu Jun 2 07:45:43 2011 for HelenOS/USB by  doxygen 1.4.7