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