/***************************************************************************** * * * B l u e M o o n * * ================= * * V2.2 * * A patience game by T.A.Lister * * Integral screen support by Eric S. Raymond * * * *****************************************************************************/ /* * Compile this with the command `cc -O blue.c -lcurses -o blue'. For best * results, use the portable freeware ncurses(3) library. On non-Intel * machines, SVr4 curses is just as good. * * $Id: blue.c,v 1.15 1997/03/09 00:47:41 tom Exp $ */ #include #include #include #include #include #define NOCARD (-1) #define ACE 0 #define KING 12 #define SUIT_LENGTH 13 #define HEARTS 0 #define SPADES 1 #define DIAMONDS 2 #define CLUBS 3 #define NSUITS 4 #define GRID_WIDTH 14 /* 13+1 */ #define GRID_LENGTH 56 /* 4*(13+1) */ #define PACK_SIZE 52 #define BASEROW 1 #define PROMPTROW 11 #define RED_ON_WHITE 1 #define BLACK_ON_WHITE 2 #define BLUE_ON_WHITE 3 static RETSIGTYPE die(int onsig) GCC_NORETURN; static int deck_size = PACK_SIZE; /* initial deck */ static int deck[PACK_SIZE]; static int grid[GRID_LENGTH]; /* card layout grid */ static int freeptr[4]; /* free card space pointers */ static int deal_number=0; static chtype ranks[SUIT_LENGTH][2] = { {' ', 'A'}, {' ', '2'}, {' ', '3'}, {' ', '4'}, {' ', '5'}, {' ', '6'}, {' ', '7'}, {' ', '8'}, {' ', '9'}, {'1', '0'}, {' ', 'J'}, {' ', 'Q'}, {' ', 'K'} }; /* Please note, that this is a bad example. Color values should not be or'ed in. This only works, because the characters used here are plain and have no color attribute themselves. */ static chtype letters[4] = { #ifdef COLOR_PAIR 'h' | COLOR_PAIR(RED_ON_WHITE), /* hearts */ 's' | COLOR_PAIR(BLACK_ON_WHITE), /* spades */ 'd' | COLOR_PAIR(RED_ON_WHITE), /* diamonds */ 'c' | COLOR_PAIR(BLACK_ON_WHITE), /* clubs */ #endif }; #if defined(__i386__) static chtype glyphs[] = { #ifdef COLOR_PAIR '\003' | A_ALTCHARSET | COLOR_PAIR(RED_ON_WHITE), /* hearts */ '\006' | A_ALTCHARSET | COLOR_PAIR(BLACK_ON_WHITE), /* spades */ '\004' | A_ALTCHARSET | COLOR_PAIR(RED_ON_WHITE), /* diamonds */ '\005' | A_ALTCHARSET | COLOR_PAIR(BLACK_ON_WHITE), /* clubs */ #endif }; #endif /* __i386__ */ static chtype *suits = letters; /* this may change to glyphs below */ static RETSIGTYPE die(int onsig) { (void) signal(onsig, SIG_IGN); endwin(); exit(EXIT_SUCCESS); } static void init_vars(void) { int i; deck_size = PACK_SIZE; for (i=0; i < PACK_SIZE; i++) deck[i]=i; for (i = 0; i < 4; i++) freeptr[i]=i * GRID_WIDTH; } static void shuffle(int size) { int i,j,numswaps,swapnum,temp; numswaps=size*10; /* an arbitrary figure */ for (swapnum=0;swapnum=PACK_SIZE)) return(NOCARD); for(i = 0; i < GRID_LENGTH; i++) if (grid[i] == card) return i; return(NOCARD); } static void movecard(int src, int dst) { grid[dst]=grid[src]; grid[src]=NOCARD; move( BASEROW + (dst / GRID_WIDTH)*2+2, (dst % GRID_WIDTH)*5 + 1); printcard(grid[dst]); move( BASEROW + (src / GRID_WIDTH)*2+2, (src % GRID_WIDTH)*5 + 1); printcard(grid[src]); refresh(); } static void play_game(void) { int dead=0, i, j; char c; int selection[4], card; while (dead<4) { dead=0; for (i=0;i<4;i++) { card=grid[freeptr[i]-1]; if ( ((card % SUIT_LENGTH)==KING) || (card==NOCARD) ) selection[i]=NOCARD; else selection[i]=find(card+1); if (selection[i]==NOCARD) dead++; }; if (dead < 4) { char live[NSUITS+1], *lp = live; for (i=0;i<4;i++) { if (selection[i] != NOCARD) { move(BASEROW + (selection[i] / GRID_WIDTH)*2+3, (selection[i] % GRID_WIDTH)*5); (void)printw(" %c ", *lp++ = 'a' + i); } }; *lp = '\0'; if (strlen(live) == 1) { move(PROMPTROW,0); (void)printw( "Making forced moves... "); refresh(); (void) sleep(1); c = live[0]; } else { char buf[BUFSIZ]; (void)sprintf(buf, "Type [%s] to move, r to redraw, q or INTR to quit: ", live); do { move(PROMPTROW,0); (void) addstr(buf); move(PROMPTROW, (int)strlen(buf)); clrtoeol(); (void) addch(' '); } while (((c = getch())<'a' || c>'d') && (c!='r') && (c!='q')); } for (j = 0; j < 4; j++) if (selection[j]!=NOCARD) { move(BASEROW + (selection[j] / GRID_WIDTH)*2+3, (selection[j] % GRID_WIDTH)*5); (void)printw(" "); } if (c == 'r') display_cards(deal_number); else if (c == 'q') die(SIGINT); else { i = c-'a'; if (selection[i] == NOCARD) beep(); else { movecard(selection[i], freeptr[i]); freeptr[i]=selection[i]; } } } } move(PROMPTROW, 0); standout(); (void)printw("Finished deal %d - type any character to continue...", deal_number); standend(); (void) getch(); } static int collect_discards(void) { int row, col, cardno=0, finish, gridno; for (row=HEARTS;row<=CLUBS;row++) { finish=0; for (col=1;col