home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 10: Diskmags / nf_archive_10.iso / MAGS / ST_USER / 1993 / USERJN93.MSA / OTHELLO2.C < prev    next >
C/C++ Source or Header  |  1993-04-20  |  20KB  |  675 lines

  1. /* DO NOT LOAD THIS FILE UNCHANGED INTO THE HISOFT C INTERPRETER.
  2.  * IT WON'T WORK.
  3.  *
  4.  * If you wish to use this file with the Hisoft C Interpreter then you
  5.  * will have to _delete_ the two lines below which contain the symbol IC
  6.  * as well as all of the lines between those two. This is necessary because
  7.  * of the Hisoft package's non-standard manner of handling these pre-processor
  8.  * commands. Try not to worry too much about what this means, we'll be dealing
  9.  * with pre-processor commands in more detail in future articles.
  10.  *
  11.  * This small chunk of # commands are instructions to the compiler.
  12.  * For now, you can ignore them, as we will be examining them next month.
  13.  */
  14. #include <stdio.h>        /* STandarD Input and Output Header    */
  15.  
  16. #ifndef IC
  17. #include <malloc.h>        /* Memory ALLOCation Header file    */
  18. #include <osbind.h>        /* Operating System BINDings Header    */
  19.  
  20. #ifdef SOZOBON
  21. #define malloc        lalloc    /* Sozobon C's malloc uses int argument    */
  22. #endif SOZOBON
  23. #endif IC
  24.  
  25. #ifndef FALSE
  26. #define TRUE    (1==1)
  27. #define FALSE    (1==0)
  28. #endif FALSE
  29.  
  30. /*******************************************************************************
  31.      Set up global variables. These variables are usable by all functions.
  32. *******************************************************************************/
  33.  
  34. char *board        = NULL;        /* Pointer to Othello Board    */
  35.  
  36. /* The representation of the Othello pieces used in the screen display is
  37.  * stored in the piece[] array, while (int)player indicates which player's
  38.  * turn it is, and is an index into the piece[] array giving the piece used
  39.  * by that player.
  40.  */
  41. char piece[2]        = { 'O', 'X' };
  42. int player        = 0;
  43.  
  44. int end_othello        = 0;        /* Set non-zero to exit Othello    */
  45.  
  46.  
  47. /* Error messages for Othello.
  48.  *
  49.  * Note that we must explicitly state the size of the array [3] here if we
  50.  * want to use this source code with packages, such as Hisoft C, which cannot
  51.  * handle implicit array sizing ( where we would just write: char *errors[] = )
  52.  */
  53. char *errors[3] =    {                /* end_othello    */
  54.             "Not enough memory",        /*    1    */
  55.             "Error displaying Board",    /*    2    */
  56.             "Quit pressed"            /*    3    */
  57.             };
  58.  
  59.  
  60. /*******************************************************************************
  61. main()        -    Entry point of program
  62. *******************************************************************************/
  63.  
  64. main()
  65. {
  66. int x, y;            /* Coordinates of the player's move    */
  67. void init();            /* Initialises global variables.    */
  68. void get_move();        /* Gets a move from the player.        */
  69. void show_board();        /* Displays Othello Board.        */
  70. int make_move();        /* Make the move specified.        */
  71.  
  72.  
  73. init();                /* Initialise Othello.            */
  74.  
  75.  
  76. /* Main loop - repeats until end_othello takes a non-zero value
  77.  */
  78. while ( !end_othello )
  79.     {
  80.     /* Read in a move from the player.
  81.      *
  82.      * Note that the player's move, translated into coordinates in the
  83.      * Othello Board, is "returned" via pointers to (int)x and (int)y .
  84.      */
  85.     get_move ( &x, &y );
  86.  
  87.     /* The first thing we check is whether or not the player has quit,
  88.      * skipped a go or restarted the game. x is set to -1 to indicate
  89.      * the latter two options.
  90.      */
  91.     if ( !end_othello && x != -1 )
  92.         {
  93.         if ( make_move ( x, y ) )
  94.             {
  95.             /* Switch to next player if the move given was legal.
  96.              */
  97.             if ( player == 0 )
  98.                 player = 1;
  99.             else
  100.                 player = 0;
  101.  
  102.             /* Re-display the Othello Board.
  103.              */
  104.             show_board();
  105.             }
  106.         else
  107.             {
  108.             /* Move was illegal, so try again.
  109.              */
  110.             printf ( ": Illegal Move: Press a Key" );
  111.  
  112.             Bconin ( 2 );
  113.  
  114.             /* Back space over previous message, erase
  115.              * it and then backspace back again.
  116.              */
  117.             printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
  118.             printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
  119.             printf ( "                             " );
  120.             printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
  121.             printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
  122.             };
  123.         };
  124.     };
  125.  
  126.  
  127. /* Handle error codes.
  128.  */
  129. printf ( "\n\n%s\nPress a Key\n", errors[end_othello - 1] );
  130.  
  131. Bconin ( 2 );
  132.  
  133.  
  134. /* Free block of memory used by Othello Board if necessary.
  135.  */
  136. if ( board != NULL )
  137.     free ( board );
  138. };
  139.  
  140.  
  141. /*******************************************************************************
  142. get_move()        -    Get a move from the player.
  143.  
  144.                 Reads in two characters from the player,
  145.                 and translates them into coordinates in the
  146.                 Othello board. Those coordinates are then
  147.                 placed into two integers via the pointers
  148.                 (int *)x and (int *)y passed in.
  149. *******************************************************************************/
  150.  
  151. void get_move ( x, y )
  152. int *x, *y;
  153. {
  154. char c;                /* The character typed by the player.    */
  155. void show_board();        /* Displays Othello Board.        */
  156. void setup_board();        /* Set up Board for a new game.        */
  157.  
  158.  
  159. /* We first of all obtain a single character from the player,
  160.  * repeating this as many times as is necessary before we get a
  161.  * valid one.
  162.  */
  163. do    {
  164.     /* The ampersand (&) performs a bitwise AND operation.
  165.      * we use it here because we are only interested in the
  166.      * lower word of the value returned from Bconin(), as that
  167.      * word contains the ASCII code of the character typed.
  168.      */
  169.     c = (char)(Bconin ( 2 ) & 0x00FF);
  170.  
  171.     /* Convert a lower-case character into an upper-case one.
  172.      * Note the use of the -= operator, which subtracts the result of the
  173.      * right-hand side from the variable on the left, exactly as if we had
  174.      * used "c = c - ('a' - 'A');" Similarly, we can use other shorthand
  175.      * operators, such as +=, *=, /=, %=, etc, etc.
  176.      */
  177.     if ( c >= 'a' && c <= 'z' )
  178.         c -= 'a' - 'A';
  179.  
  180.     /* Note that valid characters are ''A' to 'H', 'Q', 'R' and ESC
  181.      */
  182.     }
  183.     while ( !((c >= 'A' || c <= 'H') ||
  184.         c == 'Q' || c == 'R' || c == '\x1B') );
  185.  
  186.  
  187. *y = c - 'A';
  188.  
  189. if ( c != '\x1B' )
  190.     putchar ( c );        /* Echo character to the screen        */
  191.  
  192.  
  193. /* We onlt bother to obtain the second character from the user if the first
  194.  * was a coordinate, rather than a command.
  195.  */
  196. if ( c >= 'A' && c <= 'H' )
  197.     {
  198.     /* Next we repeat the operation but we're looking for a digit
  199.      * from '1' to '8' this time.
  200.      */
  201.     do    {
  202.         c = (char)(Bconin ( 2 ) & 0x00FF);
  203.  
  204.         if ( c >= 'a' && c <= 'z' )
  205.             c -= 'a' - 'A';
  206.  
  207.         /* Valid characters are '1' to '8' and 'Q', 'R' or ESC
  208.          */
  209.         }
  210.         while ( (c < '1' || c > '8') &&
  211.             c != 'Q' && c != 'R' && c != 0x1B );
  212.  
  213.  
  214.     if ( c >= '1' && c <= '8' )
  215.         {
  216.         putchar ( c );        /* Echo character to the screen    */
  217.  
  218.         *x = c - '1';
  219.         };
  220.     };
  221.  
  222.  
  223. /* Handle commands given by the user.
  224.  */
  225. if ( c == 'Q' )                /* Quit program            */
  226.     end_othello = 3;
  227.  
  228. if ( c == 0x1B )            /* ESC pressed = skip a turn    */
  229.     {
  230.     /* Switch to next player.
  231.      */
  232.     if ( player == 0 )
  233.         player = 1;
  234.     else
  235.         player = 0;
  236.  
  237.     show_board();
  238.     };
  239.  
  240. if ( c == 'R' )                /* Restart (new game)        */
  241.     setup_board();
  242.  
  243. if ( c == 0x1B || c == 'R' )        /* Signal no move entered    */
  244.     *x = -1;
  245. };
  246.  
  247.  
  248. /*******************************************************************************
  249. show_board()        -    Displays the entire Othello Board.
  250.  
  251.                 Since we are using a memory block, and we no
  252.                 longer put EOS characters on the end of each
  253.                 line of the Board, this    function is now a
  254.                 little more complex than it was last month.
  255.  
  256.                 This function also now detects a Game Over.
  257. *******************************************************************************/
  258.  
  259. void show_board()
  260. {
  261. char thispiece;            /* A piece on the board.        */
  262. int x, y;            /* Offsets into the Board "array."    */
  263. int cnt0, cnt1;            /* Count of pieces owned by players.    */
  264. char get_piece();        /* Get value of specific piece.        */
  265. void setup_board();        /* Set up Board for a new game.        */
  266.  
  267.  
  268. /* Resets the count of pieces owned to zero.
  269.  * Note that every C expression has a value. The value of an assignment is
  270.  * the value assigned, thus the value of "cnt1 = 0;" is zero, which can
  271.  * iself be assigned to a variable, as happens here.
  272.  */
  273. cnt0 = cnt1 = 0;
  274.  
  275.  
  276. printf ( "%cE", 0x1B );        /* VT52 control code - clears the screen*/
  277.  
  278.  
  279. printf ( "  12345678\n  ________ \n" );
  280.  
  281. for ( y = 0; y < 8; y++ )
  282.     {
  283.     /* This first putchar() will ensure that the leftmost column of the
  284.      * Board will contain one of the letters 'A' to 'H', depending on
  285.      * the line. Note that a char is merely an 8-bit integer like any
  286.      * other integer. It only "becomes" an ASCII code when we use it as
  287.      * such.
  288.      */
  289.     putchar ( 'A' + y );
  290.     putchar ( '|' );
  291.  
  292.     for ( x = 0; x < 8; x++ )
  293.         {
  294.         thispiece = get_piece(x,y);
  295.  
  296.         /* putchar() returns -1 on errors, so we can test its value
  297.          * within the conditional, with no need for a separate
  298.          * statement or another variable.
  299.          */
  300.         if ( (putchar ( thispiece )) == - 1 )
  301.             {
  302.             end_othello = 2;
  303.  
  304.             return;        /* Exit function, but no return value */
  305.             };
  306.  
  307.         /* Update the count of pieces owned by each player.
  308.          *
  309.          * Note the use of "cnt0++", which increments (adds one to)
  310.          * the variable cnt0, exactly as if we had typed the expression
  311.          * "cnt0 = cnt0 + 1" or "x += 1". "cnt0++" is preferred here,
  312.          * though, not only because it saves typing, but it also
  313.          * allows the compiler to generate slightly more efficent code.
  314.          * Similarly, "cnt0--" would decrement (subtract one from) the
  315.          * variable cnt0.
  316.          */
  317.         if ( thispiece == piece[0] )
  318.             cnt0++;
  319.         else
  320.             {
  321.             if ( thispiece == piece[1] )
  322.                 cnt1++;
  323.             };
  324.         };
  325.  
  326.     putchar ( '|' );
  327.     putchar ( '\n' );        /* Output '\n' at end of line    */
  328.     };
  329.  
  330. printf ( "  ¯¯¯¯¯¯¯¯ \n\n" );
  331. printf ( "Score:\t%c: %d\t\t%c: %d\n", piece[0], cnt0, piece[1], cnt1 );
  332.  
  333.  
  334. /* Check to see if the game is over.
  335.  * This happens if all of the squares are filled or if either player has no
  336.  * pieces remaining on the board. A Game Over is also forced when neither
  337.  * player has any legal moves available, but we'll cover that next month
  338.  * when we add a computer player to the program.
  339.  */
  340. if ( (cnt0 + cnt1) == 64 || cnt0 == 0 || cnt1 == 0 )
  341.     {
  342.     printf ( "\nGame Over: " );
  343.  
  344.     if ( cnt0 == cnt1 )
  345.         printf ( "It was a draw" );
  346.     else
  347.         {
  348.         if ( cnt0 > cnt1 )
  349.             player = 0;
  350.         else
  351.             player = 1;
  352.  
  353.         printf ( "Player \'%c\' has won", piece[player] );
  354.         };
  355.  
  356.     printf ( ".\n\nPress a Key\n" );  /* Wait for a key press.    */
  357.     Bconin ( 2 );
  358.  
  359.     setup_board();            /* Set up board for new game.    */
  360.     }
  361. else
  362.     {
  363.     /* Game not over, so prompt user to enter a move.
  364.      */
  365.     printf ( "\n\nCommands available: " );
  366.     printf ( "Q (Quit), R (Restart), ESC (skip a go)\n\n");
  367.     printf ( "Type your move, player \'%c\' (e.g. A7): ", piece[player] );
  368.     };
  369. };
  370.  
  371.  
  372. /*******************************************************************************
  373. make_move()        -    Check the legality of placing a piece belonging
  374.                 to the current (int)player at square (int)x
  375.                 on line (int)y of the Othello Board.
  376.  
  377.                 If the move is legal, then perform it and
  378.                 return TRUE, otherwise return FALSE.
  379. *******************************************************************************/
  380.  
  381. int make_move ( x, y )
  382. int x, y;            /* Coordinates to place new piece.    */
  383. {
  384. int x_off;            /* x-offset from <x,y>            */
  385. int y_off;            /* y-offset from <x,y>            */
  386. int was_legal = FALSE;        /* Assume legal is illegal at first.    */
  387. int opposing();            /* Check if pieces is opponent's.    */
  388. int follow_trail();        /* Check if trail exists in some dirn.    */
  389. void flip_trail();        /* Flip all opponent's pieces in trail.    */
  390. void set_piece();        /* Set value of specific piece.        */
  391. char get_piece();        /* Get value of specific piece.        */
  392.  
  393.  
  394. /* If the proposed move is to a non-empty square then it is automatically
  395.  * illegal.
  396.  */
  397. if ( get_piece (x, y) != '.' )
  398.     return ( FALSE );
  399.  
  400.  
  401. /* We loop around all eight neighbours of the current piece.
  402.  *
  403.  * Note that there is no need in this instance to check whether the coordinates
  404.  * given are off the Board, as that is checked in the opposing() function.
  405.  */
  406. for ( y_off = -1; y_off < 2; y_off++ )
  407.     {
  408.     for ( x_off = -1; x_off < 2; x_off++ )
  409.         {
  410.         /* Don't include the current piece (the one a <x,y>) in this
  411.          * search.
  412.          */
  413.         if ( x_off != 0 || y_off != 0 )
  414.             {
  415.             if ( opposing ( x + x_off, y + y_off) )
  416.                 {
  417.                 /* We have found an adjacent piece which
  418.                  * belongs to the opponent.
  419.                  *
  420.                  * If we find a valid trail of pieces in this
  421.                  * direction then the move is valid, so return
  422.                  * TRUE. Otherwise continue checking other
  423.                  * directions.
  424.                  */
  425.                 if ( follow_trail (x, y, x_off, y_off) )
  426.                     {
  427.                     /* Having found a valid trail of pieces,
  428.                      * we execute the move by flipping any
  429.                      * opponent's pieces in the trail.
  430.                      */
  431.                     flip_trail (x, y, x_off, y_off);
  432.  
  433.                     /* Set the (int)was_legal flag to
  434.                      * indicate that this move is a legal
  435.                      * one.
  436.                      */
  437.                     was_legal = TRUE;
  438.                     };
  439.                 };
  440.             };
  441.         };
  442.     };
  443.  
  444. /* Return a flag indicating whether this move was a legal one.
  445.  */
  446. return ( was_legal );
  447. };
  448.  
  449.  
  450. /*******************************************************************************
  451. follow_trail()        -    Given a position on the Board (x, y), this
  452.                 function attempts to follow a trail of pieces
  453.                 in the direction specified.
  454.  
  455.                 If the trail consists of an unbroken line of
  456.                 pieces belonging to the opponent of the current
  457.                 (int)player followed by a piece belonging to
  458.                 the current (int)player then TRUE is returned,
  459.                 otherwise FALSE.
  460.  
  461.                 The direction is specified as a pair of offsets
  462.                 (int x_dirn and y_dirn) to be successively added
  463.                 to the <x,y> coordinates.
  464. *******************************************************************************/
  465.  
  466. int follow_trail ( x, y, x_dirn, y_dirn )
  467. int x, y;            /* Coordinates of start of trail.    */
  468. int x_dirn, y_dirn;        /* Direction of trail.            */
  469. {
  470. int opposing();            /* Check if piece belongs to opponent.    */
  471. char get_piece();        /* Get value of specific piece.        */
  472.  
  473.  
  474. /* Continue moving in the direction given by <x_dirn, y_dirn> until we reach
  475.  * a piece which does not belong to the opponent of the current (int)player.
  476.  *
  477.  * This is a do{}while loop since we must move one square in the required
  478.  * direction before we can make the first test.
  479.  */
  480. do    {
  481.     x += x_dirn;
  482.     y += y_dirn;
  483.     }
  484.     while ( opposing (x, y) );
  485.  
  486.  
  487. /* Check whether we have reached the edge of the Board.
  488.  * If so, this trail is not a good one, and so return FALSE.
  489.  */
  490. if ( x < 0 || x > 7 || y < 0 || y > 7 )
  491.     return ( FALSE );
  492.  
  493.  
  494. /* Check if the piece at the end of the trail is an empty square.
  495.  * If so, this trail is not a good one (it should end in a piece owned by the
  496.  * current (int)player), and so return FALSE. Else, return TRUE (trail valid).
  497.  */
  498. if ( get_piece (x, y) == '.' )
  499.     return ( FALSE );
  500. else
  501.     return ( TRUE );
  502. };
  503.  
  504.  
  505. /*******************************************************************************
  506. flip_trail()        -    Given a position on the Board (x, y), this
  507.                 function attempts to follow a trail of pieces
  508.                 in the direction specified.
  509.  
  510.                 A trail consists of an unbroken line of pieces
  511.                 belonging to the opponent of the current
  512.                 (int)player, followed by a piece belonging to
  513.                 the current (int)player.
  514.  
  515.                 Every one of the opponents pieces in the trail
  516.                 is flipped over to become a piece belonging to
  517.                 the current (int)player.
  518.  
  519.                 The direction is specified as a pair of offsets
  520.                 (int x_dirn and y_dirn) to be successively added
  521.                 to the <x,y> coordinates.
  522.  
  523.                 Finally, note that this function assumes that
  524.                 the trail to be flipped both exists and is a
  525.                 valid one, having been previously checked by
  526.                 follow_trail().
  527. *******************************************************************************/
  528.  
  529. void flip_trail ( x, y, x_dirn, y_dirn )
  530. int x, y;            /* Coordinates of start of trail.    */
  531. int x_dirn, y_dirn;        /* Direction of trail.            */
  532. {
  533. int opposing();            /* Check if piece belongs to opponent.    */
  534. void set_piece();        /* Set value of specific piece.        */
  535.  
  536.  
  537. /* Continue moving in the direction given by <x_dirn, y_dirn> until we reach
  538.  * a piece which does not belong to the opponent of the current (int)player,
  539.  * which marks the end of the trail.
  540.  *
  541.  * This is a do{}while loop since we must move one square in the required
  542.  * direction before we can make the first test.
  543.  */
  544. do    {
  545.     set_piece ( x, y, piece[player] );    /* Flip the piece    */
  546.  
  547.     x += x_dirn;
  548.     y += y_dirn;
  549.     }
  550.     while ( opposing (x, y) );
  551. };
  552.  
  553.  
  554. /*******************************************************************************
  555. opposing()    -    Takes as arguments the coordinates of a piece on the
  556.             Board ( int x, int y ).
  557.  
  558.             Returns TRUE if there is a piece at coordinates <x,y>
  559.             which does not belong to (int)player.
  560. *******************************************************************************/
  561.  
  562. int opposing ( x, y )
  563. int x, y;            /* Coordinates of piece to check.    */
  564. {
  565. char thispiece;            /* Holds piece at position <x,y>.    */
  566. char get_piece();        /* Get value of specific piece.        */
  567.  
  568.  
  569. /* If this piece is off the Board then return FALSE automatically.
  570.  */
  571. if ( x < 0 || x > 7 || y < 0 || y > 7 )
  572.     return ( FALSE );
  573.  
  574. thispiece = get_piece (x, y);        /* Get piece at position  <x,y>    */
  575.  
  576.  
  577. if ( thispiece != piece[player]  && thispiece != '.' )
  578.     return ( TRUE );
  579. else
  580.     return ( FALSE );
  581. };
  582.  
  583.  
  584. /*******************************************************************************
  585. init()        -    Initialises global variables.
  586. *******************************************************************************/
  587.  
  588. void init()
  589. {
  590. void setup_board();            /* Set up Board for a new game.    */
  591.  
  592.  
  593. /* The major variable is the Board itself. We use malloc() to obtain a block
  594.  * of memory 8*8 bytes long, room for an 8x8 Othello Board.
  595.  */
  596. board = (char *)malloc ( (long)(8 * 8) );
  597.  
  598. /* You should always check the value of the pointer returned from malloc()
  599.  */
  600. if ( board == NULL )
  601.     end_othello = 1;
  602. else
  603.     setup_board();
  604. };
  605.  
  606.  
  607. /*******************************************************************************
  608. setup_board()        -    Setups a blank Board ready for a new game.
  609. *******************************************************************************/
  610.  
  611. void setup_board()
  612. {
  613. int x;                /* Looping variable.            */
  614. void set_piece();        /* Set value of specific piece.        */
  615. void show_board();        /* Displays Othello Board.        */
  616.  
  617.  
  618. /* First move of the game goes to player zero.
  619.  */
  620. player = 0;
  621.  
  622. for ( x = 0; x < 64; x++ )
  623.     *(board + x) = '.';    /* An empty square is denoted by '.'    */
  624.  
  625.  
  626. /* Othello starts off with the central four pieces already on the Board.
  627.  */
  628. set_piece ( 3, 3, piece[0] );
  629. set_piece ( 3, 4, piece[1] );
  630. set_piece ( 4, 3, piece[1] );
  631. set_piece ( 4, 4, piece[0] );
  632.  
  633.  
  634. show_board();            /* Display the Othello Board        */
  635. };
  636.  
  637.  
  638. /*******************************************************************************
  639. get_piece()        -    Returns the value of the piece at position
  640.                 (int)x on line (int)y of the Board.
  641.  
  642.                 The value returned is a char (a member of the
  643.                 char piece[] array) indicating which player's
  644.                 piece is at this square, or '.' if the
  645.                 square is empty.
  646. *******************************************************************************/
  647.  
  648. char get_piece ( x, y )
  649. int x, y;            /* Coordinates of square to check.    */
  650. {
  651. /* Note the use off offsets with the (char *)board pointer to address an
  652.  * individual element of the memory block.
  653.  */
  654. return ( *(board + (8 * y) + x) );
  655. };
  656.  
  657.  
  658. /*******************************************************************************
  659. set_piece()        -    Actually change the piece at position (int)x on
  660.                 line (int)y of the Board to a new piece, given
  661.                 by (char)newpiece .
  662. *******************************************************************************/
  663.  
  664. void set_piece ( x, y, newpiece )
  665. int x, y;            /* Coordinates to place new piece.    */
  666. char newpiece;            /* New value of piece.            */
  667. {
  668. /* Change the Board to reflect the player's move.
  669.  */
  670. *(board + (8 * y) + x) = newpiece;
  671. };
  672.  
  673.  
  674. /* End of File OTHELLO2.C */
  675.