home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume15 / accordian / part01 / accordian.c next >
C/C++ Source or Header  |  1993-01-27  |  13KB  |  720 lines

  1. /*
  2.  * accordian - the solitaire card game
  3.  *
  4.  * Author: Eric Lechner (ericl@xilinx.com)
  5.  * Originally written: Summer 1990
  6.  * Minor enhancements: March 1991 and November 1992
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <pwd.h>
  12. #include <time.h>
  13. #include <curses.h>
  14. #include <signal.h>
  15. #include "cards.h"
  16.  
  17. #define BADCARD        -1
  18. #define NOTINDECK    -2
  19. #define STUCK        -3
  20.  
  21. #define MOVE1    1
  22. #define MOVE3    2
  23.  
  24. #define WIN        1
  25. #define MOREMOVES    2
  26. #define LOSE        3
  27.  
  28. #define BUFFERLENGTH    256
  29.  
  30. int quit();
  31.  
  32. struct save {
  33.     int position;
  34.     int num_spaces;
  35. };
  36.  
  37. int save_nextcard, save_lastpile;
  38. int _face = 0, _suit = 0;
  39. int _msg[5];
  40. struct card deck[52];
  41. struct card save_deck[52];
  42. char buffer[256];
  43. struct save undo[52], save[52];
  44. int nummoves, save_moves;
  45.  
  46. /*
  47.  * main -- the main program loop
  48.  */
  49. main(argc,argv)
  50. int argc;
  51. char *argv[];
  52. {
  53.     int lastpile;    /* last exposed "pile" position in the deck */
  54.     int nextcard;    /* next "free" card in the deck */
  55.     int place;    /* place of card to move in the deck*/
  56.     int playing;
  57.     int lastlast, thislast;    /* last displayed card */
  58.     int i, ch, tmp, num;
  59.     int title;
  60.     FILE *fp, *pfp;
  61.     char *pager;
  62.  
  63.     if (argc > 1) {
  64.     pager = getenv("PAGER");
  65.     if (pager == NULL || *pager == '\0') pager = DEFAULT_PAGER;
  66.  
  67.     pfp = popen(pager, "w");
  68.     if (pfp == NULL) pfp = stdout;
  69.  
  70.     i = 0;
  71.     while (helplist[i] != 0)
  72.         fprintf(pfp, "%s\n",helplist[i++]);
  73.  
  74.     fp = fopen(ACCORDIAN_WINFILE, "r");
  75.     if (fp != NULL) {
  76.         fprintf(pfp, "\nAccordian winners:\n");
  77.         while ((ch = fgetc(fp)) != EOF) fputc(ch, pfp);
  78.         fclose(fp);
  79.     }
  80.     if (pfp != stdout) pclose(pfp);
  81.     exit(-1);
  82.     }
  83.  
  84.     SRANDOM(getpid());
  85.  
  86.     signal(SIGINT,quit);
  87.  
  88.     /* yap, if curses window couldn't be formed */
  89.     /* note: most curses implementations quit for you here */
  90.     if (initscr() == NULL) {
  91.     fprintf(stderr,"Couldn't initialize the screen.\n");
  92.     exit(-1);
  93.     }
  94.  
  95.     savetty();
  96.  
  97. StartOfGame:
  98.     title = FALSE;
  99.  
  100.     for (i=0; i<5; i++) _msg[i] = 0;
  101.  
  102.     for (i=0; i<52; i++) {
  103.     undo[i].position = 0;
  104.     undo[i].num_spaces = 0;
  105.     }
  106.     nummoves = 0;
  107.  
  108.     newdeck();
  109.     shuffle();
  110.  
  111.     lastpile = 0;
  112.     nextcard = 1;
  113.  
  114.     savedeck(lastpile,nextcard);
  115.  
  116.     clear();
  117.     cbreak();
  118.     noecho();
  119.  
  120.     playing = TRUE;
  121.  
  122.     lastlast = -1;
  123.     while (playing) {
  124.     thislast = lastpile;
  125.     if (lastlast != thislast) display(lastlast+1,lastpile);
  126.     if (!title) {
  127.         move(2,23);
  128.         printw("Accordian Solitaire - by Eric Lechner");
  129.         title = TRUE;
  130.     }
  131.     lastlast = thislast;
  132.     move(8,50);
  133.     if (lastpile == 51 || nextcard == 52)
  134.         printw("All cards have been dealt.");
  135.     else
  136.         printw("Cards left : %d",52 - nextcard);
  137.     clrtoeol();
  138.     move(11,50);
  139.     printw("Your move : ");
  140.     move(11,62);
  141.     clrtoeol();
  142.     refresh();
  143.     ch = getch();
  144.     printch(ch);
  145.     switch (ch) {
  146.         case 'D' :        /* deal the whole deck */
  147.         if (nextcard < 52) {
  148.             lastpile += 52 - nextcard;
  149.             nextcard = 52;
  150.             clearmsg();
  151.         } else {
  152.             putmsg("Out of cards.");
  153.         }
  154.         break;
  155.         case 'd' :        /* deal another card */
  156.         if (nextcard < 52) {
  157.             nextcard++;
  158.             lastpile++;
  159.             clearmsg();
  160.         } else {
  161.             putmsg("Out of cards.");
  162.         }
  163.         break;
  164.         case 0x12 :        /* redraw screen if a ^R or ^L */
  165.         case 0x1c:
  166.         clear();
  167.         display(0,lastpile);
  168.         title = FALSE;
  169.         for (i=0; i<5; i++) _msg[i] = 0;
  170.         break;
  171.         case 'x' :
  172.         case 'X' :
  173.         playing = FALSE;
  174.         break;
  175. #ifdef DEBUG
  176.         case 'l' :    /* kluge to test save_win() routine */
  177.         save_win();
  178.         break;
  179. #endif
  180.         case ' ' :
  181.         clearmsg();
  182.         break;
  183.         case '?' :
  184.         help();
  185.         clear();
  186.         display(0,lastpile);
  187.         title = FALSE;
  188.         for (i=0; i<5; i++) _msg[i] = 0;
  189.         break;
  190.         case 'r' :
  191.         case 'R' :
  192.         restoredeck(&lastpile,&nextcard);
  193.         display(1,lastpile);
  194.         if (lastpile < 51) undisplay(lastpile+1,51);
  195.         putmsg("Deck restored.");
  196.         break;
  197.         case 's' :
  198.         case 'S' :
  199.         savedeck(lastpile,nextcard);
  200.         putmsg("Deck saved.");
  201.         break;
  202.         case 'f' :
  203.         case 'F' :
  204.         find_move(lastpile);
  205.         break;
  206.         case 'u' :
  207.         case 'U' : /* undo a move here */
  208.         clearmsg();
  209.         if (--nummoves < 0) {
  210.             nummoves = 0;
  211.             putmsg("No moves to undo!");
  212.         } else {
  213.             for (i=51; i>undo[nummoves].position; i--) {
  214.                 swap(i,i-1);
  215.             }
  216.             swap(i,i - undo[nummoves].num_spaces);
  217.             lastpile++;
  218.             display( undo[nummoves].position - undo[nummoves].num_spaces, lastpile);
  219.         }
  220.         break;
  221.         case 'a' :
  222.         case 'A' :
  223.         case '1' :
  224.         case '2' :
  225.         case '3' :
  226.         case '4' :
  227.         case '5' :
  228.         case '6' :
  229.         case '7' :
  230.         case '8' :
  231.         case '9' :
  232.         case 'j' :
  233.         case 'J' :
  234.         case 'q' :
  235.         case 'Q' :
  236.         case 'k' :
  237.         case 'K' :
  238.         place = get_card(ch,lastpile);
  239.         switch (place) {
  240.             case BADCARD :
  241.             /* print "bad key" error message */
  242.             putmsg("Hit '?' for help.");
  243.             break;
  244.             case NOTINDECK :
  245.             /* print "not in deck" error message */
  246.             sprintf(buffer,"Couldn't find the %s of %s.",
  247.                 cardnames[_face], suitnames[_suit]);
  248.             putmsg(buffer);
  249.             break;
  250.             default:
  251.             /* choose move for card, if any */
  252.             switch (check(place)) {
  253.                 case MOVE1 :
  254.                 tmp = '1';
  255.                 break;
  256.                 case MOVE3 :
  257.                 tmp = '3';
  258.                 break;
  259.                 case (MOVE3 | MOVE1) :
  260.                 putmsg("Move 1 or 3 spaces");
  261.                 move(11,62);
  262.                 clrtoeol();
  263.                 refresh();
  264.                 tmp = getch();
  265.                 break;
  266.                 default :
  267.                 tmp = STUCK;
  268.                 break;
  269.             }
  270.             switch (tmp) {
  271.                 case '0' :
  272.                 clearmsg();
  273.                 break;
  274.                 case '1' :
  275.                 case '3' :
  276.                 num = tmp - '0';
  277.                 if (place < num) {
  278.                     sprintf(buffer,"Can't swap up %d.",num);
  279.                     putmsg(buffer);
  280.                     break;
  281.                 } else clearmsg();
  282.                 undo[nummoves].num_spaces = num;
  283.                 undo[nummoves].position = place;
  284.                 nummoves++;
  285.                 swap(place,place-num);
  286.                 for(i=place; i<51; i++)
  287.                     swap(i,i+1);
  288.                 lastpile--;
  289.                 display(place - num,lastpile);
  290.                 undisplay(lastpile + 1,lastpile + 1);
  291.                 switch(checkwin(lastpile,nextcard)) {
  292.                     case WIN :
  293.                     putmsg("You win! Congratulations!");
  294.                     playing = FALSE;
  295.                     save_win();
  296.                     break;
  297.                     case LOSE :
  298.                         putmsg("No more moves. You lose!");
  299.                         playing = FALSE;
  300.                         break;
  301.                     default :
  302.                     break;
  303.                 }
  304.                 break;
  305.                 case STUCK :
  306.                 sprintf(buffer,"The %s of %s cannot move!",
  307.                     cardnames[_face], suitnames[_suit]);
  308.                 putmsg(buffer);
  309.                 break;
  310.                 default :
  311.                 putmsg("Hit '?' for help.");
  312.                 break;
  313.             }
  314.         }
  315.         break;
  316.         default :
  317.         putmsg("Hit '?' for help.");
  318.         break;
  319.     }
  320.     }
  321.     move(20,50);
  322.     printw("Play again? [y/n] ");
  323. GetAnotherCh:
  324.     move(20,68);
  325.     refresh();
  326.     ch = getch();
  327.     switch (ch) {
  328.     case 'y' :
  329.     case 'Y' :
  330.         goto StartOfGame;
  331.     case 'n' :
  332.     case 'N' :
  333.     case 'x' :
  334.     case 'X' :
  335.     case 'q' :
  336.     case 'Q' :
  337.         break;
  338.     default:
  339.         goto GetAnotherCh;
  340.     }
  341.     move(20,0);
  342.     refresh();
  343.     resetty();
  344.     endwin();
  345. }
  346.  
  347. /*
  348.  * display -- print the deck onto the screen from position "start" to "end"
  349.  */
  350. display(start,end)
  351. int start, end;
  352. {
  353.     int i, hilite = NORMAL;
  354.  
  355.     for (i=start; i<=end; i++) {
  356.     move((i%13) + 5, (int) (i/13) * 10 + 10);
  357.     if (deck[i].face != 9) {
  358.         printw(" ");
  359.     }
  360.     switch (deck[i].suit) {
  361.         case CLUB :
  362.         case SPADE :
  363.         hilite = NORMAL;
  364.         break;
  365.         case HEART :
  366.         case DIAMOND :
  367.         standout();
  368.         hilite = REVERSE;
  369.         break;
  370.     }
  371.     printw("%s%s",cards[deck[i].face],suits[deck[i].suit]);
  372.     if (hilite == REVERSE) {
  373.         standend();
  374.         hilite = NORMAL;
  375.     }
  376.     if (!(i % 13) && i > 0) {
  377.         arrow(1,(int) i / 13);
  378.     }
  379.     }
  380. }
  381.  
  382. /*
  383.  * undisplay -- clear display from "place1" to "place2"
  384.  *              (useful for clearing off the end card)
  385.  */
  386. undisplay(place1,place2)
  387. int place1, place2;
  388. {
  389.     int i;
  390.  
  391.     for (i = place1; i <= place2; i++) {
  392.     move((i%13) + 5, (int) (i/13) * 10 + 10);
  393.     standend();
  394.     printw("   ");
  395.     standend();
  396.     if (!(i%13) && i > 0)
  397.         arrow(0,(int) i/13);
  398.     }
  399. }
  400.  
  401. /*
  402.  * arrow -- draw an arrow from one column to the preceding one
  403.  */
  404. arrow(on,row)
  405. int on,row;
  406. {
  407.     int i;
  408.     move(5, row * 10 + 6);
  409.     printw("%s",on ? "---" : "   ");
  410.     for(i=1;i<12;i++) {
  411.     move(5 + i, row * 10 + 6);
  412.     printw("%s",on ? "|" : " ");
  413.     }
  414.     move(17,row * 10 + 4);
  415.     printw("%s",on ? "<--" : "   ");
  416. }
  417.  
  418. /*
  419.  * get_card -- get a card as input from the user, face value, and suit.
  420.  */
  421. get_card(ch,lastpile)
  422. int ch, lastpile;
  423. {
  424.     int card, suit, i;
  425.  
  426.     /* get the card */
  427.     switch (ch) {
  428.     case 'a' :
  429.     case 'A' :
  430.         card = 0;
  431.         break;
  432.     case '2' :
  433.     case '3' :
  434.     case '4' :
  435.     case '5' :
  436.     case '6' :
  437.     case '7' :
  438.     case '8' :
  439.     case '9' :
  440.         card = ch - '1';
  441.         break;
  442.     case '1' :
  443.         if (getch() == '0') {
  444.         card = 9;
  445.         printch('0');
  446.         } else
  447.         return(BADCARD);
  448.         break;
  449.     case 'j' :
  450.     case 'J' :
  451.         card = 10;
  452.         break;
  453.     case 'q' :
  454.     case 'Q' :
  455.         card = 11;
  456.         break;
  457.     case 'k' :
  458.     case 'K' :
  459.         card = 12;
  460.         break;
  461.     default :
  462.         return (BADCARD);
  463.     }
  464.     _face = card;
  465.  
  466.     /* now get the suit */
  467.     switch(getch()) {
  468.     case 's' :
  469.     case 'S' :
  470.         suit = SPADE;
  471.         break;
  472.     case 'h' :
  473.     case 'H' :
  474.         suit = HEART;
  475.         break;
  476.     case 'c' :
  477.     case 'C' :
  478.         suit = CLUB;
  479.         break;
  480.     case 'd' :
  481.     case 'D' :
  482.         suit = DIAMOND;
  483.         break;
  484.     default :
  485.         return (BADCARD);
  486.     }
  487.     _suit = suit;
  488.  
  489.     /* now we've got the card.  find it in the deck */
  490.     i = 0;
  491.     do {
  492.     if (card == deck[i].face && suit == deck[i].suit)
  493.         return(i);
  494.     } while (++i <= lastpile);
  495.     return(NOTINDECK);
  496. }
  497.  
  498. /*
  499.  * check -- return if the card in postion "place" can move up the deck
  500.  */
  501. check(place)
  502. int place;
  503. {
  504.     int tmp = 0;
  505.  
  506.     if (place < 1)
  507.     return(tmp);
  508.  
  509.     if ((deck[place-1].face == deck[place].face) ||
  510.     (deck[place-1].suit == deck[place].suit)) {
  511.     tmp |= MOVE1;
  512.     }
  513.  
  514.     if (place < 3)
  515.     return(tmp);
  516.  
  517.     if ((deck[place-3].face == deck[place].face) ||
  518.     (deck[place-3].suit == deck[place].suit)) {
  519.     tmp |= MOVE3;
  520.     }
  521.     return(tmp);
  522. }
  523.  
  524. /*
  525.  * putmsg -- print a message to the message buffer space
  526.  */
  527. putmsg(buffer)
  528. char *buffer;
  529. {
  530.     int line = 0, pos, space, length;
  531.     char *text[5];
  532.     char tmpbuffer[BUFFERLENGTH];
  533.     char *msgbuffer;
  534.  
  535.     msgbuffer = tmpbuffer;
  536.  
  537.     strcpy(msgbuffer,buffer);
  538.  
  539.     while (line < 5) {
  540.     length = strlen(msgbuffer);
  541.     if (length >= 30) {
  542.         text[line] = msgbuffer;
  543.  
  544.         space = -1;
  545.         for (pos=0; pos<30; pos++) 
  546.         if (msgbuffer[pos] == ' ')
  547.             space = pos;
  548.  
  549.         if (space != -1)
  550.         msgbuffer[space] = '\0';
  551.         else
  552.         space = 30;
  553.  
  554.         msgbuffer += space + 1;
  555.     } else if (length != 0) {
  556.         text[line] = msgbuffer;
  557.         msgbuffer += length;
  558.     } else text[line] = 0;
  559.     line++;
  560.     }
  561.  
  562.     for (line=0; line<5; line++) {
  563.     if (_msg[line] || text[line] != 0)
  564.         move(14+line,50);
  565.  
  566.     if (_msg[line]) clrtoeol();
  567.  
  568.     if (text[line] != 0) {
  569.         printw("%s",text[line]);
  570.         _msg[line] = TRUE;
  571.     }
  572.     }
  573. }
  574.  
  575. /*
  576.  * clearmsg -- clear the message buffer space
  577.  */
  578. clearmsg()
  579. {
  580.     int i;
  581.  
  582.     for (i=0; i<5; i++) {
  583.     if (_msg[i]) {
  584.         move(14+i,50);
  585.         clrtoeol();
  586.         _msg[i] = FALSE;
  587.     }
  588.     }
  589. }
  590.  
  591. /*
  592.  * checkwin -- determine if the user has finished the game
  593.  */
  594. checkwin(lastpile,nextcard)
  595. int lastpile, nextcard;
  596. {
  597.     int i;
  598.  
  599.     if (nextcard != 52)
  600.     return(MOREMOVES);
  601.  
  602.     if (lastpile == 0)
  603.     return(WIN);
  604.  
  605.     for (i=0; i<=lastpile; i++)
  606.     if (check(i) != 0)
  607.         return(MOREMOVES);
  608.  
  609.     return(LOSE);
  610. }
  611.  
  612. /*
  613.  * find_move -- a "cheater" function, to find first available move
  614.  */
  615. find_move(lastpile)
  616. {
  617.     int i;
  618.     for (i=0; i<=lastpile; i++) {
  619.     if (check(i) != 0) {
  620.         sprintf(buffer,"The %s of %s can move.",
  621.         cardnames[deck[i].face],suitnames[deck[i].suit]);
  622.         putmsg(buffer);
  623.         return;
  624.     }
  625.     }
  626.     putmsg("Try dealing more cards.");
  627. }
  628.  
  629. /*
  630.  * quit -- the nice control-C handler
  631.  */
  632. quit()
  633. {
  634.     move(21,0);
  635.     refresh();
  636.     resetty();
  637.     endwin();
  638.  
  639.     exit(0);
  640. }
  641.  
  642. /*
  643.  * savedeck -- save the deck into the "save" deck
  644.  */
  645. savedeck(lastpile,nextcard)
  646. int lastpile, nextcard;
  647. {
  648.     int i;
  649.  
  650.     for (i=0; i<52; i++) {
  651.     save_deck[i].face = deck[i].face;
  652.     save_deck[i].suit = deck[i].suit;
  653.     save[i].num_spaces = undo[i].num_spaces;
  654.     save[i].position = undo[i].position;
  655.     }
  656.     save_lastpile = lastpile;
  657.     save_nextcard = nextcard;
  658.     save_moves = nummoves;
  659. }
  660.  
  661. /*
  662.  * restoredeck -- restore the deck from the previously saved deck
  663.  */
  664. restoredeck(lastpile,nextcard)
  665. int *lastpile, *nextcard;
  666. {
  667.     int i;
  668.  
  669.     for (i=0; i<52; i++) {
  670.     deck[i].face = save_deck[i].face;
  671.     deck[i].suit = save_deck[i].suit;
  672.     undo[i].position = save[i].position;
  673.     undo[i].num_spaces = save[i].num_spaces;
  674.     }
  675.     *lastpile = save_lastpile;
  676.     *nextcard = save_nextcard;
  677.     nummoves = save_moves;
  678. }
  679.  
  680. /*
  681.  * printch -- print a character to the screen, filtering out
  682.  *            all non-alphanumeric characters
  683.  */
  684. printch(ch)
  685. int ch;
  686. {
  687.     if ((ch >= 'a' && ch <= 'z') ||
  688.     (ch >= 'A' && ch <= 'Z') || 
  689.     (ch >= '0' && ch <= '9')) {
  690.     printw("%c",ch);
  691.     refresh();
  692.     }
  693. }
  694.  
  695. /*
  696.  * save_win -- save this win to the "win" file, for historical purposes
  697.  */
  698. save_win()
  699. {
  700.     time_t utime;
  701.     struct passwd *pw;
  702.     char *name;
  703.     FILE *fp;
  704.  
  705.     fp = fopen(ACCORDIAN_WINFILE,"a+");
  706.     if (!fp) return;
  707.  
  708.     time(&utime);
  709.     pw = getpwuid(getuid());
  710.     if (!pw)
  711.     name = "Someone with no name";
  712.     else
  713.     name = pw->pw_name;
  714.  
  715.     fprintf(fp,"%s won on %s",name,ctime(&utime));
  716.  
  717.     fclose(fp);
  718. }
  719.  
  720.