home *** CD-ROM | disk | FTP | other *** search
- /*
- * accordian - the solitaire card game
- *
- * Author: Eric Lechner (ericl@xilinx.com)
- * Originally written: Summer 1990
- * Minor enhancements: March 1991 and November 1992
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <pwd.h>
- #include <time.h>
- #include <curses.h>
- #include <signal.h>
- #include "cards.h"
-
- #define BADCARD -1
- #define NOTINDECK -2
- #define STUCK -3
-
- #define MOVE1 1
- #define MOVE3 2
-
- #define WIN 1
- #define MOREMOVES 2
- #define LOSE 3
-
- #define BUFFERLENGTH 256
-
- int quit();
-
- struct save {
- int position;
- int num_spaces;
- };
-
- int save_nextcard, save_lastpile;
- int _face = 0, _suit = 0;
- int _msg[5];
- struct card deck[52];
- struct card save_deck[52];
- char buffer[256];
- struct save undo[52], save[52];
- int nummoves, save_moves;
-
- /*
- * main -- the main program loop
- */
- main(argc,argv)
- int argc;
- char *argv[];
- {
- int lastpile; /* last exposed "pile" position in the deck */
- int nextcard; /* next "free" card in the deck */
- int place; /* place of card to move in the deck*/
- int playing;
- int lastlast, thislast; /* last displayed card */
- int i, ch, tmp, num;
- int title;
- FILE *fp, *pfp;
- char *pager;
-
- if (argc > 1) {
- pager = getenv("PAGER");
- if (pager == NULL || *pager == '\0') pager = DEFAULT_PAGER;
-
- pfp = popen(pager, "w");
- if (pfp == NULL) pfp = stdout;
-
- i = 0;
- while (helplist[i] != 0)
- fprintf(pfp, "%s\n",helplist[i++]);
-
- fp = fopen(ACCORDIAN_WINFILE, "r");
- if (fp != NULL) {
- fprintf(pfp, "\nAccordian winners:\n");
- while ((ch = fgetc(fp)) != EOF) fputc(ch, pfp);
- fclose(fp);
- }
- if (pfp != stdout) pclose(pfp);
- exit(-1);
- }
-
- SRANDOM(getpid());
-
- signal(SIGINT,quit);
-
- /* yap, if curses window couldn't be formed */
- /* note: most curses implementations quit for you here */
- if (initscr() == NULL) {
- fprintf(stderr,"Couldn't initialize the screen.\n");
- exit(-1);
- }
-
- savetty();
-
- StartOfGame:
- title = FALSE;
-
- for (i=0; i<5; i++) _msg[i] = 0;
-
- for (i=0; i<52; i++) {
- undo[i].position = 0;
- undo[i].num_spaces = 0;
- }
- nummoves = 0;
-
- newdeck();
- shuffle();
-
- lastpile = 0;
- nextcard = 1;
-
- savedeck(lastpile,nextcard);
-
- clear();
- cbreak();
- noecho();
-
- playing = TRUE;
-
- lastlast = -1;
- while (playing) {
- thislast = lastpile;
- if (lastlast != thislast) display(lastlast+1,lastpile);
- if (!title) {
- move(2,23);
- printw("Accordian Solitaire - by Eric Lechner");
- title = TRUE;
- }
- lastlast = thislast;
- move(8,50);
- if (lastpile == 51 || nextcard == 52)
- printw("All cards have been dealt.");
- else
- printw("Cards left : %d",52 - nextcard);
- clrtoeol();
- move(11,50);
- printw("Your move : ");
- move(11,62);
- clrtoeol();
- refresh();
- ch = getch();
- printch(ch);
- switch (ch) {
- case 'D' : /* deal the whole deck */
- if (nextcard < 52) {
- lastpile += 52 - nextcard;
- nextcard = 52;
- clearmsg();
- } else {
- putmsg("Out of cards.");
- }
- break;
- case 'd' : /* deal another card */
- if (nextcard < 52) {
- nextcard++;
- lastpile++;
- clearmsg();
- } else {
- putmsg("Out of cards.");
- }
- break;
- case 0x12 : /* redraw screen if a ^R or ^L */
- case 0x1c:
- clear();
- display(0,lastpile);
- title = FALSE;
- for (i=0; i<5; i++) _msg[i] = 0;
- break;
- case 'x' :
- case 'X' :
- playing = FALSE;
- break;
- #ifdef DEBUG
- case 'l' : /* kluge to test save_win() routine */
- save_win();
- break;
- #endif
- case ' ' :
- clearmsg();
- break;
- case '?' :
- help();
- clear();
- display(0,lastpile);
- title = FALSE;
- for (i=0; i<5; i++) _msg[i] = 0;
- break;
- case 'r' :
- case 'R' :
- restoredeck(&lastpile,&nextcard);
- display(1,lastpile);
- if (lastpile < 51) undisplay(lastpile+1,51);
- putmsg("Deck restored.");
- break;
- case 's' :
- case 'S' :
- savedeck(lastpile,nextcard);
- putmsg("Deck saved.");
- break;
- case 'f' :
- case 'F' :
- find_move(lastpile);
- break;
- case 'u' :
- case 'U' : /* undo a move here */
- clearmsg();
- if (--nummoves < 0) {
- nummoves = 0;
- putmsg("No moves to undo!");
- } else {
- for (i=51; i>undo[nummoves].position; i--) {
- swap(i,i-1);
- }
- swap(i,i - undo[nummoves].num_spaces);
- lastpile++;
- display( undo[nummoves].position - undo[nummoves].num_spaces, lastpile);
- }
- break;
- case 'a' :
- case 'A' :
- case '1' :
- case '2' :
- case '3' :
- case '4' :
- case '5' :
- case '6' :
- case '7' :
- case '8' :
- case '9' :
- case 'j' :
- case 'J' :
- case 'q' :
- case 'Q' :
- case 'k' :
- case 'K' :
- place = get_card(ch,lastpile);
- switch (place) {
- case BADCARD :
- /* print "bad key" error message */
- putmsg("Hit '?' for help.");
- break;
- case NOTINDECK :
- /* print "not in deck" error message */
- sprintf(buffer,"Couldn't find the %s of %s.",
- cardnames[_face], suitnames[_suit]);
- putmsg(buffer);
- break;
- default:
- /* choose move for card, if any */
- switch (check(place)) {
- case MOVE1 :
- tmp = '1';
- break;
- case MOVE3 :
- tmp = '3';
- break;
- case (MOVE3 | MOVE1) :
- putmsg("Move 1 or 3 spaces");
- move(11,62);
- clrtoeol();
- refresh();
- tmp = getch();
- break;
- default :
- tmp = STUCK;
- break;
- }
- switch (tmp) {
- case '0' :
- clearmsg();
- break;
- case '1' :
- case '3' :
- num = tmp - '0';
- if (place < num) {
- sprintf(buffer,"Can't swap up %d.",num);
- putmsg(buffer);
- break;
- } else clearmsg();
- undo[nummoves].num_spaces = num;
- undo[nummoves].position = place;
- nummoves++;
- swap(place,place-num);
- for(i=place; i<51; i++)
- swap(i,i+1);
- lastpile--;
- display(place - num,lastpile);
- undisplay(lastpile + 1,lastpile + 1);
- switch(checkwin(lastpile,nextcard)) {
- case WIN :
- putmsg("You win! Congratulations!");
- playing = FALSE;
- save_win();
- break;
- case LOSE :
- putmsg("No more moves. You lose!");
- playing = FALSE;
- break;
- default :
- break;
- }
- break;
- case STUCK :
- sprintf(buffer,"The %s of %s cannot move!",
- cardnames[_face], suitnames[_suit]);
- putmsg(buffer);
- break;
- default :
- putmsg("Hit '?' for help.");
- break;
- }
- }
- break;
- default :
- putmsg("Hit '?' for help.");
- break;
- }
- }
- move(20,50);
- printw("Play again? [y/n] ");
- GetAnotherCh:
- move(20,68);
- refresh();
- ch = getch();
- switch (ch) {
- case 'y' :
- case 'Y' :
- goto StartOfGame;
- case 'n' :
- case 'N' :
- case 'x' :
- case 'X' :
- case 'q' :
- case 'Q' :
- break;
- default:
- goto GetAnotherCh;
- }
- move(20,0);
- refresh();
- resetty();
- endwin();
- }
-
- /*
- * display -- print the deck onto the screen from position "start" to "end"
- */
- display(start,end)
- int start, end;
- {
- int i, hilite = NORMAL;
-
- for (i=start; i<=end; i++) {
- move((i%13) + 5, (int) (i/13) * 10 + 10);
- if (deck[i].face != 9) {
- printw(" ");
- }
- switch (deck[i].suit) {
- case CLUB :
- case SPADE :
- hilite = NORMAL;
- break;
- case HEART :
- case DIAMOND :
- standout();
- hilite = REVERSE;
- break;
- }
- printw("%s%s",cards[deck[i].face],suits[deck[i].suit]);
- if (hilite == REVERSE) {
- standend();
- hilite = NORMAL;
- }
- if (!(i % 13) && i > 0) {
- arrow(1,(int) i / 13);
- }
- }
- }
-
- /*
- * undisplay -- clear display from "place1" to "place2"
- * (useful for clearing off the end card)
- */
- undisplay(place1,place2)
- int place1, place2;
- {
- int i;
-
- for (i = place1; i <= place2; i++) {
- move((i%13) + 5, (int) (i/13) * 10 + 10);
- standend();
- printw(" ");
- standend();
- if (!(i%13) && i > 0)
- arrow(0,(int) i/13);
- }
- }
-
- /*
- * arrow -- draw an arrow from one column to the preceding one
- */
- arrow(on,row)
- int on,row;
- {
- int i;
- move(5, row * 10 + 6);
- printw("%s",on ? "---" : " ");
- for(i=1;i<12;i++) {
- move(5 + i, row * 10 + 6);
- printw("%s",on ? "|" : " ");
- }
- move(17,row * 10 + 4);
- printw("%s",on ? "<--" : " ");
- }
-
- /*
- * get_card -- get a card as input from the user, face value, and suit.
- */
- get_card(ch,lastpile)
- int ch, lastpile;
- {
- int card, suit, i;
-
- /* get the card */
- switch (ch) {
- case 'a' :
- case 'A' :
- card = 0;
- break;
- case '2' :
- case '3' :
- case '4' :
- case '5' :
- case '6' :
- case '7' :
- case '8' :
- case '9' :
- card = ch - '1';
- break;
- case '1' :
- if (getch() == '0') {
- card = 9;
- printch('0');
- } else
- return(BADCARD);
- break;
- case 'j' :
- case 'J' :
- card = 10;
- break;
- case 'q' :
- case 'Q' :
- card = 11;
- break;
- case 'k' :
- case 'K' :
- card = 12;
- break;
- default :
- return (BADCARD);
- }
- _face = card;
-
- /* now get the suit */
- switch(getch()) {
- case 's' :
- case 'S' :
- suit = SPADE;
- break;
- case 'h' :
- case 'H' :
- suit = HEART;
- break;
- case 'c' :
- case 'C' :
- suit = CLUB;
- break;
- case 'd' :
- case 'D' :
- suit = DIAMOND;
- break;
- default :
- return (BADCARD);
- }
- _suit = suit;
-
- /* now we've got the card. find it in the deck */
- i = 0;
- do {
- if (card == deck[i].face && suit == deck[i].suit)
- return(i);
- } while (++i <= lastpile);
- return(NOTINDECK);
- }
-
- /*
- * check -- return if the card in postion "place" can move up the deck
- */
- check(place)
- int place;
- {
- int tmp = 0;
-
- if (place < 1)
- return(tmp);
-
- if ((deck[place-1].face == deck[place].face) ||
- (deck[place-1].suit == deck[place].suit)) {
- tmp |= MOVE1;
- }
-
- if (place < 3)
- return(tmp);
-
- if ((deck[place-3].face == deck[place].face) ||
- (deck[place-3].suit == deck[place].suit)) {
- tmp |= MOVE3;
- }
- return(tmp);
- }
-
- /*
- * putmsg -- print a message to the message buffer space
- */
- putmsg(buffer)
- char *buffer;
- {
- int line = 0, pos, space, length;
- char *text[5];
- char tmpbuffer[BUFFERLENGTH];
- char *msgbuffer;
-
- msgbuffer = tmpbuffer;
-
- strcpy(msgbuffer,buffer);
-
- while (line < 5) {
- length = strlen(msgbuffer);
- if (length >= 30) {
- text[line] = msgbuffer;
-
- space = -1;
- for (pos=0; pos<30; pos++)
- if (msgbuffer[pos] == ' ')
- space = pos;
-
- if (space != -1)
- msgbuffer[space] = '\0';
- else
- space = 30;
-
- msgbuffer += space + 1;
- } else if (length != 0) {
- text[line] = msgbuffer;
- msgbuffer += length;
- } else text[line] = 0;
- line++;
- }
-
- for (line=0; line<5; line++) {
- if (_msg[line] || text[line] != 0)
- move(14+line,50);
-
- if (_msg[line]) clrtoeol();
-
- if (text[line] != 0) {
- printw("%s",text[line]);
- _msg[line] = TRUE;
- }
- }
- }
-
- /*
- * clearmsg -- clear the message buffer space
- */
- clearmsg()
- {
- int i;
-
- for (i=0; i<5; i++) {
- if (_msg[i]) {
- move(14+i,50);
- clrtoeol();
- _msg[i] = FALSE;
- }
- }
- }
-
- /*
- * checkwin -- determine if the user has finished the game
- */
- checkwin(lastpile,nextcard)
- int lastpile, nextcard;
- {
- int i;
-
- if (nextcard != 52)
- return(MOREMOVES);
-
- if (lastpile == 0)
- return(WIN);
-
- for (i=0; i<=lastpile; i++)
- if (check(i) != 0)
- return(MOREMOVES);
-
- return(LOSE);
- }
-
- /*
- * find_move -- a "cheater" function, to find first available move
- */
- find_move(lastpile)
- {
- int i;
- for (i=0; i<=lastpile; i++) {
- if (check(i) != 0) {
- sprintf(buffer,"The %s of %s can move.",
- cardnames[deck[i].face],suitnames[deck[i].suit]);
- putmsg(buffer);
- return;
- }
- }
- putmsg("Try dealing more cards.");
- }
-
- /*
- * quit -- the nice control-C handler
- */
- quit()
- {
- move(21,0);
- refresh();
- resetty();
- endwin();
-
- exit(0);
- }
-
- /*
- * savedeck -- save the deck into the "save" deck
- */
- savedeck(lastpile,nextcard)
- int lastpile, nextcard;
- {
- int i;
-
- for (i=0; i<52; i++) {
- save_deck[i].face = deck[i].face;
- save_deck[i].suit = deck[i].suit;
- save[i].num_spaces = undo[i].num_spaces;
- save[i].position = undo[i].position;
- }
- save_lastpile = lastpile;
- save_nextcard = nextcard;
- save_moves = nummoves;
- }
-
- /*
- * restoredeck -- restore the deck from the previously saved deck
- */
- restoredeck(lastpile,nextcard)
- int *lastpile, *nextcard;
- {
- int i;
-
- for (i=0; i<52; i++) {
- deck[i].face = save_deck[i].face;
- deck[i].suit = save_deck[i].suit;
- undo[i].position = save[i].position;
- undo[i].num_spaces = save[i].num_spaces;
- }
- *lastpile = save_lastpile;
- *nextcard = save_nextcard;
- nummoves = save_moves;
- }
-
- /*
- * printch -- print a character to the screen, filtering out
- * all non-alphanumeric characters
- */
- printch(ch)
- int ch;
- {
- if ((ch >= 'a' && ch <= 'z') ||
- (ch >= 'A' && ch <= 'Z') ||
- (ch >= '0' && ch <= '9')) {
- printw("%c",ch);
- refresh();
- }
- }
-
- /*
- * save_win -- save this win to the "win" file, for historical purposes
- */
- save_win()
- {
- time_t utime;
- struct passwd *pw;
- char *name;
- FILE *fp;
-
- fp = fopen(ACCORDIAN_WINFILE,"a+");
- if (!fp) return;
-
- time(&utime);
- pw = getpwuid(getuid());
- if (!pw)
- name = "Someone with no name";
- else
- name = pw->pw_name;
-
- fprintf(fp,"%s won on %s",name,ctime(&utime));
-
- fclose(fp);
- }
-
-