home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 102_01 / othello.c < prev    next >
Text File  |  1984-02-12  |  14KB  |  614 lines

  1. /*
  2.     OTHELLO -- The Game of Dramatic Reversals
  3.  
  4.     written by Bert Halstead
  5.     modified for BDS C by Leor Zolman
  6.  
  7. *** Features added by Gilbert Shapiro:
  8.  
  9. (1) A view of the board after the player has moved but before the
  10. computer's response. (2) When player responds to "Move:" by <CR>,
  11. provides a list of available options on the screen. (3)
  12. Displays a board with "X" in all legal positions when player's move is
  13. illegal and numeric.  And (4) substitutes a reverse video * for @ as
  14. the white piece, if terminal is an H19.
  15.  
  16. The program uses #ifdef wherever required, so that the original
  17. OTHELLO can be reinstated by deleting or commenting out the line
  18. "#define H19."  All new functions are at the end of the file. The
  19. revised program works on an H89.  All screen formatting is performed
  20. by direct cursor addressing to ease portability. (Heath direct cursor
  21. addressing is "033Y" followed by an indication of the row and column.)
  22. The functions of other Heath screen manipulation commands are
  23. indicated in comments, to facilitate rewriting for other equipment.
  24. --GS  ***
  25.  
  26. This program is a good example of:
  27.     a) structured, heirarchical function organization
  28.     b) arrays as formal parameters
  29.     c) use of the "qsort" library function
  30.  
  31.    Object of the game is for two players to alternate
  32. placing their marker someplace on an 8 by 8 grid, so that
  33. at least one of the opponent's pieces becomes surrounded
  34. by the moving player's peices -- causing the flanked pieces
  35. to flip 'color' and belong to the moving player. After 60
  36. moves have been played (or if no player has a legal move left),
  37. the player with the most of his own pieces on the board wins.
  38.  
  39.    The playing pieces are '*' and '@'. You may choose to play
  40. either '*' or '@' for the first game; thereafter, you and the
  41. computer will alternate going first for each game. Whoever
  42. goes first always plays `*'.
  43.  
  44.    You enter a move as a two digit number, each digit being
  45. from 1 to 8, first digit representing row and second representing
  46. column. For example: if playing '*', your first move might be '46',
  47. meaning 4th row down, 6th position across.
  48.  
  49.    As an alternative to entering a move, one of the following
  50. commands may be typed:
  51.  
  52.     g    causes computer to play both sides until game
  53.         is over
  54.     a    causes computer to print out an analysis of
  55.         each of your possible moves. A letter from A
  56.         to Z will appear at each of your legal move
  57.         positions, where A is the machine's opinion
  58.         of an excellant move and Z is a real loser.
  59.     hn    sets handicap. n is 1,2,3, or 4. If n is
  60.         positive, gives n free pieces to the computer.
  61.         If n is negative, gives YOU the free peices.
  62.     f    forfeit the current move. This happens
  63.         automatically if you have no legal moves.
  64.     q    quit the current game.
  65.     b    prints out board again.
  66.     s    prints out the score, and tells who is winning.
  67. */
  68.  
  69. #define H19         /* GS -- Deletion of this line reverts program to 
  70.                original features. */
  71. #define BLACK '*'
  72. #define WHITE '@'
  73. #define EMPTY '-'
  74. int handicap;
  75. char selfplay;        /* true if computer playing with itself */
  76. int h[4][2];        /* handicap position table */
  77. char mine, his;        /* who has black (*) and white (@) in current game */
  78. char mefirst;        /* true if computer goes first in current game */
  79.  
  80. main(argc,argv)
  81. int argc;
  82. char **argv;
  83. {
  84.     char b[8][8];
  85.     int i;
  86.     h[0][0] = h[0][1] = h[2][0] = h[3][1] = 0;
  87.     h[1][0] = h[1][1] = h[2][1] = h[3][0] = 7;
  88.     printf("\nWelcome to the BDS C OTHELLO program!\n");
  89.     printf("\nNote: `*' always goes first...Good luck!!!\n\n");
  90.     srand1("Do you want to go first? ");
  91.     if (toupper(getchar()) == 'Y') 
  92.         mefirst = 0;
  93.     else
  94.         mefirst = 1;
  95.     printf("\n\n");
  96.     do {
  97.         clrbrd(b);
  98.         prtbrd(b);
  99.         i = game(b,4);
  100.         mefirst = !mefirst;
  101.         if (i==4) break;
  102.         if (i=='Q') continue;
  103.         printf("\n");
  104.         i = prtscr(b);
  105.         if (i>0) printf(" You won by %d\n",i);
  106.         else if (i<0) printf(" You lost by %d\n",-i);
  107.         else printf(" A draw\n");
  108.     } while (ask("Another game? ")=='Y');
  109. }
  110.  
  111. game(b,n)
  112. char b[8][8];
  113. int n;
  114. {
  115.     char c;
  116.     int ff;
  117.     int i,j;
  118.     handicap = 0;
  119.     selfplay = ' ';
  120.     ff=0;
  121.     if (mefirst) {
  122.         mine = BLACK; his = WHITE;
  123.         printf("\nI go first:\n\n");
  124.     }
  125.     else {
  126.         mine = WHITE; his = BLACK;
  127.         printf("\nYou go first:\n\n");
  128.     }
  129.     while(1) {
  130.         if (cntbrd(b,EMPTY)==0) return 'D';
  131.         if (cntbrd(b,EMPTY)==60 && mine == BLACK) goto Istart;
  132.         if (chkmvs(b,his)==0) {
  133.             printf(!mefirst ? "Forfeit" : "   ...Forfeit\n");
  134.             ff |= 1;
  135.             }
  136.         else switch (c = getmov(&i,&j)) {
  137.         case 'B': prtbrd(b); continue;
  138.         case 'S': i= prtscr(b);
  139.             if (i>0) printf(" You're winning\n");
  140.             else if (i<0)printf(" You're losing!\n");
  141.             else putchar('\n');
  142.             continue;
  143.         case 'Q': case 4: return c;
  144.         case 'H': if (n>abs(handicap)+4)
  145.                 printf("Illegal!\n");
  146.             else for (j=0; i!=0; j++) {
  147.              b[h[j][0]][h[j][1]]= i>0?BLACK:WHITE;
  148.              handicap += i>0 ? 1 : -1;
  149.              ++n;
  150.              i += i>0 ? -1 : 1;
  151.             }
  152.             prtbrd(b); continue;
  153.         case 'A': analyze(b,his,mine,EMPTY);
  154.             continue;
  155.         case 'G': my_mov(b,his,mine,EMPTY,&i,&j);
  156.         case 'M': if (chkmov(b,his,i,j)>0) {
  157.             printf(!mefirst ? "%1d-%1d" : "   ...%1d-%1d\n",
  158.                 i+1,j+1);
  159.             putmov(b,his,i,j);
  160. #ifdef H19
  161.             prtbrd_rt(b);        /* GS */
  162. #endif
  163.             }
  164.             else {
  165. #ifdef H19
  166.               displegl(b,his,mine,EMPTY);  /* GS */
  167. #else
  168.               printf("Illegal!\n");
  169. #endif
  170.               continue;
  171.              }
  172.             break;
  173.         case 'F': if (n>abs(handicap)+4) {
  174.             printf ("Illegal!\n");
  175.             continue;
  176.              }
  177.             else printf(!mefirst ? "Forfeit" :
  178.                          "   ...Forfeit\n");
  179.         }
  180. Istart:        if (cntbrd(b,EMPTY) == 0) return 'D';
  181.         if (chkmvs(b,mine)==0) {
  182.             printf(!mefirst ? "...Forfeit\n": "Forfeit...\n");
  183.             ff |=2;
  184.             }
  185.         else {
  186.             my_mov(b,mine,his,EMPTY,&i,&j);
  187.             printf(!mefirst ? "...%1d-%1d\n" : "%1d-%1d...\n",
  188.                 i+1,j+1);
  189.             putmov(b,mine,i,j);
  190.             ++n;
  191.             }
  192.         if (ff==3 || n>64) return 'D';
  193.         if (!(ff & 1)) prtbrd(b);
  194.         ff = 0;
  195.     }
  196. }
  197.  
  198. prtscr(b)
  199. char *b;
  200. {
  201.     int i,j;
  202.     printf("%1d-%1d",i = cntbrd(b,his), j=cntbrd(b,mine));
  203.     return i-j;
  204. }
  205.  
  206. char getmov(i,j)
  207. int *i, *j;
  208. {
  209.     char a,c;
  210.     int n;
  211.     char *p;
  212.     char skipbl();
  213.     if (selfplay == 'G') {
  214.         if (!kbhit()) return 'G';
  215.         selfplay = ' ';
  216.         getchar();
  217.     }
  218.     printf("Move: ");
  219.     while(1) switch (c=skipbl()) {
  220.         case '\n': printf("Move?  ");
  221. #ifdef H19
  222.             dispopts();        /* GS */
  223. #endif
  224.             continue;
  225.         case 'G': if ((c = skipbl()) != '\n')
  226.                 goto flush;
  227.             selfplay='G';
  228.             return 'G';
  229.         case 'B': case 'S': case 'Q':
  230.         case 'F': case 'A':
  231.           a=c;
  232.           if (( c = skipbl()) != '\n') goto flush;
  233.           return a;
  234.         case 'H': if ((a=c=skipbl()) == EMPTY)
  235.                 c=getchar();
  236.             if (c<'1' || c>'4' || skipbl() !='\n')
  237.                 goto flush;
  238.             *i = a==EMPTY? -(c-'0') : (c-'0');
  239.             return 'H';
  240.         case 4: return c;
  241.         default: if (c<'1' || c>'8') goto flush;
  242.             *i = c-'1';
  243.             c = skipbl();
  244.             if (c<'1' || c>'8') goto flush;
  245.             *j = c- '1';
  246.             if ((c=skipbl()) == '\n') return 'M';
  247.         flush:    while (c != '\n' && c != 4)
  248.                 c=getchar();
  249.             if (c==4) return c;
  250. #ifdef H19
  251.             dispopts();
  252. #else
  253.             printf("Huh?");
  254. #endif
  255.         }
  256. }
  257.  
  258. char ask(s)
  259. char *s;
  260. {
  261.     char a,c;
  262.     printf ("%s ",s);
  263.     a=skipbl();
  264.     while (c != '\n' && c != 4) c= getchar();
  265.     return a;
  266. }
  267.  
  268. char skipbl()
  269. {
  270.     char c;
  271.     while ((c = toupper(getchar())) == ' ' || c=='\t');
  272.     return c;
  273. }
  274.  
  275. chkmvs(b,p)
  276. char b[8][8];
  277. char p;
  278. {
  279.     int i,j,k;
  280.     k=0;
  281.     for (i=0; i<8; i++) for (j=0; j<8; j++)
  282.         k += chkmov(b,p,i,j);
  283.     return k;
  284. }
  285.  
  286. chkmov(b,p,x,y)
  287. char b[8][8],p;
  288. int x,y;
  289. {
  290.     if (b[x][y] != EMPTY) return 0;
  291.     return    chkmv1(b,p,x,y,0,1) + chkmv1(b,p,x,y,1,0) +
  292.         chkmv1(b,p,x,y,0,-1)+ chkmv1(b,p,x,y,-1,0)+
  293.         chkmv1(b,p,x,y,1,1) + chkmv1(b,p,x,y,1,-1)+
  294.         chkmv1(b,p,x,y,-1,1)+ chkmv1(b,p,x,y,-1,-1);
  295. }
  296.  
  297. chkmv1(b,p,x,y,m,n)
  298. char b[8][8],p;
  299. int x,y,m,n;
  300. {
  301.     int k;
  302.     k=0;
  303.     while ((x += m) >= 0 && x < 8 && (y += n) >= 0 && y<8)
  304.     {
  305.         if (b[x][y]==EMPTY) return 0;
  306.         if (b[x][y]== p ) return k;
  307.         if (x==0 || x==7 || y==0 || y==7)
  308.             k += 10;
  309.          else k++;
  310.     }
  311.     return 0;
  312. }
  313.  
  314. notake(b,p,o,e,x,y)
  315. char b[8][8];
  316. char p,o,e;
  317. int x,y;
  318. {
  319.     return notak1(b,p,o,e,x,y,0,1)&&
  320.         notak1(b,p,o,e,x,y,1,1)&&
  321.         notak1(b,p,o,e,x,y,1,0)&&
  322.         notak1(b,p,o,e,x,y,1,-1);
  323. }
  324.  
  325. notak1(b,p,o,e,x,y,m,n)
  326. char b[8][8],p,o,e;
  327. int x,y,m,n;
  328. {
  329.     int c1,c2;
  330.     c1 = notak2(b,p,o,e,x,y,m,n);
  331.     c2 = notak2(b,p,o,e,x,y,-m,-n);
  332.     return !(c1==o && c2==e || c1==e && c2==o);
  333. }
  334.  
  335. notak2(b,p,o,e,x,y,m,n)
  336. char b[8][8],p,o,e;
  337. int x,y,m,n;
  338. {
  339.     x += m; y +=n;
  340.     if (x>=0 && x<=7 && y>=0 && y<=7)
  341.         while(b[x][y] == 0) {
  342.          x += m; y+=n;
  343.          if (x<0 || x>7 || y<0 || y>7 || b[x][y]==e)
  344.             return o;
  345.          }
  346.     while (x>=0 && x<=7 && y>=0 && y<=7 && b[x][y]==p)
  347.             { x +=m; y+=n; }
  348.     if (x<0 || x>7 || y<0 || y>7) return p;
  349.     return b[x][y];
  350. }
  351.  
  352. putmov(b,p,x,y)
  353. char b[8][8];
  354. char p;
  355. int x,y;
  356. {
  357.     int i,j;
  358.     b[x][y] = p;
  359.     for (i= -1; i<=1; i++) for (j= -1; j<=1; j++) {
  360.         if ((i != 0 || j!=0)&&chkmv1(b,p,x,y,i,j)>0)
  361.             putmv1(b,p,x,y,i,j);
  362.      }
  363. }
  364.  
  365. putmv1(b,p,x,y,m,n)
  366. char b[8][8];
  367. char p;
  368. int x,y,m,n;
  369. {
  370.     while ((x += m) >= 0 && x<8 && (y += n)>=0 && y<8) {
  371.         if (b[x][y] == EMPTY || b[x][y] == p) return;
  372.         b[x][y] = p;
  373.      }
  374. }
  375.  
  376. struct mt {
  377.         int x;
  378.         int y;
  379.         int c;
  380.         int s;
  381.      };
  382. my_mov(b,p,o,e,m,n)
  383. char b[8][8],p;
  384. int *m, *n;
  385. {
  386.     struct mt  t[64];
  387.     int i,k;
  388.     int cmpmov();
  389.     k = fillmt(b,p,o,e,t);
  390.     if (!k) return 0;
  391.     qsort (&t, k, 8, &cmpmov);
  392.     for (i=1; i<k; i++)
  393.         if (t[i].s != t[0].s || t[i].c != t[0].c)
  394.                         break;
  395.     k = rand() % i;
  396.     *m = t[k].x;
  397.     *n = t[k].y;
  398.     return 1;
  399. }
  400.  
  401. analyze(b,p,o,e)
  402. char b[8][8], p,o,e;
  403. {
  404.     struct mt  t[64];
  405.     char a[8][8];
  406.     int i,k,c;
  407.     k = fillmt(b,p,o,e,t);
  408.     cpybrd(a,b);
  409.     for (i=0; i<k; i++)
  410.       a[t[i].x][t[i].y] = ((c = 'F' - t[i].s) <= 'Z')?c:'Z';
  411.     prtbrd(a);
  412. }
  413.  
  414. fillmt(b,p,o,e,t)
  415. char b[8][8],p,o,e;
  416. struct mt  t[64];
  417. {
  418.     int i,j,k;
  419.     k = 0;
  420.     for (i=0; i<8; i++) for(j=0; j<8; j++)
  421.        if (t[k].c = chkmov(b,p,i,j)) {
  422.             t[k].x =i;
  423.             t[k].y =j;
  424.             t[k].s = s_move(b,p,o,e,i,j);
  425.             ++k;
  426.         }
  427.     return k;
  428. }
  429.  
  430. s_move(b,p,o,e,i,j)
  431. char b[8][8], p, o, e;
  432. int i,j;
  433. {
  434.     char a[8][8];
  435.     int ok,s,k,l,side,oside;
  436.     int c,dkl;
  437.     cpybrd(a,b);
  438.     putmov(a,p,i,j);
  439.     side = 0;
  440.     if (i==0 || i==7) side++;
  441.     if (j==0 || j==7) side++;
  442.     s = 0;
  443.     ok = 0;
  444.     if (side==2 || notake(b,p,o,e,i,j)) ok++;
  445.     oside = 0;
  446.     for (k=0; k<8; k++) for(l=0; l<8; l++)
  447.      {
  448.         c=chkmov(a,o,k,l);
  449.         if (c==0) continue;
  450.         dkl = 1;
  451.         if (k==0 || k==7) { dkl+=2; oside|=4;}
  452.         if (l==0 || l==7) {dkl+=2; oside|=4; }
  453.         if (dkl==5) {dkl = 10; oside |= 16; }
  454.             else if (!notake(a,o,p,e,k,l))
  455.                     continue;
  456.         oside |= 1;
  457.         s -= dkl;
  458.         if (c>=10) { s -= 4; oside |= 8; }
  459.         }
  460.     if (s< -oside) s= -oside;
  461.     if (side>0) return s+side-7+10*ok;
  462.     if (i==1 || i==6) {s--; side++;}
  463.     if (j==1 || j==6) {s--; side++;}
  464.     if (side>0) return s;
  465.     if (i==2 || i==5) s++;
  466.     if (j==2 || j==5) s++;
  467.     return s;
  468. }
  469.  
  470. cmpmov(a,b)
  471. struct mt  *a, *b;
  472. {
  473.     if ((*a).s > (*b).s) return -1;
  474.     if ((*a).s < (*b).s) return 1;
  475.     if ((*a).c > (*b).c) return -1;
  476.     if ((*a).c < (*b).c) return 1;
  477.     return 0;
  478. }
  479.  
  480. clrbrd(b)
  481. char b[8][8];
  482. {
  483.     int i,j;
  484.     for (i=0; i<8; i++)
  485.         for (j=0; j<8; j++)
  486.             b[i][j]= EMPTY;
  487.     b[3][3] = b[4][4] = BLACK;
  488.     b[3][4] = b[4][3] = WHITE;
  489. }
  490.  
  491. prtbrd(b)
  492. char b[8][8];
  493. {
  494.     int i,j;
  495.     printf("   1 2 3 4 5 6 7 8\n");
  496.     for (i=0; i<8; i++) {
  497.         printf("%2d",i+1);
  498.         for (j=0; j<8; j++) {
  499.             putchar(' ');
  500.  
  501. #ifdef H19
  502.             if (b[i][j]=='@') printf("\033p*\033q");
  503.             else putchar(b[i][j]);
  504. #else
  505.             putchar(b[i][j]);
  506. #endif
  507.  
  508.          }
  509.         putchar('\n');
  510.      }
  511.     putchar('\n');
  512. }
  513.  
  514.  
  515.  
  516. cpybrd(a,b)
  517. char *a, *b;
  518. {
  519.     int i;
  520.     i=64;
  521.     while (i--)
  522.         *a++ = *b++;
  523. }
  524.  
  525. cntbrd(b,p)
  526. char *b, p;
  527. {
  528.     int i,j;
  529.     i= 64; j=0;
  530.     while (i--)
  531.         if (*b++ == p) ++j;
  532.     return (j);
  533. }
  534.  
  535. dispopts()        /* GS -- Displays options, after <CR>.  Works on H89.
  536.                 Uses only direct cursor addressing. */
  537.                 
  538. {    char row, col;
  539.     int i;
  540.     clrq3();
  541.     row = '\053';
  542.     printf("\033Y%c\107g:  Computer plays both sides\n",row++);
  543.     printf("\033Y%c\107a:  Analysis of your possible moves\n",row++);
  544.     printf("\033Y%c\107hn: Sets handicap\n",row++);
  545.     printf("\033Y%c\107f:  Forfeit current move\n",row++);
  546.     printf("\033Y%c\107q:  Quit current game\n",row++);
  547.     printf("\033Y%c\107b:  Print board again\n",row++);
  548.     printf("\033Y%c\107s:  Print score, tell who's winning\n",row++);
  549.     printf("\033Y\066\047");
  550. }
  551.  
  552. displegl(b,p,o,e)        /* GS --  For H89, Displays legal moves as X */
  553. char b[8][8], p,o,e;        /* Based on analyze() */
  554. {
  555.     struct mt  t[64];
  556.     char a[8][8];
  557.     int i,j,k,c;
  558.     k = fillmt(b,p,o,e,t);
  559.     cpybrd(a,b);
  560.     for (i=0; i<k; i++)
  561.         a[t[i].x][t[i].y] = ((c = 'F' - t[i].s) <= 'Z')?c:'Z';
  562.     for (i=1; i<=8; i++) for (j=1; j<=8; j++)
  563.         a[i][j] = (a[i][j] >= 'A' && a[i][j] <= 'Z') ? 'X' : a[i][j];
  564.     prtbrd_rt(a);
  565. }
  566.  
  567. clrq3()            /* GS -- Clears the lower right quadrant of screen */
  568. {
  569.     int i;
  570.     char row, col;
  571.     col = 71;    /* For H89, this is screen col. 40 */
  572.     printf("\033x5");    /* For H89, shuts off cursor. */
  573.     for (row=42; row<=55; row++) {     /* Screen rows 11 to 24 */
  574.             printf("\033Y%c%c", row, col);
  575.         for (i=1; i<=41; i++) putchar(' ');
  576.     }
  577.     printf("\033y5");    /* Turns on cursor */
  578. }
  579.  
  580. prtbrd_rt(b)        /* GS - prtbrd modified to print on the right
  581.                 half of the screen. */
  582. char b[8][8];
  583. {
  584.     char row, col;
  585.     int i,j;
  586.     clrq3();
  587.     row = '\053' - mefirst;
  588.     printf("\033Y%c\107   1 2 3 4 5 6 7 8\n",row);
  589.     for (i=0; i<8; i++) {
  590.         row = '\054' + i - mefirst;
  591.         printf("\033Y%c\107",row);
  592.         printf("%2d",i+1);
  593.         for (j=0; j<8; j++) {
  594.             putchar(' ');
  595.  
  596. #ifdef H19
  597.             if (b[i][j]=='@') printf("\033p*\033q");
  598.             else putchar(b[i][j]);
  599. #else
  600.             putchar(b[i][j]);
  601. #endif
  602.  
  603.          }
  604.      }
  605.     col = mefirst ? 32 : '\043';
  606.     printf("\033Y\066%c",col);
  607. }
  608.  
  609.  
  610. & a[i][j] <= 'Z') ? 'X' : a[i][j];
  611.     prtbrd_rt(a);
  612. }
  613.  
  614. clrq3()            /* GS -- Clears the lower right quadrant