home *** CD-ROM | disk | FTP | other *** search
/ ftp.muug.mb.ca / 2014.06.ftp.muug.mb.ca.tar / ftp.muug.mb.ca / pub / src / linux / old-src / ncurses-1.8.5 / battle.c < prev    next >
C/C++ Source or Header  |  1993-11-27  |  14KB  |  705 lines

  1. /* 
  2.  * battle.c - original author: Bruce Holloway
  3.  *        mods by: Chuck A DeGaul
  4.  */
  5.  
  6. #include <unistd.h>
  7. #include <stdlib.h>
  8. #include <ctype.h>
  9. #include <ncurses.h>
  10. #include <signal.h>
  11.  
  12. #define    OTHER    1-turn
  13.  
  14. char numbers[] = "   0  1  2  3  4  5  6  7  8  9";
  15.  
  16. char carrier[] = "Aircraft Carrier";
  17. char battle[] = "Battleship";
  18. char sub[] = "Submarine";
  19. char destroy[] = "Destroyer";
  20. char ptboat[] = "PT Boat";
  21.  
  22. char name[40];
  23. char dftname[] = "Stranger";
  24.  
  25. struct _ships {
  26.     char *name;
  27.     char symbol;
  28.     char length;
  29.     char start;        /* Coordinates - 0,0=0; 10,10=100. */
  30.     char dir;        /* Direction - 0 = right; 1 = down. */
  31.     char hits;        /* How many times has this ship been hit? (-1==sunk) */
  32. };
  33.  
  34. struct _ships plyship[] = {
  35.     { carrier,'A',5,0,0,0 },
  36.     { battle,'B',4,0,0,0 },
  37.     { destroy,'D',3,0,0,0 },
  38.     { sub,'S',3,0,0,0 },
  39.     { ptboat,'P',2,0,0,0 },
  40. };
  41.  
  42. struct _ships cpuship[] = {
  43.     { carrier,'A',5,0,0,0 },
  44.     { battle,'B',4,0,0,0 },
  45.     { destroy,'D',3,0,0,0 },
  46.     { sub,'S',3,0,0,0 },
  47.     { ptboat,'P',2,0,0,0 },
  48. };
  49.  
  50. char hits[2][100], board[2][100];    /* "Hits" board, and main board. */
  51.  
  52. int srchstep;
  53. int cpuhits;
  54. int cstart, cdir;
  55. int plywon=0, cpuwon=0;            /* How many games has each won? */
  56. int turn;                /* 0=player, 1=computer */
  57. int huntoffs;                /* Offset on search strategy */
  58.  
  59. int salvo, blitz, ask, seemiss;        /* options */
  60.  
  61. void intro(void);
  62. void initgame(void);
  63. int rnd(int);
  64. void plyplace(struct _ships *);
  65. int getdir(void);
  66. void placeship(struct _ships *, int, int);
  67. int checkplace(struct _ships *, int, int);
  68. void error(char *);
  69. void prompt(void);
  70. char getcoord(void);
  71. void cpuplace(struct _ships *);
  72. int awinna(void);
  73. int plyturn(void);
  74. int hitship(int);
  75. int cputurn(void);
  76. int playagain(void);
  77. void uninitgame();
  78. int sgetc(char *);
  79. int do_options(int, char *[]);
  80. int scount(int);
  81.  
  82. int
  83. main(int argc, char **argv)
  84. {
  85.     do_options(argc, argv);
  86.  
  87.     intro();
  88.     do {
  89.     initgame();
  90.     while(awinna() == -1) {
  91.         if (!blitz) {
  92.         if (!salvo) {
  93.                 if(turn) cputurn(); else plyturn();
  94.         } else {
  95.              register int i;
  96.  
  97.              i = scount(turn);
  98.              while (i--) {
  99.              if (turn) {
  100.                  if (cputurn()) {
  101.                  if (awinna() != -1) {
  102.                      i = 0;
  103.                  }
  104.                  }
  105.              } else {
  106.                  if(plyturn()) {
  107.                  if (awinna() != -1) {
  108.                      i = 0;
  109.                  }
  110.                  }
  111.              }
  112.              }
  113.          } 
  114.         } else {
  115.             while((turn) ? cputurn() : plyturn());
  116.         }
  117.         turn = OTHER;
  118.     }
  119.     } while(playagain());
  120.     uninitgame();
  121. }
  122.  
  123. #define    PR    addstr
  124.  
  125. void
  126. intro()
  127. {
  128. char *tmpname;
  129.  
  130.     srand(time(0L));            /* Kick the random number generator */
  131.  
  132.     signal(SIGINT,uninitgame);
  133.     if(signal(SIGQUIT,SIG_IGN) != SIG_IGN) signal(SIGQUIT,uninitgame);
  134. #if 1
  135.     /* for some bizzare reason, getlogin or cuserid cause havoc with the terminal */
  136.     if ((tmpname = getlogin()) != NULL) {
  137.         strcpy(name, tmpname);
  138.     } else
  139. #endif
  140.     strcpy(name,dftname);
  141.     name[0] = toupper(name[0]);
  142.  
  143.     initscr();
  144.     savetty();
  145.     nonl(); 
  146.     cbreak(); 
  147.     noecho();
  148.     clear();
  149.     mvaddstr(4,29,"Welcome to Battleship!");
  150.     move(8,0);
  151. PR("                                                  \\\n");
  152. PR("                           \\                     \\ \\\n");
  153. PR("                          \\ \\                   \\ \\ \\_____________\n");
  154. PR("                         \\ \\ \\_____________      \\ \\/            |\n");
  155. PR("                          \\ \\/             \\      \\/             |\n");
  156. PR("                           \\/               \\_____/              |__\n");
  157. PR("           ________________/                                       |\n");
  158. PR("           \\  S.S. Penguin                                         |\n");
  159. PR("            \\                                                     /\n");
  160. PR("             \\___________________________________________________/\n");
  161.     mvaddstr(20,27,"Hit any key to continue..."); refresh();
  162.     getch();
  163. }
  164.  
  165. void
  166. initgame()
  167. {
  168. int i;
  169.  
  170.     clear();
  171.     mvaddstr(0,35,"BATTLESHIP");
  172.     mvaddstr(4,12,"Main Board");
  173.     mvaddstr(6,0,numbers);
  174.     move(7,0);
  175.     for(i=0; i<10; ++i){
  176.     printw("%c  .  .  .  .  .  .  .  .  .  .  %c\n",i+'A',i+'A');
  177.     }
  178.     mvaddstr(17,0,numbers);
  179.     mvaddstr(4,55,"Hit/Miss Board");
  180.     mvaddstr(6,45,numbers);
  181.     for(i=0; i<10; ++i){
  182.     mvprintw(7+i,45,"%c  .  .  .  .  .  .  .  .  .  .  %c",i+'A',i+'A');
  183.     }
  184.     mvaddstr(17,45,numbers);
  185.     for(turn=0; turn<2; ++turn)
  186.     for(i=0; i<100; ++i){
  187.         hits[turn][i] = board[turn][i] = 0;
  188.         }
  189.     for(turn=0; turn<2; ++turn){
  190.     for(i=0; i<5; ++i)
  191.         if(!turn) plyplace(&plyship[i]);
  192.         else cpuplace(&cpuship[i]);
  193.     }
  194.     turn = rnd(2);
  195.     cstart = cdir = -1;
  196.     cpuhits = 0;
  197.     srchstep = 3;
  198.     huntoffs = rnd(srchstep);
  199. }
  200.  
  201. int
  202. rnd(int n)
  203. {
  204.     return(((rand() & 0x7FFF) % n));
  205. }
  206.  
  207. void
  208. plyplace(ss)
  209. struct _ships *ss;
  210. {
  211.     int c, d;
  212.  
  213.     do {
  214.         prompt();
  215.         printw("Place your %s (ex.%c%d) ? ",ss->name,rnd(10)+'A',rnd(10));
  216.         c = getcoord();
  217.         d = getdir();
  218.     } while(!checkplace(ss,c,d));
  219.     placeship(ss,c,d);
  220. }
  221.  
  222. int 
  223. getdir()
  224. {
  225.  
  226.     prompt(); 
  227.     addstr("What direction (0=right, 1=down) ? ");
  228.     return(sgetc("01")-'0');
  229. }
  230.  
  231. void
  232. placeship(ss,c,d)
  233. struct _ships *ss;
  234. int c, d;
  235. {
  236. int x, y, l, i;
  237.  
  238.     for(l=0; l<ss->length; ++l){
  239.         i = c + l * ((d) ? 10 : 1);
  240.         board[turn][i] = ss->symbol;
  241.         x = (i % 10) * 3 + 3;
  242.         y = (i / 10) + 7;
  243.         if(!turn) mvaddch(y,x,ss->symbol);
  244.     }
  245.     ss->start = c;
  246.     ss->dir = d;
  247.     ss->hits = 0;
  248. }
  249.  
  250. int
  251. checkplace(ss,c,d)
  252. struct _ships *ss;
  253. int c, d;
  254. {
  255. int x, y, l;
  256.  
  257.     x = c%10; y = c/10;
  258.     if(((x+ss->length) > 10 && !d) || ((y+ss->length) > 10 && d==1)){
  259.     if(!turn)
  260.         switch(rnd(3)){
  261.         case 0:
  262.             error("Ship is hanging from the edge of the world");
  263.             break;
  264.         case 1:
  265.             error("Try fitting it on the board");
  266.             break;
  267.         case 2:
  268.             error("Figure I won't find it if you put it there?");
  269.             break;
  270.         }
  271.     return(0);
  272.     }
  273.     for(l=0; l<ss->length; ++l){
  274.     x = c + l * ((d) ? 10 : 1);
  275.     if(board[turn][x]){
  276.         if(!turn)
  277.         switch(rnd(3)){
  278.             case 0:
  279.             error("There's already a ship there");
  280.             break;
  281.             case 1:
  282.             error("Collision alert! Aaaaaagh!");
  283.             break;
  284.             case 2:
  285.             error("Er, Admiral, what about the other ship?");
  286.             break;
  287.             }
  288.         return(0);
  289.         }
  290.     }
  291.     return(1);
  292. }
  293.  
  294. void
  295. error(s)
  296. char *s;
  297. {
  298.     prompt(); 
  299.     beep();
  300.     printw("%s -- hit any key to continue --",s);
  301.     refresh();
  302.     getch();
  303. }
  304.  
  305. void
  306. prompt(){
  307.     move(22,0); 
  308.     clrtoeol();
  309. }
  310.  
  311. char
  312. getcoord()
  313. {
  314. int ch, x, y;
  315.  
  316. redo:
  317.     y = sgetc("ABCDEFGHIJ");
  318.     do {
  319.         ch = getch();
  320.         if (ch == 0x7F || ch == 8) {
  321.             addstr("\b \b"); 
  322.             refresh();
  323.             goto redo;
  324.         }
  325.     } while(ch < '0' || ch > '9');
  326.     addch(x = ch); 
  327.     refresh();
  328.     return((y-'A')*10+x-'0');
  329. }
  330.  
  331. void
  332. cpuplace(ss)
  333. struct _ships *ss;
  334. {
  335. int c, d;
  336.  
  337.     do{
  338.         c = rnd(100); 
  339.         d = rnd(2);
  340.     } while(!checkplace(ss,c,d));
  341.     placeship(ss,c,d);
  342. }
  343.  
  344. int
  345. awinna()
  346. {
  347. int i, j;
  348. struct _ships *ss;
  349.  
  350.     for (i = 0; i < 2; ++i) {
  351.         ss = (i) ? cpuship : plyship;
  352.         for(j=0; j<5; ++j, ++ss)
  353.             if(ss->length != ss->hits)
  354.                 break;
  355.         if(j == 5) return(OTHER);
  356.     }
  357.     return(-1);
  358. }
  359.  
  360. int
  361. plyturn()
  362. {
  363. int c, res;
  364. char *m;
  365.  
  366.     prompt();
  367.     addstr("Where do you want to shoot? ");
  368.     c = getcoord();
  369.     if(!(res = hits[turn][c])){
  370.     hits[turn][c] = res = (board[OTHER][c]) ? 'H' : 'M';
  371.     mvaddch(7+c/10,48+3*(c%10),(res=='H') ? 'H' : 'o');
  372.     if(c = hitship(c)){
  373.         prompt();
  374.         switch(rnd(3)){
  375.         case 0:
  376.             m = "You sank my %s!";
  377.             break;
  378.         case 1:
  379.             m = "I have this sinking feeling about my %s....";
  380.             break;
  381.         case 2:
  382.             m = "Have some mercy for my %s!";
  383.             break;
  384.         }
  385.         move(23,0); 
  386.         clrtoeol(); 
  387.         beep();
  388.         printw(m,cpuship[c-1].name); refresh();
  389.         return(awinna() == -1);
  390.         }
  391.     }
  392.     prompt();
  393.     move(23,0); clrtoeol();
  394.     printw("You %s.",(res=='M')?"missed":"scored a hit"); refresh();
  395.     return(res == 'H');
  396. }
  397.  
  398. int
  399. hitship(c)
  400. int c;
  401. {
  402. struct _ships *ss;
  403. int sym, i, j;
  404.  
  405.     ss = (turn) ? plyship : cpuship;
  406.     if (!(sym = board[OTHER][c])) return(0);
  407.     for (i = 0; i < 5; ++i, ++ss)
  408.     if (ss->symbol == sym) {
  409.         j = ss->hits; 
  410.         ++j; 
  411.         ss->hits = j;
  412.         if (j == ss->length) 
  413.             return(i+1);
  414.         return(0);
  415.      }
  416. }
  417.  
  418. int 
  419. cputurn()
  420. {
  421. int c, res, x, y, i, d;
  422.  
  423. redo:
  424.     if (cstart == -1){
  425.         if (cpuhits){
  426.             for(i=0, c=rnd(100); i<100; ++i, c = (c+1) % 100)
  427.             if(hits[turn][c] == 'H')
  428.                 break;
  429.             if(i != 100){
  430.                 cstart = c;
  431.                 cdir = -1;
  432.                 goto fndir;
  433.             }
  434.         }
  435.         do {
  436.             i = 0;
  437.             do{
  438.                 while(hits[turn][c=rnd(100)]);
  439.                 x = c % 10; y = c / 10;
  440.                 if(++i == 1000) break;
  441.             } while(((x+huntoffs) % srchstep) != (y % srchstep));
  442.             if(i == 1000) --srchstep;
  443.         } while(i == 1000);
  444.     }
  445.     else if(cdir == -1){
  446. fndir:    for(i=0, d=rnd(4); i++ < 4; d = (d+1) % 4){
  447.             x = cstart%10; y = cstart/10;
  448.             switch(d){
  449.                 case 0: ++x; break;
  450.                 case 1: ++y; break;
  451.                 case 2: --x; break;
  452.                 case 3: --y; break;
  453.             }
  454.             if(x<0 || x>9 || y<0 || y>9) continue;
  455.             if(hits[turn][c=y*10+x]) continue;
  456.             cdir = -2;
  457.             break;
  458.         }
  459.         if(i == 4){
  460.             cstart = -1;
  461.             goto redo;
  462.         }
  463.     }
  464.     else{
  465.         x = cstart%10; y = cstart/10;
  466.         switch(cdir){
  467.             case 0: ++x; break;
  468.             case 1: ++y; break;
  469.             case 2: --x; break;
  470.             case 3: --y; break;
  471.         }
  472.         if(x<0 || x>9 || y<0 || y>9 || hits[turn][y*10+x]){
  473.             cdir = (cdir+2) % 4;
  474.             for(;;){
  475.                 switch(cdir){
  476.                     case 0: ++x; break;
  477.                     case 1: ++y; break;
  478.                     case 2: --x; break;
  479.                     case 3: --y; break;
  480.                 }
  481.                 if(x<0 || x>9 || y<0 || y>9){ cstart = -1; 
  482.                 goto redo; 
  483.             }
  484.             if(!hits[turn][y*10+x]) break;
  485.         }
  486.     }
  487.     c = y*10 + x;
  488.     }
  489.  
  490.     if (!ask) {
  491.         res = (board[OTHER][c]) ? 'H' : 'M';
  492.         move(21,0); clrtoeol();
  493.         printw("I shoot at %c%d. I %s!",c/10+'A',c%10,(res=='H')?"hit":"miss");
  494.     } else {
  495.         for(;;){
  496.         prompt();
  497.         printw("I shoot at %c%d. Do I (H)it or (M)iss? ",c/10+'A',c%10);
  498.         res = sgetc("HM");
  499.         if((res=='H' && !board[OTHER][c]) || (res=='M' && board[OTHER][c])){
  500.             error("You lie!");
  501.             continue;
  502.             }
  503.         break;
  504.         }
  505.         addch(res);
  506.     }
  507.     hits[turn][c] = res;
  508.     if(res == 'H') {
  509.     ++cpuhits;
  510.     if(cstart == -1) cdir = -1;
  511.     cstart = c;
  512.     if(cdir == -2) cdir = d;
  513.     mvaddch(7+(c/10),3+3*(c%10),'*');
  514.     if (blitz && !ask) {
  515.         refresh();
  516.         sleep(1);
  517.     }
  518.     }
  519.     else { 
  520.     if (seemiss) {
  521.         mvaddch(7+(c/10),3+3*(c%10),' ');
  522.     } else {
  523.         if(cdir == -2) cdir = -1;
  524.     }
  525.     }
  526.     if(c=hitship(c)){
  527.     cstart = -1;
  528.     cpuhits -= plyship[c-1].length;
  529.     x = plyship[c-1].start;
  530.     d = plyship[c-1].dir;
  531.     y = plyship[c-1].length;
  532.     for(i=0; i<y; ++i){
  533.         hits[turn][x] = '*';
  534.         x += (d) ? 10 : 1;
  535.         }
  536.     }
  537.     if (salvo && !ask) {
  538.     refresh();
  539.     sleep(1);
  540.     }
  541.     if(awinna() != -1) return(0);
  542.     return(res == 'H');
  543. }
  544.  
  545. int
  546. playagain()
  547. {
  548. int i, x, y, dx, dy, j;
  549.  
  550.     for(i=0; i<5; ++i){
  551.     x = cpuship[i].start; y = x/10+7; x = (x % 10) * 3 + 48;
  552.     dx = (cpuship[i].dir) ? 0 : 3;
  553.     dy = (cpuship[i].dir) ? 1 : 0;
  554.     for(j=0; j < cpuship[i].length; ++j){
  555.         mvaddch(y,x,cpuship[i].symbol);
  556.         x += dx; y += dy;
  557.         }
  558.     }
  559.  
  560.     if(awinna()) ++cpuwon; else ++plywon;
  561.     i = 18 + strlen(name);
  562.     if(plywon >= 10) ++i;
  563.     if(cpuwon >= 10) ++i;
  564.     mvprintw(2,(80-i)/2,"%s: %d     Computer: %d",name,plywon,cpuwon);
  565.  
  566.     prompt();
  567.     printw((awinna()) ? "Want to be humiliated again, %s? "
  568.           : "Going to give me a chance for revenge, %s? ",name);
  569.     return(sgetc("YN") == 'Y');
  570. }
  571.  
  572. void
  573. uninitgame(int sig)
  574. {
  575.     refresh();
  576.     endwin();
  577.     exit(0);
  578. }
  579.  
  580. int
  581. sgetc(s)
  582. char *s;
  583. {
  584. char *s1;
  585. int ch;
  586.  
  587.     refresh();
  588.     for (;;) {
  589.         ch = toupper(getch());
  590.         for (s1 = s; *s1 && ch != *s1; ++s1);
  591.         if (*s1) {
  592.             addch(ch); 
  593.             refresh();
  594.             return(ch);
  595.         }
  596.     }
  597. }
  598.  
  599. /* 
  600.  * I should use getopts() from libc.a, but I'm leary that other UNIX
  601.  * systems might not have it, although I'd love to use it.
  602.  */
  603.  
  604. int
  605. do_options(c,op)
  606. int c;
  607. char *op[];
  608. {
  609. register int i;
  610.  
  611.     if (c > 1) {
  612.         for (i=1; i<c; i++) {
  613.             switch(op[i][0]) {
  614.             default:
  615.             case '?':
  616.             fprintf(stderr, "Usage: battle [ -s | -b ] [ -a ] [ -m ]\n");
  617.             fprintf(stderr, "\tWhere the options are:\n");
  618.             fprintf(stderr, "\t-s : play a salvo game (mutex with -b)\n");
  619.             fprintf(stderr, "\t-b : play a blitz game (mutex with -s)\n");
  620.             fprintf(stderr, "\t-a : computer asks you for hit/miss\n");
  621.             fprintf(stderr, "\t-m : computer misses are displayed\n");
  622.             exit(1);
  623.             break;
  624.             case '-':
  625.             switch(op[i][1]) {
  626.             case 'b':
  627.                 blitz = 1;
  628.                 if (salvo == 1) {
  629.                 fprintf(stderr,
  630.                     "Bad Arg: -b and -s are mutually exclusive\n");
  631.                 exit(1);
  632.                 }
  633.                 break;
  634.             case 's':
  635.                 salvo = 1;
  636.                 if (blitz == 1) {
  637.                 fprintf(stderr,
  638.                     "Bad Arg: -s and -b are mutually exclusive\n");
  639.                 exit(1);
  640.                 }
  641.                 break;
  642.             case 'a':
  643.                 ask = 1;
  644.                 break;
  645.             case 'm':
  646.                 seemiss = 1;
  647.                 break;
  648.             default:
  649.                 fprintf(stderr,
  650.                 "Bad Arg: type \"%s ?\" for usage message\n", op[0]);
  651.                 exit(1);
  652.             }
  653.                }
  654.         }
  655.         fprintf(stdout, "Playing optional game (");
  656.         if (salvo) 
  657.             fprintf(stdout, "salvo, noblitz, ");
  658.         else if (blitz)
  659.                 fprintf(stdout, "blitz, nosalvo, ");
  660.             else 
  661.                 fprintf(stdout, "noblitz, nosalvo, ");
  662.  
  663.         if (ask) 
  664.             fprintf(stdout, "ask, ");
  665.         else 
  666.             fprintf(stdout, "noask, ");
  667.  
  668.         if (seemiss) 
  669.             fprintf(stdout, "seemiss)\n");
  670.         else 
  671.             fprintf(stdout, "noseemiss)\n");
  672.     }    
  673.     else
  674.     fprintf(stdout,
  675.         "Playing standard game (no blitz, no slavo, no ask, no seemiss)\n");
  676.     sleep(2);
  677.     return(0);
  678. }
  679.  
  680. int
  681. scount(who)
  682. int who;
  683. {
  684. int i, shots;
  685. struct _ships *sp;
  686.  
  687.     if (who) {
  688.     /* count cpu shots */
  689.     sp = cpuship;
  690.     } else {
  691.     /* count player shots */
  692.     sp = plyship;
  693.     }
  694.     for (i=0, shots = 0; i<5; i++, sp++) {
  695.     /* extra test for machines with unsigned chars! */
  696.     if (sp->hits == (char) -1 || sp->hits >= sp->length) {
  697.         continue;    /* dead ship */
  698.     } else {
  699.         shots++;
  700.     }
  701.     }
  702.     return(shots);
  703. }
  704.  
  705.