home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / languages / progs / curses / examples / c / battle next >
Encoding:
Text File  |  1992-02-28  |  13.8 KB  |  692 lines

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