home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Appls / tetris / tetris.c < prev   
Encoding:
C/C++ Source or Header  |  1991-03-28  |  15.8 KB  |  752 lines  |  [TEXT/????]

  1. /* Tetris.
  2.  
  3.    A simple but challenging game where pieces of different shapes
  4.    falling with a constant speed must be manoeuvered to a final
  5.    docking position.  Piece shapes are randomly chosen from all possible
  6.    ways to connect four squares.  The manipulations allowed are moving
  7.    the piece left or right and rotating it; every clock tick it moves
  8.    down one step, until it cannot move further, or the player decides
  9.    to "drop" it to earn more points.  The game is made more or less
  10.    challenging by making the clock tick faster or slower.  A score is
  11.    kept.  Points earned per piece depend on the height where it is
  12.    dropped or stopped; extra points are awarded for choosing a higher
  13.    speed ("level").  To allow the play to continue indefinitely,
  14.    complete rows (i.e., horizontal rows where all squares
  15.    are filled) are removed from the board and its contents above that
  16.    row shifted down.
  17.    
  18.    The user interface uses mostly the left, right and up keys, for
  19.    moving the piece left and right and rotating it.  For Unix adepts,
  20.    'h'=left, 'k'=up and 'l'=right also work.  Space bar or Return
  21.    drops the piece.  The Cancel key (Command-Period on the Mac,
  22.    Control-C on most other systems) restarts the game; close the window
  23.    or type 'q' to quit the game.
  24.    
  25.    The origin of the game appears to be in the East Block; I've heard
  26.    that the (original?) Macintosh version was by a Hungarian programmer.
  27.    
  28.    This code is hereby put in the public domain, but the package
  29.    STDWIN used as portable window interface is copyrighted.  STDWIN
  30.    is available from me, too, provided you respect the copyright etc.
  31.    
  32.    Guido van Rossum, CWI, Kruislaan 413, 1098 SJ Amsterdam,
  33.    The Netherlands
  34.    Internet e-mail address: guido@cwi.nl
  35.    April 1989
  36. */
  37.  
  38. /* TO DO:
  39.     - show next piece coming up in a side window
  40.     - change chance distribution of pieces? (too few bars)
  41.     - advanced level (what should it do? just faster?)
  42.     - rethink level <--> delay relation
  43.     
  44.     - improve "game over" behavior
  45.     
  46.     - display high score
  47.     - score and status display next to the board
  48.     - statistics
  49.     
  50.     - cute graphics
  51. */
  52.  
  53. /* Standard include files */
  54.  
  55. #include "stdwin.h"
  56. #include <stdio.h>
  57.  
  58. /* Parametrizations */
  59.  
  60. /* Piece size.  It only makes sense to change this if you also
  61.    change the initialization of the 'shapes' array.
  62.    Since we rotate pieces, their max size must always be square. */ 
  63. #define PSIZE 4
  64.  
  65. /* Game dimensions.  Traditionally it is played on a 10x20 board. */
  66. #ifndef BWIDTH
  67. #define BWIDTH 10
  68. #endif
  69. #ifndef BHEIGHT
  70. #define BHEIGHT 20
  71. #endif
  72.  
  73. /* Initial timer delay.  This affects initial difficulty and scoring.
  74.    The current value is kept in variable 'delay'. */
  75. #ifndef DELAY
  76. #define DELAY 10
  77. #endif
  78.  
  79. /* Individual 'square' sizes.
  80.    These can be adjusted according to taste and the size of pixels
  81.    on your screen.  (You can also fine-tune window and document size
  82.    in main() below.)
  83.    For the alfa version of STDWIN, where pixel size == character size,
  84.    a fixed size of 2x1 is forced later. */
  85. #ifndef SQWIDTH
  86. #define SQWIDTH 12
  87. #endif
  88. #ifndef SQHEIGHT
  89. #define SQHEIGHT 12
  90. #endif
  91.  
  92. /* Left, top of board image in window */
  93. #ifndef BLEFT
  94. #define BLEFT 0
  95. #endif
  96. #ifndef BTOP
  97. #define BTOP 4
  98. #endif
  99.  
  100. /* Some useful macros (predefined on some but not all systems) */
  101.  
  102. #ifndef MIN
  103. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  104. #endif
  105.  
  106. #ifndef MAX
  107. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  108. #endif
  109.  
  110. /* Available shapes.
  111.    Relnext is the offset to the next piece after rotation.
  112.    The pieces are aligned with the bottom so their scoring values are
  113.    comparable, and the delay before their start is minimal; they are
  114.    centered horizontally so the random placement appears even.
  115.    Remember C's aggregate initialization rules; the initializer below
  116.    is completely bracketed, but trailing zeros are sometimes elided. */
  117.  
  118. struct shapedef {
  119.     int relnext;
  120.     char piece[PSIZE][PSIZE];
  121. } shapes[] = {
  122.     
  123.     /* "Four in a row" (2 orientations) */
  124.     
  125.     {1,    {{0, 0, 0, 0},
  126.          {0, 0, 0, 0},
  127.          {0, 0, 0, 0},
  128.          {1, 1, 1, 1}}},
  129.     
  130.     {-1,    {{0, 1, 0, 0},
  131.          {0, 1, 0, 0},
  132.          {0, 1, 0, 0},
  133.          {0, 1, 0, 0}}},
  134.     
  135.     /* "L shape" (4 orientations) */
  136.     
  137.     {1,    {{0, 0, 0},
  138.          {0, 1, 0},
  139.          {0, 1, 0},
  140.          {0, 1, 1}}},
  141.     
  142.     {1,    {{0, 0, 0},
  143.          {0, 0, 0},
  144.          {0, 0, 1},
  145.          {1, 1, 1}}},
  146.     
  147.     {1,    {{0, 0, 0},
  148.          {0, 1, 1},
  149.          {0, 0, 1},
  150.          {0, 0, 1}}},
  151.     
  152.     {-3,    {{0, 0, 0},
  153.          {0, 0, 0},
  154.          {1, 1, 1},
  155.          {1, 0, 0}}},
  156.     
  157.     /* "Inverse L shape" (4 orientations) */
  158.     
  159.     {1,    {{0, 0, 0},
  160.          {0, 1, 1},
  161.          {0, 1, 0},
  162.          {0, 1, 0}}},
  163.     
  164.     {1,    {{0, 0, 0},
  165.          {0, 0, 0},
  166.          {1, 0, 0},
  167.          {1, 1, 1}}},
  168.     
  169.     {1,    {{0, 0, 0},
  170.          {0, 0, 1},
  171.          {0, 0, 1},
  172.          {0, 1, 1}}},
  173.     
  174.     {-3,    {{0, 0, 0},
  175.          {0, 0, 0},
  176.          {1, 1, 1},
  177.          {0, 0, 1}}},
  178.     
  179.     /* "Z shape" (2 orientations) */
  180.     
  181.     {1,    {{0, 0, 0},
  182.          {0, 0, 0},
  183.          {1, 1, 0},
  184.          {0, 1, 1}}},
  185.     
  186.     {-1,    {{0, 0, 0},
  187.          {0, 0, 1},
  188.          {0, 1, 1},
  189.          {0, 1, 0}}},
  190.     
  191.     /* "S shape" (2 orientations) */
  192.     
  193.     {1,    {{0, 0, 0},
  194.          {0, 1, 0},
  195.          {0, 1, 1},
  196.          {0, 0, 1}}},
  197.     
  198.     {-1,    {{0, 0, 0},
  199.          {0, 0, 0},
  200.          {0, 1, 1},
  201.          {1, 1, 0}}},
  202.     
  203.     /* "T shape" (4 orientations) */
  204.     
  205.     {1,    {{0, 0, 0},
  206.          {0, 0, 0},
  207.          {1, 1, 1},
  208.          {0, 1, 0}}},
  209.     
  210.     {1,    {{0, 0, 0},
  211.          {0, 1, 0},
  212.          {0, 1, 1},
  213.          {0, 1, 0}}},
  214.     
  215.     {1,    {{0, 0, 0},
  216.          {0, 0, 0},
  217.          {0, 1, 0},
  218.          {1, 1, 1}}},
  219.     
  220.     {-3,    {{0, 0, 0},
  221.          {0, 0, 1},
  222.          {0, 1, 1},
  223.          {0, 0, 1}}},
  224.     
  225.     /* "Block" (1 orientation) */
  226.     
  227.     {0,    {{0, 0, 0},
  228.          {0, 0, 0},
  229.          {0, 1, 1},
  230.          {0, 1, 1}}},
  231.  
  232. };
  233.  
  234. /* Global variables */
  235.  
  236. int alfa;            /* Nonzero if using alfa STDWIN */
  237. int sqwidth = SQWIDTH;        /* Width of squares, in pixels */
  238. int sqheight = SQHEIGHT;    /* Height */
  239. int bleft = BLEFT;
  240. int btop = BTOP;
  241. WINDOW *win;            /* The window where we do our drawing */
  242. int delay;            /* Current delay */
  243.                 /* NB: level = MAX(0, DELAY-delay) */
  244. char board[BHEIGHT][BWIDTH];    /* Contents of board, except current piece */
  245. char (*piece)[PSIZE];        /* Piece currently being manoeuvered */
  246. int pindex;            /* Index in the shape array of current piece */
  247. int pleft, ptop;        /* Position of current piece */
  248. long score;            /* Score of current game */
  249.  
  250. /* Generate an informative title from level and/or score.
  251.    (By putting it in the title bar we don't need an info window.) */
  252.  
  253. settitle()
  254. {
  255.     char buf[100];
  256.     int level = MAX(0, DELAY-delay);
  257.     
  258.     if (level == 0) {
  259.         if (score == 0)
  260.             strcpy(buf, "Tetris");
  261.         else
  262.             sprintf(buf, "Score %ld", score);
  263.     }
  264.     else {
  265.         if (score == 0)
  266.             sprintf(buf, "Level %d", level);
  267.         else
  268.             sprintf(buf, "Sc %ld Lv %d", score, level);
  269.     }
  270.     wsettitle(win, buf);
  271. }
  272.  
  273. /* Erase a portion of the board on the screen.
  274.    Call only within wbegin/enddrawing. */
  275.  
  276. eraseboard(ileft, itop, iright, ibottom)
  277.     int ileft, itop, iright, ibottom;
  278. {
  279.     werase(bleft + ileft*sqwidth,  btop + itop*sqheight,
  280.            bleft + iright*sqwidth, btop + ibottom*sqheight);
  281. }
  282.  
  283. /* Draw a portion of the board, and a border around it.
  284.    Call only within wbegin/enddrawing.
  285.    This may be called with out-of-range parameters.
  286.    Draw those squares of the game that lie (partly) in the rectangle
  287.    given by the parameters.  Assume the background is blank.
  288.    This contains #ifdef'ed code for the alfa version of STDWIN,
  289.    which only supports text output. */
  290.  
  291. drawboard(ileft, itop, iright, ibottom)
  292.     int ileft, itop, iright, ibottom;
  293. {
  294.     int ih, iv;
  295.     int h, v;
  296.     int flag;
  297.     
  298.     ileft = MAX(0, ileft);
  299.     itop = MAX(0, itop);
  300.     iright = MIN(BWIDTH, iright);
  301.     ibottom = MIN(BHEIGHT, ibottom);
  302.     for (iv = itop, v = btop + iv*sqheight; iv < ibottom;
  303.                     ++iv, v += sqheight) {
  304.         for (ih = ileft, h = bleft + ih*sqwidth; ih < iright;
  305.                         ++ih, h += sqwidth) {
  306.             flag = board[iv][ih];
  307.             if (!flag && pleft <= ih && ih < pleft+PSIZE &&
  308.                     ptop <= iv && iv < ptop+PSIZE)
  309.                 flag = piece[iv-ptop][ih-pleft];
  310.             if (flag) {
  311.                 if (alfa)
  312.                     wdrawchar(h, v, '#');
  313.                 else
  314.                     wshade(h+1, v+1,
  315.                         h+sqwidth, v+sqheight, 50);
  316.             }
  317.         }
  318.     }
  319.     if (alfa) {
  320.         /* Draw markers at the right margin */
  321.         wdrawchar(bleft + BWIDTH*sqwidth, btop, '|');
  322.         wdrawchar(bleft + BWIDTH*sqwidth, btop + (BHEIGHT-1)*sqheight,
  323.                                     '|');
  324.     }
  325.     else {
  326.         /* Draw a box around the board */
  327.         wdrawbox(bleft - 1, btop - 1, bleft + BWIDTH*sqwidth + 2,
  328.                         btop + BHEIGHT*sqheight + 2);
  329.     }
  330. }
  331.  
  332. /* Erase and redraw part of the board.
  333.    Unlike eraseboard and drawboard above, this includes calls to
  334.    wbegin/enddrawing. */
  335.  
  336. redrawboard(ileft, itop, iright, ibottom)
  337.     int ileft, itop, iright, ibottom;
  338. {
  339.     wbegindrawing(win);
  340.     eraseboard(ileft, itop, iright, ibottom);
  341.     drawboard(ileft, itop, iright, ibottom);
  342.     wenddrawing(win);
  343. }
  344.  
  345. /* Draw procedure, passed to STDWIN's wopen */
  346.  
  347. void
  348. drawproc(win, left, top, right, bottom)
  349.     WINDOW *win;
  350.     int left, top, right, bottom;
  351. {
  352.     drawboard((left-bleft)/sqwidth, (top-btop)/sqheight,
  353.         (right-bleft+sqwidth-1)/sqwidth,
  354.         (bottom-btop+sqheight-1)/sqheight);
  355. }
  356.  
  357. /* Check if the piece can be at (dh, dv).
  358.    This is used to check for legal moves.
  359.    No part of the piece can be on a filled spot in the board or
  360.    be outside it, but it can stick out above the top. */
  361.  
  362. int
  363. allowed(dh, dv)
  364.     int dh, dv;
  365. {
  366.     int ih, iv;
  367.     
  368.     for (iv = 0; iv < PSIZE; ++iv) {
  369.         for (ih = 0; ih < PSIZE; ++ih) {
  370.             if (piece[iv][ih]) {
  371.                 if (ih+dh < 0 || ih+dh >= BWIDTH)
  372.                     return 0;
  373.                 if (iv+dv < 0)
  374.                     continue;
  375.                 if (iv+dv >= BHEIGHT)
  376.                     return 0;
  377.                 if (board[iv+dv][ih+dh])
  378.                     return 0;
  379.             }
  380.         }
  381.     }
  382.     return 1;
  383. }
  384.  
  385. /* Return a random integer in the range [0..n-1] */
  386.  
  387. int
  388. uniform(n)
  389.     int n;
  390. {
  391.     return rand() % n;
  392. }
  393.  
  394. /* Rotate the piece 90 degrees counterclockwise.  No drawing is done.
  395.    The implementation is trivial: just take the "next" element from the
  396.    shape array. */
  397.  
  398. leftrotate()
  399. {
  400.     pindex += shapes[pindex].relnext;
  401.     piece = shapes[pindex].piece;
  402. }
  403.  
  404. /* Move the piece by the given vector (dh, dv), if this is a legal move..
  405.    Return 1 if moved, 0 if not (then no changes were made). */
  406.  
  407. int
  408. moveby(dh, dv)
  409.     int dh, dv;
  410. {
  411.     int ileft, itop, iright, ibottom;
  412.     
  413.     if (!allowed(pleft+dh, ptop+dv)) {
  414.         return 0;
  415.     }
  416.     ileft   = pleft + MIN(dh, 0);
  417.     itop    = ptop  + MIN(dv, 0);
  418.     iright  = pleft + PSIZE + MAX(dh, 0);
  419.     ibottom = ptop  + PSIZE + MAX(dv, 0);
  420.     pleft += dh;
  421.     ptop += dv;
  422.     redrawboard(ileft, itop, iright, ibottom);
  423.     return 1;
  424. }
  425.  
  426. /* Rotate the piece n quarter left turns, if this is a legal move.
  427.    Return 1 if moved, 0 if not (then no changes were made). */
  428.  
  429. int
  430. rotateby(n)
  431.     int n;
  432. {
  433.     int i;
  434.     
  435.     for (i = 0; i < n; ++i)
  436.         leftrotate();
  437.     if (!allowed(pleft, ptop)) {
  438.         for (i = 0; i < 4-n; ++i)
  439.             leftrotate();
  440.         return 0;
  441.     }
  442.     redrawboard(pleft, ptop, (pleft+PSIZE), (ptop+PSIZE));
  443.     return 1;
  444. }
  445.  
  446.  
  447. /* Trivial routines to implement the commands. */
  448.  
  449. left()
  450. {
  451.     (void) moveby(-1, 0);
  452. }
  453.  
  454. right()
  455. {
  456.     (void) moveby(1, 0);
  457. }
  458.  
  459. rot()
  460. {
  461.     (void) rotateby(1);
  462. }
  463.  
  464. /* Generate a new piece.  Its initial position is just above the top of
  465.    the board, so that a single move down will show its bottom row.
  466.    (This is one reason why the pieces are aligned with the bottom in the
  467.    'shapes' array.) */
  468.  
  469. generate()
  470. {
  471.     pindex = uniform(sizeof shapes / sizeof shapes[0]);
  472.     
  473.     piece = shapes[pindex].piece;
  474.     pleft = (BWIDTH-PSIZE) / 2;
  475.     ptop = -PSIZE;
  476. }
  477.  
  478. /* Start a new game.
  479.    Reset deley/level, score, board and title; generate a new piece.
  480.    The game is not restarted immediately. */
  481.  
  482. reset()
  483. {
  484.     int ih, iv;
  485.     
  486.     wsettimer(win, 0);
  487.     delay = DELAY;
  488.     score = 0;
  489.     for (iv = 0; iv < BHEIGHT; ++iv) {
  490.         for (ih = 0; ih < BWIDTH; ++ih)
  491.             board[iv][ih] = 0;
  492.     }
  493.     generate();
  494.     redrawboard(0, 0, BWIDTH, BHEIGHT);
  495.     settitle();
  496. }
  497.  
  498. /* Remove any full rows found, shifting the board above down */
  499.  
  500. removerows()
  501. {
  502.     int ih, iv;
  503.     int jv;
  504.     
  505.     for (iv = 0; iv < BHEIGHT; ++iv) {
  506.         for (ih = 0; ih < BWIDTH; ++ih) {
  507.             if (!board[iv][ih])
  508.                 goto next; /* Two-level continue */
  509.         }
  510.         for (jv = iv; jv > 0; --jv) {
  511.             for (ih = 0; ih < BWIDTH; ++ih)
  512.                 board[jv][ih] = board[jv-1][ih];
  513.         }
  514.         for (ih = 0; ih < BWIDTH; ++ih)
  515.             board[jv][ih] = 0;
  516.         wscroll(win,
  517.             bleft, btop,
  518.             bleft + BWIDTH*sqwidth, btop + (iv+1)*sqheight,
  519.             0, sqheight);
  520.     next:    ;
  521.     }
  522. }
  523.  
  524. /* Add the score for the current piece to the total score.
  525.    The title is not regenerated; that is done later in finish(). */
  526.  
  527. addscore()
  528. {
  529.     int level = MAX(0, DELAY-delay);
  530.     int height = MAX(0, BHEIGHT-ptop);
  531.     
  532.     score += height + 2*level /* *(advanced?2:1) */ ;
  533. }
  534.  
  535. /* Finish a piece off by dropping it; score and generate a new one.
  536.    Called by the user and from timer of the piece can't move down.
  537.    This also contains a hack to detect the end of the game:
  538.    if the new piece can't move one step, it is over. */
  539.  
  540. finish()
  541. {
  542.     int ih, iv;
  543.     
  544.     addscore();
  545.     while (moveby(0, 1))
  546.         ;
  547.     for (iv = 0; iv < PSIZE; ++iv) {
  548.         for (ih = 0; ih < PSIZE; ++ih) {
  549.             if (piece[iv][ih] && iv+ptop >= 0)
  550.                 board[iv+ptop][ih+pleft] = 1;
  551.         }
  552.     }
  553.     removerows();
  554.     generate();
  555.     settitle();
  556.     if (moveby(0, 1))
  557.         wsettimer(win, delay);
  558.     else {
  559.         if (alfa) {
  560.             /* Alfa STDWIN's wmessage doesn't wait for an OK */
  561.             char buffer[10];
  562.             strcpy(buffer, "Game over");
  563.             (void) waskstr("", buffer, strlen(buffer));
  564.         }
  565.         else
  566.             wmessage("Game over");
  567.         reset();
  568.     }
  569. }
  570.  
  571. /* The clock has ticked.
  572.    Try to move down; if it can't, finish it off and start a new one. */
  573.  
  574. timer()
  575. {
  576.     if (moveby(0, 1))
  577.         wsettimer(win, delay);
  578.     else
  579.         finish();
  580. }
  581.  
  582. /* Make the clock tick faster (increase level) */
  583.  
  584. faster()
  585. {
  586.     if (delay > 1)
  587.         --delay;
  588.     settitle();
  589. }
  590.  
  591. /* Make the clock tick slower (decrease level) */
  592.  
  593. slower()
  594. {
  595.     ++delay;
  596.     settitle();
  597. }
  598.  
  599. /* Quit the program.
  600.    Note that wdone() MUST be called before a STDWIN application exits. */
  601.  
  602. quit()
  603. {
  604.     wdone();
  605.     exit(0);
  606. }
  607.  
  608. /* Main event loop.
  609.    React on commands, ignoring illegal ones, and react to clock ticks.
  610.    Call various routines to execute the commands.
  611.    Never return; calls quit() to exit. */
  612.  
  613. mainloop()
  614. {
  615.     EVENT e;
  616.     
  617.     for (;;) {
  618.         wgetevent(&e);
  619.         
  620.         switch (e.type) {
  621.         
  622.         case WE_TIMER:
  623.             timer();
  624.             break;
  625.         
  626.         case WE_CHAR:
  627.             switch (e.u.character) {
  628.             case '+':
  629.                 faster();
  630.                 break;
  631.             case '-':
  632.                 slower();
  633.                 break;
  634.             case 'g':
  635.                 timer();
  636.                 break;
  637.             case ' ':
  638.                 finish();
  639.                 break;
  640.             case 'h':
  641.                 left();
  642.                 break;
  643.             case 'k':
  644.                  rot();
  645.                  break;
  646.             case 'l':
  647.                 right();
  648.                 break;
  649.             case 'q':
  650.                 quit();
  651.                 break;
  652.             case 'r':
  653.                 reset();
  654.                 break;
  655.             case '0': case '1': case '2': case '3': case '4':
  656.             case '5': case '6': case '7': case '8': case '9':
  657.                 delay = DELAY-(e.u.character-'0');
  658.                 delay = MAX(1, delay);
  659.                 settitle();
  660.                 break;
  661.             }
  662.             break;
  663.         
  664.         case WE_CLOSE:
  665.             quit();
  666.             break;
  667.  
  668.         case WE_COMMAND:
  669.             switch (e.u.command) {
  670.             case WC_RETURN:
  671.                 timer();
  672.                 break;
  673.             case WC_CANCEL:
  674.                 reset();
  675.                 break;
  676.             case WC_CLOSE:
  677.                 quit();
  678.                 break;
  679.             case WC_LEFT:
  680.                 left();
  681.                 break;
  682.             case WC_UP:
  683.                 rot();
  684.                 break;
  685.             case WC_RIGHT:
  686.                 right();
  687.                 break;
  688.             }
  689.             break;
  690.         
  691.         }
  692.     }
  693.     /*NOTREACHED*/
  694. }
  695.  
  696. /* Add a menu, only used as a cheap way to display some help */
  697.  
  698. addhelpmenu()
  699. {
  700.     MENU *mp;
  701.     
  702.     mp = wmenucreate(1, "Help");
  703.     wmenuadditem(mp, "g or return starts the game", -1);
  704.     wmenuadditem(mp, "", -1);
  705.     wmenuadditem(mp, "h or left arrow moves left", -1);
  706.     wmenuadditem(mp, "l or right arrow moves right", -1);
  707.     wmenuadditem(mp, "k or up arrow rotates", -1);
  708.     wmenuadditem(mp, "space drops", -1);
  709.     wmenuadditem(mp, "", -1);
  710.     wmenuadditem(mp, "+/- increases/decreases level (speed)", -1);
  711.     wmenuadditem(mp, "0-9 chooses level directly", -1);
  712.     wmenuadditem(mp, "", -1);
  713.     wmenuadditem(mp, "r or cancel restarts", -1);
  714.     wmenuadditem(mp, "close or q quits the game", -1);
  715. }
  716.  
  717. /* Main program.
  718.    Initialize STDWIN, create the window and the help menu,
  719.    reset the game and call 'mainloop()' to play it. */
  720.  
  721. main(argc, argv)
  722.     int argc;
  723.     char **argv;
  724. {
  725.     long t;
  726.     
  727.     time(&t);
  728.     srand((short)t ^ (short)(t>>16));
  729.     winitargs(&argc, &argv);
  730.     wsetdefscrollbars(0, 0);
  731.     if (wlineheight() == 1) {
  732.         alfa = 1;
  733.         sqwidth = 2;
  734.         sqheight = 1;
  735.         bleft = btop = 0;
  736.     }
  737.     wsetdefwinsize(bleft + BWIDTH*sqwidth + 1,
  738.                     btop + BHEIGHT*sqheight + 5);
  739.     win = wopen("Tetris", drawproc);
  740.     if (win == NULL) {
  741.         printf("Can't create window\n");
  742.         wdone();
  743.         exit(1);
  744.     }
  745.     wsetdocsize(win,
  746.         bleft + BWIDTH*sqwidth + 1, btop + BHEIGHT*sqheight + 1);
  747.     addhelpmenu();
  748.     reset();
  749.     mainloop();
  750.     /*NOTREACHED*/
  751. }
  752.