home *** CD-ROM | disk | FTP | other *** search
- /* MIKEY: notes, todo */
-
- /* shooting scoring messed up */
- /* improve passing */
- /* keep high cards for jd trick at end? only if don't have jd */
- /* => take all tricks for jd at end if qs gone */
- /* computer shoot attempt? */
- /* jdvoided */
-
- /*
- * dealer - more commonly known as heartsd
- *
- * Smarts of hearts program. Runs in background when invoked by initial
- * caller of hearts. Contains all logic for communicating with other
- * hearts players. Handles all computer players, and communicates play
- * of others to other players.
- *
- * JD variant addition and strategy mods by:
- * Mike Yang of Silicon Graphics (mikey@sgi.com)
- *
- * Computer strategy originally written in Pascal by:
- * Don Baccus of Oregon Software.
- * Strategy mods by:
- * Jeff Hemmerling of Test Systems Strategies, Inc.
- *
- * Converted strategy to C, added curses and multi-player (sockets)
- * interface by:
- * Bob Ankeney of Generic Computer Products
- *
- * Thanks to Keith Packard, for his invaluable (is that the same as
- * unvaluable?) assistance as a unix guru, for design suggestions, and
- * (I suppose) for convincing me to rewrite the bloody thing.
- *
- * Bug reports to Bob Ankeney at:
- * ...!tektronix!reed!bob
- *
- */
- /*
- * MODIFICATION HISTORY
- *
- * S001 rr@sco.com 14 May 93
- * - Use lrand48() and srand48() rather than random() and srandom().
- * Also use time(0) rather than getpid() for the random seed.
- */
-
- #include "misc.h"
- #include "defs.h"
- #include "local.h"
- #include <sys/resource.h>
-
- /* #define DEBUG uncomment to enable play logging */
-
- #define BUF_SIZE 64
- #define FUNNY_FACTOR 2
- #define NPASS 3 /* # cards to pass */
- #define PLAYERS 4 /* # players total */
- #define NCARDS (52 / PLAYERS)
-
- #define ACE 13
- #define KING 12
- #define QUEEN 11
- #define JACK 10
-
- #define HEARTS_PANIC 4
-
- #define PANIC_RATIO 0.85
-
- #define COMPUTER 1
- #define HUMAN 2
- #define VOYEUR 3
-
- int debug = 0;
-
- int num_humans, /* # HUMAN players */
- human_type, /* HUMAN or VOYEUR */
- player_mask; /* Bit n+1 is set for each human player n */
-
- char someone_is_shooting,
- queen_played,
- jack_played;
-
- typedef struct node *ptr;
-
- struct card {
- int suit, rank;
- };
-
- struct node {
- ptr llink, rlink;
- int rank;
- };
-
- struct suit_list {
- ptr head, tail;
- int length;
- };
-
- typedef struct suit_list card_hand[MAX_SUIT + 1];
-
- struct player_status {
- card_hand cards;
- int pts, totalpts;
- int passer;
- struct card passed_cards[NPASS + 1];
- int num_passed;
- int player_kind;
- int socket;
- char name[9];
- };
-
- struct player_status card_table[PLAYERS + 1];
-
- card_hand cards_played;
-
- struct card deck[53];
-
- struct sockaddr_in sockaddr;
-
-
- int player_count, leader,
- round, hand,
- points_played;
-
- int mikeyshooter,MIKEYJder,MIKEYJdintrick;
-
- int privatemsgs = 1;
-
- int voided[MAX_SUIT+1][PLAYERS+1], hasqs[PLAYERS+1][PLAYERS+1];
- /* FALSE: No info, assume not
- TRUE: Yes
- MAYBE: Maybe, based on play */
- #define MAYBE 2
- #define NONE 666
-
- FILE *fp;
-
- char hearts_broken;
-
- struct {
- int card_count, highest_played, high_player, suit_led, pts;
- char any_hearts;
- struct card played[PLAYERS + 1];
- } trick;
-
- char *snames[] = {
- "",
- "clubs",
- "diamonds",
- "hearts",
- "spades"
- },
- rnames[] = " 23456789TJQKA",
- *comp_names[] = {
- "",
- "zeppo",
- "chico",
- "harpo",
- "groucho"
- };
-
- #define map_player(leader, player) (((leader + player - 1) % PLAYERS) + 1)
-
- #define queen_safe(player) (queen_played || (find_true(hasqs[player]) == FALSE))
-
- #define safe_suit(suit) ((suit != HEARTS) && (find_true(voided[suit]) == FALSE))
-
- #define highest(player, suit) (card_table[player].cards[suit].head->rlink)
-
- #define lowest(player, suit) (card_table[player].cards[suit].tail->llink)
-
- #define cards_out(suit) (MAX_RANK - cards_played[suit].length)
-
- #define spades_safe(player) (( (float) (cards_out(SPADES) - \
- card_table[player].cards[SPADES].length) / (PLAYERS - 1.0) >= 2.3) && \
- safe_suit(SPADES))
-
- #define diamonds_safe(player) (( (float) (cards_out(DIAMONDS) - \
- card_table[player].cards[DIAMONDS].length) / (PLAYERS - 1.0) >= 2.3) && \
- safe_suit(DIAMONDS))
-
- #define clubs_safe(player) (( (float) (cards_out(CLUBS) - \
- card_table[player].cards[CLUBS].length) / (PLAYERS - 1.0) >= 2.3) && \
- safe_suit(CLUBS))
-
- #define only_hearts(player) ((14 - round) == \
- card_table[player].cards[HEARTS].length)
-
- #define max(a,b) ((a > b) ? a : b)
-
- rnd(num)
- {
- extern long lrand48();
-
- return (lrand48() % num);
- }
-
-
- init_deck()
- {
- int suit_temp, rank_temp, j;
-
- j = 0;
- for (rank_temp = MIN_RANK; rank_temp <= MAX_RANK ; rank_temp++)
- for (suit_temp = CLUBS; suit_temp <= SPADES; suit_temp++) {
- deck[++j].suit = suit_temp;
- deck[j].rank = rank_temp;
- }
- }
-
- init_suit(list)
- struct suit_list *list;
- {
- char *malloc();
- ptr p, p1;
-
- list->length = 0;
- p = list->head = (ptr) malloc(sizeof(*p));
- p1 = list->tail = (ptr) malloc(sizeof(*p1));
- p->llink = NULL;
- p1->rlink = NULL;
- p->rlink = p1;
- p1->llink = p;
- p->rank = MAX_RANK + 1;
- p1->rank = 0;
- }
-
- init()
- {
- int player;
- extern void srand48();
-
- srand48((long)time(0)); /* Init random number gen */
- for (player = 1; player <= PLAYERS; player++) {
- card_table[player].player_kind = COMPUTER;
- (void) strcpy(card_table[player].name, comp_names[player]);
- card_table[player].socket = -1;
- }
- num_humans = 0;
- }
-
- new_game()
- {
- int suit, player;
-
- init_deck();
- for (player = 1; player <= PLAYERS; player++) {
- card_table[player].totalpts = 0;
- for (suit = CLUBS; suit <= SPADES; suit++)
- init_suit(&card_table[player].cards[suit]);
- }
- for (suit = CLUBS; suit <= SPADES; suit++)
- init_suit(&cards_played[suit]);
- }
-
- get_rank(rch)
- char rch;
- {
- int i;
-
- for (i = 1; i <= MAX_RANK; i++)
- if (rch == rnames[i])
- return(i);
- return(0);
- }
-
- get_suit(sch)
- char sch;
- {
- int i;
-
- for (i = 1; i <= MAX_SUIT; i++)
- if (sch == *snames[i])
- return(i);
- return(0);
- }
-
- char *
- get_name(player_num)
- int player_num;
- {
- int i;
- char unique_name = TRUE;
- static char pname[16+64];
-
- for (i = 1; i <= PLAYERS; i++)
- if ((i != player_num) &&
- !strcmp(card_table[i].name, card_table[player_num].name))
- unique_name = FALSE;
- if (unique_name)
- (void) strcpy(pname, card_table[player_num].name);
- else
- (void) sprintf(pname, "%s (%d)", card_table[player_num].name,
- player_num);
- if (strlen(pname) >= 16) {
- pname[15] = '\0';
- }
- return(pname);
- }
-
- /*
- * Get a card from somebody. get_mask is a bit mask specifying who is
- * acceptable to get a card from (i.e., bit n states player n can send
- * a card.) Scans all sockets for input, handling messages and player
- * leaving signals. Returns when one of the specified players passes
- * a card. Returns 0 if one of the specified players exits the game.
- */
- get_card(get_mask, from, buf)
- int get_mask, *from;
- char *buf;
- {
- int i, player, ret;
- char mesg_buf[64+16];
- fd_type read_fd;
-
- for (;;) {
- fd_init(4, &read_fd); /* Watch for new arrivals */
- for (player = 1; player <= PLAYERS; player++)
- if (card_table[player].player_kind != COMPUTER)
- fd_set(card_table[player].socket, &read_fd);
- if (select(WIDTH, &read_fd, (fd_type *) 0, (fd_type *) 0,
- (struct timeval *) 0)) {
- if (fd_isset(4, read_fd)) /* New arrival? */
- add_player();
- for (player = 1; player <= PLAYERS; player++) /* This player send? */
- if (fd_isset(card_table[player].socket, read_fd)) {
- ret = read_socket(card_table[player].socket, buf);
- *from = player;
- if (ret && (buf[0] == 'M')) {
- (void) sprintf(mesg_buf, "M%d%s: %s", MESG_WINDOW,
- get_name(player), buf + 1);
- if (strlen(mesg_buf) >= 64) {
- mesg_buf[63] = '\0';
- }
- send_to_all(mesg_buf); /* Message to everyone */
- }
- else if (ret && (buf[0] == '~')) {
- if (privatemsgs)
- privatemsgs = FALSE;
- else
- privatemsgs = TRUE;
- }
- else if (ret && (buf[0] == ';')) {
- if ((1 <= buf[1]-'0') &&
- privatemsgs &&
- (buf[1]-'0' <= PLAYERS) &&
- (card_table[buf[1]-'0'].player_kind != COMPUTER)) {
- (void) sprintf(mesg_buf, "M%d%s; %s", MESG_WINDOW,
- get_name(player), buf + 2);
- if (strlen(mesg_buf) >= 64) {
- mesg_buf[63] = '\0';
- }
- send_buf(buf[1]-'0',mesg_buf);
- send_buf(player,mesg_buf);
- }
- }
- else {
- if (!ret) {
- if (card_table[player].player_kind == HUMAN)
- player_mask &= ~(1 << player); /* player went away */
- card_table[player].player_kind = COMPUTER;
- (void) close(card_table[player].socket);
- if (--num_humans == 0)
- exit (0); /* give up if nobody wants to play (sniff) */
- for (i = 1; i <= PLAYERS; i++) {
- if (card_table[i].player_kind != COMPUTER) {
- (void) sprintf(buf,
- "M%d%s vanishes in a puff of greasy black smoke!",
- MESG_WINDOW, get_name(player)); /* Announce deletion */
- send_buf(i, buf); /* to others */
- (void) sprintf(buf,
- /*
- * Inform dealer.
- */
- "p%d<empty>", player - 1);
- write_socket(3, buf);
- }
- }
- (void) strcpy(card_table[player].name, comp_names[player]);
- send_all_totals();
- }
- if (get_mask & (1 << player))
- return(ret);
- }
- }
- }
- }
- }
-
- toss_card(player, card_to_toss, suit_to_toss)
- int player, suit_to_toss;
- ptr card_to_toss;
- {
- char buf[BUF_SIZE];
-
- (void) sprintf(buf, "R%c%c",
- rnames[card_to_toss->rank], *snames[suit_to_toss]);
- send_buf(player, buf); /* Tell player to remove card */
- }
-
- read_card(read_mask, player, card_to_play, suit_to_play)
- int read_mask, *player, *suit_to_play;
- ptr *card_to_play;
- {
- char buf[BUF_SIZE];
- int rank, suit;
- ptr p;
- char rank_ch, suit_ch;
-
- if (get_card(read_mask, player, buf)) {
- do {
- rank_ch = buf[1];
- if (rank_ch == '?') {
- if (round == 0)
- get_pass(*player, card_table[*player].num_passed+1,
- &p, &suit);
- else
- if (leader == *player)
- computer_lead(&p,&suit);
- else
- computer_pick(*player,&p,&suit);
- erase_window(*player, TEXT_WINDOW);
- } else {
- suit_ch = buf[2];
- rank = get_rank(rank_ch);
- suit = get_suit(suit_ch);
- erase_window(*player, TEXT_WINDOW);
- p = card_table[*player].cards[suit].head->rlink;
- while (p && (p->rank != rank))
- p = p->rlink;
- if (p == NULL) {
- (void) sprintf(buf, "M%dPlay a card you have:",
- TEXT_WINDOW);
- send_buf(*player, buf);
- send_buf(*player, "G");
- if (!get_card(read_mask, player, buf))
- return(0);
- }
- }
- }
- while (p == NULL);
- *card_to_play = p;
- *suit_to_play = suit;
- return(1);
- }
- return(0);
- }
-
- send_card(player, rank, suit)
- int player, rank, suit;
- {
- char buf[BUF_SIZE];
-
- (void) sprintf(buf, "A%c%c", rnames[rank], *snames[suit]);
- send_buf(player, buf);
- }
-
- /*
- * send cards in hand to player
- */
- send_hand(player)
- int player;
- {
- int suit;
- ptr p;
-
- for (suit = CLUBS; suit <= SPADES; suit++) { /* send cards in hand */
- p = card_table[player].cards[suit].head->rlink;
- while (p->rank) {
- send_card(player, p->rank, suit);
- p = p->rlink;
- }
- }
- }
-
- get_first_player()
- {
- fd_type read_fd; /* main socket bit mask */
-
- /*
- * wait for new player to show up
- */
- fd_init(4, &read_fd); /* Wait for someone to show up */
- if (select(WIDTH, &read_fd, (fd_type *) 0, (fd_type *) 0,
- (struct timeval *) 0) == -1) {
- perror("select");
- exit(1);
- }
- }
-
- add_player()
- {
- int new_socket; /* new file descriptor */
- char pname[128], buf[128];
- struct sockaddr_in sockad;
- int ssize; /* to make accept happy */
- int new_player = 0;
- int i;
-
- /*
- * add whoever's waiting
- */
- ssize = sizeof (sockad);
- if ((new_socket = accept(4, &sockad, &ssize)) == -1) {
- perror("accept");
- exit(1);
- }
- /* get user name */
- if (read_socket(new_socket, pname) > 0) {
- pname[8] = '\0'; /* Name must be less than 9 chars */
- for (i = PLAYERS; i >= 1; i--)
- if (card_table[i].player_kind == COMPUTER)
- new_player = i;
- }
- if (new_player) {
- /*
- * Inform distributor
- */
- (void) sprintf(buf, "p%d%s", new_player - 1, pname);
- write_socket(3, buf);
- card_table[new_player].player_kind = human_type;
- card_table[new_player].socket = new_socket;
- (void) strcpy(card_table[new_player].name, pname);
- ++num_humans;
- if (human_type == VOYEUR) {
- (void) sprintf(buf,
- "M%d Game in progress...", PLAY_WINDOW);
- send_buf(new_player, buf);
- (void) sprintf(buf,
- "M%dYou may watch till next hand.", MESG_WINDOW);
- send_buf(new_player, buf);
- }
- else
- player_mask |= 1 << new_player;
- for (i = 1; i <= PLAYERS; i++) {
- if (card_table[i].player_kind != COMPUTER) {
- (void) sprintf(buf,
- "M%d%s added as player %d", MESG_WINDOW,
- pname, new_player);
- if (i != new_player) /* Announce addition */
- send_buf(i, buf);
- send_totals(i);
- }
- }
- send_hand(new_player);
- }
- else {
- (void) sprintf(buf, "M%dAll seats are full!", MESG_WINDOW);
- write_socket(new_socket, buf);
- write_socket(new_socket, "Z");
- (void) close(new_socket);
- }
- }
-
- erase_window(player, which_window)
- int player, which_window;
- {
- char buf[BUF_SIZE];
-
- (void) sprintf(buf, "E%d", which_window);
- send_buf(player, buf);
- }
-
- erase_all_window(which_window)
- int which_window;
- {
- int player;
-
- for (player = 1; player <= PLAYERS; player++)
- if (card_table[player].player_kind != COMPUTER)
- erase_window(player, which_window);
- }
-
- send_totals(player)
- int player;
- {
- int i;
- char buf[BUF_SIZE];
-
- if (card_table[player].player_kind != COMPUTER) {
- for (i = 1; i <= PLAYERS; i++) {
- (void) sprintf(buf, "S%d%03d%03d%s", i,
- card_table[i].pts,
- card_table[i].totalpts, card_table[i].name);
- send_buf(player, buf);
- }
- }
- }
-
- send_all_totals()
- {
- int player;
-
- for (player = 1; player <= PLAYERS; player++)
- send_totals(player);
- }
-
- send_all_winner()
- {
- int max_score,
- player, shooter;
- char buf[BUF_SIZE];
- char mikeysh;
-
- (void) sprintf(buf, "M%d--------------------------------------------------------", MESG_WINDOW);
- send_to_all(buf);
- max_score = 0;
- mikeysh = TRUE;
- for (player = 1; player <= PLAYERS; player++) {
- if ((max_score != 0) &&
- (card_table[player].pts != 0) &&
- (card_table[player].pts != -10))
- mikeysh = FALSE;
- if ((card_table[player].pts > max_score) &&
- (card_table[player].pts != -10) &&
- (card_table[player].pts != 0)) {
- max_score = card_table[player].pts;
- shooter = player;
- }
- }
- mikeysh = mikeysh && (mikeyshooter == shooter);
-
- if (mikeysh) {
- for (player = 1; player <= PLAYERS; player++) {
- if (player != shooter)
- card_table[player].totalpts += 26;
- if ((player == MIKEYJder) && MIKEYJ)
- card_table[player].totalpts -= 10;
- }
- }
- else {
- for (player = 1; player <= PLAYERS; player++)
- card_table[player].totalpts += card_table[player].pts;
- }
- if (mikeysh)
- (void) sprintf(buf, "M %s wins by shooting the moon!",
- get_name(shooter));
- else {
- get_winner(buf, FALSE);
- (void) strcat(buf, ".");
- }
- buf[1] = MESG_WINDOW + '0';
- send_to_all(buf);
- }
-
- send_final_winner()
- {
- char buf[64];
-
- get_winner(buf, TRUE);
- buf[1] = PLAY_WINDOW + '0';
- (void) strcat(buf, " total!");
- erase_all_window(PLAY_WINDOW);
- send_to_all(buf);
- }
-
- /*
- * Get buffer of form: "M groucho wins with nn points"
- * or: "M groucho and chico tie with nn points"
- */
- get_winner(buf, use_totalpts)
- char *buf;
- char use_totalpts;
- {
- int player, winning_score, temp,
- scores[PLAYERS + 1], players[PLAYERS + 1];
- char sorted;
-
- for (player = 1; player <= PLAYERS; player++) {
- scores[player] = use_totalpts ? card_table[player].totalpts
- : card_table[player].pts;
- players[player] = player;
- }
- do { /* Bubble sort the bloody thing */
- sorted = TRUE;
- for (player = 1; player < PLAYERS; player++)
- if (scores[player + 1] < scores[player]) {
- temp = scores[player];
- scores[player] = scores[player + 1];
- scores[player + 1] = temp;
- temp = players[player];
- players[player] = players[player + 1];
- players[player + 1] = temp;
- sorted = FALSE;
- }
- }
- while (!sorted);
- winning_score = scores[1];
- (void) sprintf(buf, "M %s", card_table[players[1]].name);
- for (player = 2;
- (player <= PLAYERS) && (scores[player] == winning_score); player++)
- (void) sprintf(buf + strlen(buf), " and %s",
- card_table[players[player]].name);
- if (scores[2] == winning_score)
- (void) sprintf(buf + strlen(buf),
- " tie with %d point", winning_score);
- else
- (void) sprintf(buf + strlen(buf),
- " wins with %d point", winning_score);
- if (winning_score != 1)
- (void) strcat(buf, "s");
- }
-
- send_buf(player, buf)
- int player;
- char *buf;
- {
- write_socket(card_table[player].socket, buf);
- }
-
- send_to_all(buf)
- char *buf;
- {
- int player;
-
- for (player = 1; player <= PLAYERS; player++)
- if (card_table[player].player_kind != COMPUTER)
- send_buf(player, buf);
- }
-
- new_round()
- {
- char buf[BUF_SIZE];
- int mikey;
-
- for(mikey = 1;mikey <= PLAYERS;mikey++) {
- trick.played[mikey].rank = 0;
- trick.played[mikey].suit = 0;
- }
- for(mikey=CLUBS; mikey<=SPADES; mikey++) {
- if (cards_out(mikey) <= 1.5*PLAYERS) {
- int each;
-
- for (each=1; each<=PLAYERS; each++) {
- if (voided[mikey][each] == FALSE) {
- voided[mikey][each] = MAYBE;
- }
- }
- }
- }
- trick.pts = 0;
- trick.any_hearts = FALSE;
- player_count = 0;
- erase_all_window(PLAY_WINDOW);
- /*
- * Inform distributor
- */
- (void) sprintf(buf, "r%d", round);
- write_socket(3, buf);
- (void) sprintf(buf, "M%dHand: %d Round: %d",
- ROUND_WINDOW, hand, round);
- send_to_all(buf);
- }
-
- enter_card(which_card, which_hand)
- struct card which_card;
- card_hand which_hand;
-
- {
- ptr p, p1;
-
- p = which_hand[which_card.suit].head;
- ++which_hand[which_card.suit].length;
- while (p->rank > which_card.rank)
- p = p->rlink;
- p1 = (ptr) malloc(sizeof(*p1));
- p1->llink = p->llink;
- p1->llink->rlink = p1;
- p->llink = p1;
- p1->rlink = p;
- p1->rank = which_card.rank;
- }
-
- remove_node(p)
- ptr p;
-
- {
- p->llink->rlink = p->rlink;
- p->rlink->llink = p->llink;
- free((char *) p);
- }
-
- clear_hand(which_hand)
- card_hand which_hand;
- {
- int suit;
- ptr p, p1;
-
- for (suit = CLUBS; suit <= SPADES; suit++) {
- which_hand[suit].length = 0;
- p = which_hand[suit].head->rlink;
- while (p->rank > 0) {
- p1 = p;
- p = p->rlink;
- remove_node(p1);
- }
- }
- }
-
- shuffle()
- {
- int j, k;
- struct card t;
-
- for (j = 52; j >= 1; j--) {
- k = rnd(j) + 1;
- t = deck[k];
- deck[k] = deck[j];
- deck[j] = t;
- }
- }
-
- deal()
- {
- int i, j, player;
-
- for (player = 1; player <= PLAYERS; player++) {
- j = NCARDS * (player - 1);
- for (i = 1; i <= NCARDS; i++)
- enter_card(deck[i+j], card_table[player].cards);
- if (card_table[player].player_kind != COMPUTER)
- send_hand(player);
- }
- }
-
- new_hand()
- {
- int player;
- char buf[BUF_SIZE];
-
- mikeyshooter = 0;
- MIKEYJder = 0;
- MIKEYJdintrick = FALSE;
- points_played = 0;
- someone_is_shooting = FALSE;
- jack_played = queen_played = hearts_broken = FALSE;
- trick.suit_led = CLUBS;
- for (player = 1; player <= PLAYERS; player++) {
- int each;
-
- card_table[player].pts = 0;
- clear_hand(card_table[player].cards);
- voided[CLUBS][player] = voided[DIAMONDS][player] =
- voided[HEARTS][player] = voided[SPADES][player] = FALSE;
- for (each=1; each<=PLAYERS; each++) {
- hasqs[player][each] = TRUE;
- }
- }
- clear_hand(cards_played);
- erase_all_window(PLAY_WINDOW);
- send_all_totals();
- /*
- * Inform distributor
- */
- (void) sprintf(buf, "h%d", hand);
- write_socket(3, buf);
- write_socket(3, "r0");
- (void) sprintf(buf, "M%dNew hand...", ROUND_WINDOW);
- send_to_all(buf);
- shuffle(); /* Shuffle three times! */
- shuffle(); /* (just like vegas!) */
- shuffle();
- deal();
- }
-
- ptr
- find_card(player,rank,suit)
- int player,rank,suit;
- {
- ptr p;
-
- p = card_table[player].cards[suit].head->rlink;
- while (p && p->rank)
- if (p->rank == rank)
- return(p);
- else
- p = p->rlink;
- return(NULL);
- }
-
- char
- not_in_trick(rank,suit)
- int rank,suit;
- {
- int mikey;
-
- for(mikey = 1;mikey <= PLAYERS;mikey++) {
- if ((trick.played[mikey].rank == rank) &&
- (trick.played[mikey].suit == suit))
- return(FALSE);
- }
- return(TRUE);
- }
-
- ptr
- effective_high(player,rank,suit)
- int player,rank,suit;
- {
- ptr card,p,q;
- int r;
-
- r = rank-1;
- card = find_card(player,rank,suit);
- p = card->rlink;
- q = cards_played[suit].head->rlink;
- while (q->rank > r)
- q = q->rlink;
- while (r && (!MIKEYJ || (suit != DIAMONDS) || (r != JACK)) &&
- ((suit != SPADES) || (r != QUEEN)) &&
- ((p->rank == r) || ((q->rank == r) &&
- (not_in_trick(r,suit))))) {
- if (p->rank == r) {
- card = p;
- p = p->rlink;
- } else {
- q = q->rlink;
- }
- r--;
- }
- return(card);
- }
-
-
- ptr
- effective_low(player,rank,suit)
- int player,rank,suit;
- {
- ptr card,p,q;
- int r;
-
- r = rank+1;
- card = find_card(player,rank,suit);
- p = card->llink;
- q = cards_played[suit].tail->llink;
- while (q->rank < r)
- q = q->llink;
- while ((r <= MAX_RANK) &&
- (!MIKEYJ || (suit != DIAMONDS) || (r != JACK)) &&
- ((suit != SPADES) || (r != QUEEN)) &&
- ((p->rank == r) || ((q->rank == r) &&
- (not_in_trick(r,suit))))) {
- if (p->rank == r) {
- card = p;
- p = p->llink;
- } else {
- q = q->llink;
- }
- r++;
- }
- return(card);
- }
-
-
- ptr
- next_highest(player, rank, suit_to_play)
- int player, rank, suit_to_play;
- {
- ptr p;
-
- p = card_table[player].cards[suit_to_play].head->rlink;
- while (p && p->rank)
- if (p->rank < rank)
- return(effective_high(player,p->rank,suit_to_play));
- else
- p = p->rlink;
- return(NULL);
- }
-
- int
- highest_unplayed(suit, player)
- int suit, player;
- {
- ptr p, q;
- int last;
-
- p = cards_played[suit].head->rlink;
- q = card_table[player].cards[suit].head->rlink;
- last = MAX_RANK+1;
- while (last) {
- if ((p->rank != last-1) && (q->rank != last-1)) {
- return(last-1);
- } else {
- if (q->rank == last-1) {
- q = q->rlink;
- } else {
- p = p->rlink;
- }
- last--;
- }
- }
- return(0);
- }
-
- int
- lowest_unplayed(suit, player)
- int suit, player;
- {
- ptr p, q;
- int last;
-
- p = cards_played[suit].tail->llink;
- q = card_table[player].cards[suit].tail->llink;
- last = 0;
- while (last != MAX_RANK) {
- if ((p->rank != last+1) && (q->rank != last+1)) {
- return(last+1);
- } else {
- if (q->rank == last+1) {
- q = q->rlink;
- } else {
- p = p->rlink;
- }
- last++;
- }
- }
- return(MAX_RANK+1);
- }
-
- int
- count_losers(rank, suit)
- int rank, suit;
- {
- ptr p;
- int losers;
-
- p = cards_played[suit].head->rlink;
- losers = 0;
- while (p->rank) {
- if (p->rank < rank)
- losers++;
- p = p->rlink;
- }
- return(losers);
- }
-
- int
- find_true(array)
- int array[PLAYERS+1];
- {
- int each, result;
-
- result = FALSE;
- for (each=trick.card_count+1; each<=PLAYERS; each++) {
- if (array[map_player(leader,each)] == TRUE)
- result = TRUE;
- if ((array[map_player(leader,each)] == MAYBE) && (result != TRUE))
- result = MAYBE;
- }
- return(result);
- }
-
- int
- count_array(array, value)
- int array[PLAYERS+1], value;
- {
- int each, result;
-
- result = 0;
- for (each=1; each<=PLAYERS; each++) {
- if (array[each] == value)
- result++;
- }
- return(result);
- }
-
- int
- find_false(array)
- int array[PLAYERS+1];
- {
- int each, result;
-
- result = TRUE;
- for (each=trick.card_count+1; each<=PLAYERS; each++) {
- if (array[map_player(leader,each)] == FALSE)
- result = FALSE;
- if ((array[map_player(leader,each)] == MAYBE) && (result != FALSE))
- result = MAYBE;
- }
- return(result);
- }
-
- ptr
- effective_highest(player, suit)
- int player, suit;
- {
- ptr p;
-
- p = highest(player,suit);
- if (p->rank)
- return(effective_high(player,p->rank,suit));
- else
- return(p);
- }
-
- ptr
- effective_lowest(player, suit)
- int player, suit;
- {
- ptr p;
-
- p = lowest(player,suit);
- if (p->rank != MAX_RANK+1)
- return(effective_low(player,p->rank,suit));
- else
- return(p);
- }
-
- int
- lowestp(rank,suit)
- int rank, suit;
- {
- ptr p;
- int each;
-
- p = cards_played[suit].tail->llink;
- for (each=1; each<rank; each++) {
- if (p->rank == each) {
- p = p->llink;
- } else {
- return(FALSE);
- }
- }
- return(TRUE);
- }
-
-
- find_high_card(player, card_to_play, suit_to_play, play_points, play_spades, play_diamonds)
- int player, *suit_to_play;
- char play_points, play_spades, play_diamonds;
- ptr *card_to_play;
- {
- int high_card, suit;
- ptr p;
-
- high_card = -1;
- *card_to_play = NULL;
- for (suit = CLUBS; suit <= SPADES; suit++) {
- p = card_table[player].cards[suit].head->rlink;
-
- if ((suit == DIAMONDS) && (p->rank >= JACK) && MIKEYJ) {
- p=p->rlink;
- }
-
- if ((p->rank != 0) &&
- (p->rank-count_losers(p->rank,suit) > high_card) &&
- (play_spades ||
- (suit != SPADES)) &&
- (play_diamonds ||
- (suit != DIAMONDS)) &&
- (play_points ||
- (point_value(p->rank, suit) == 0))) {
- high_card = p->rank-count_losers(p->rank,suit);
- *card_to_play = p;
- *suit_to_play = suit;
- }
- }
- if (*card_to_play == NULL) {
- /*
- * No clubs or diamonds. Q spades is highest spade, or no
- * spades at all. Try to play next highest spade.
- */
-
- /*
- * May have Jack of Diamonds also, if MIKEYJ
- */
- if (play_spades)
- *card_to_play = next_highest(player, QUEEN, SPADES);
- if (*card_to_play)
- *suit_to_play = SPADES;
- else if (play_points &&
- (card_table[player].cards[HEARTS].length)) {
- /* Play highest heart */
- *card_to_play = effective_highest(player, HEARTS);
- *suit_to_play = HEARTS;
- }
- /* otherwise, try lowest diamond */
- if ((*card_to_play == NULL) &&
- card_table[player].cards[DIAMONDS].length) {
- *card_to_play = lowest(player, DIAMONDS);
- *suit_to_play = DIAMONDS;
- }
- if ((*card_to_play == NULL) &&
- card_table[player].cards[SPADES].length) {
- *card_to_play = effective_highest(player, SPADES);
- *suit_to_play = SPADES;
- }
- /* shouldn't ever need the following
- if (*card_to_play == NULL) {
- *card_to_play = effective_highest(player, CLUBS);
- *suit_to_play = CLUBS;
- if (((*card_to_play)->rank) == 0)
- *card_to_play = NULL;
- }
- */
- }
- }
-
- find_low_card(player, card_to_play, suit_to_play)
- int player, *suit_to_play;
- ptr *card_to_play;
- {
- int low_card, suit;
- ptr p;
-
- low_card = MAX_RANK + 1;
- *card_to_play = NULL;
- for (suit = CLUBS; suit <= SPADES; suit++) {
- p = card_table[player].cards[suit].tail->llink;
- if (MIKEYJ && (p->rank == JACK) && (suit == DIAMONDS))
- p = p->llink;
- if ((p->rank < low_card) &&
- (point_value(p->rank, suit) == 0)) {
- low_card = p->rank;
- *card_to_play = p;
- *suit_to_play = suit;
- }
- }
- if (*card_to_play == NULL) {
- *suit_to_play = HEARTS;
- *card_to_play = card_table[player].cards[HEARTS].tail->llink;
- if ((*card_to_play)->rank == MAX_RANK+1) {
- *suit_to_play = DIAMONDS;
- *card_to_play = find_card(player,JACK,DIAMONDS);
- }
- if (!(*card_to_play) || (*card_to_play)->rank == MAX_RANK+1) {
- *suit_to_play = SPADES;
- *card_to_play = find_card(player,QUEEN,SPADES);
- }
- }
- }
-
- find_low_club(leader)
- int *leader;
- {
- int player, low_club, rank;
-
- low_club = MAX_RANK;
- for (player = 1; player <= PLAYERS; player++)
- if ((rank = card_table[player].cards[CLUBS].tail->llink->rank) < low_club) {
- *leader = player;
- low_club = rank;
- }
- }
-
- find_queen(player, card_to_play)
- int player;
- ptr *card_to_play;
- {
- ptr p;
-
- *card_to_play = NULL;
- p = card_table[player].cards[SPADES].head->rlink;
- while (p)
- if (p->rank == QUEEN) {
- *card_to_play = p;
- p = NULL;
- }
- else
- p = p->rlink;
- }
-
- print_pass(player)
- int player;
- {
- int i;
- char buf[BUF_SIZE];
- struct card cd;
-
- erase_window(player, PLAY_WINDOW);
- (void) sprintf(buf, "M%d%s passes you:", LEAD_WINDOW,
- get_name(card_table[player].passer));
- send_buf(player, buf);
- for (i = 1; i <= NPASS; i++) {
- cd = card_table[player].passed_cards[i];
- send_card(player, cd.rank, cd.suit);
- (void) sprintf(buf, "P%d%c%c", i, rnames[cd.rank], *snames[cd.suit]);
- send_buf(player, buf);
- }
- }
-
- /*
- * Get card to pass from computer player
- */
- get_pass(from, which_pass, card_to_pass, suit_to_pass)
- int from, which_pass, *suit_to_pass;
- ptr *card_to_pass;
- {
- ptr p1;
- int each;
-
- p1 = highest(from, SPADES);
- if ((((p1->rank > QUEEN) &&
- (!find_card(from,QUEEN,SPADES) ||
- (card_table[from].cards[SPADES].length <= 4))) ||
- ((p1->rank == QUEEN) &&
- (card_table[from].cards[SPADES].length <= 4))) &&
- card_table[from].cards[SPADES].length) {
- *card_to_pass = p1;
- *suit_to_pass = SPADES;
- if (p1->rank == QUEEN) {
- /* remember who has the QS */
- for (each=1; each<=PLAYERS; each++) {
- hasqs[from][each] = FALSE;
- }
- hasqs[from][map_player(from, hand)] = TRUE;
- }
- } else if (card_table[from].cards[DIAMONDS].length &&
- !find_card(from,JACK,DIAMONDS) &&
- (highest(from,DIAMONDS)->rank >= 4) &&
- (card_table[from].cards[DIAMONDS].length <= NPASS-which_pass+1)) {
- /* create void in DIAMONDS */
- *card_to_pass = highest(from, DIAMONDS);
- *suit_to_pass = DIAMONDS;
- } else if (card_table[from].cards[CLUBS].length &&
- (highest(from,CLUBS)->rank >= 4) &&
- (card_table[from].cards[CLUBS].length <= NPASS-which_pass+1)) {
- /* create void in CLUBS */
- *card_to_pass = highest(from, CLUBS);
- *suit_to_pass = CLUBS;
- } else if (card_table[from].cards[HEARTS].length &&
- (highest(from,HEARTS)->rank >= 7) &&
- (card_table[from].cards[HEARTS].length <= NPASS-which_pass+1)) {
- /* create void in HEARTS */
- *card_to_pass = highest(from, HEARTS);
- *suit_to_pass = HEARTS;
- } else if (card_table[from].cards[HEARTS].length &&
- ((card_table[from].cards[HEARTS].length <= 2) ||
- ((card_table[from].cards[HEARTS].length == 3) &&
- (highest(from,HEARTS)->rlink->rank > 8))) &&
- (highest(from,HEARTS)->rank > JACK)) {
- /* get rid of high HEART */
- *card_to_pass = highest(from, HEARTS);
- *suit_to_pass = HEARTS;
- } else if ((card_table[from].cards[CLUBS].length > 2) &&
- (lowest(from,CLUBS)->rank >= 8)) {
- /* get rid of high CLUBS */
- *card_to_pass = highest(from, CLUBS);
- *suit_to_pass = CLUBS;
- } else if ((card_table[from].cards[HEARTS].length > 2) &&
- (lowest(from,HEARTS)->rank >= 8)) {
- /* get rid of high HEARTS */
- *card_to_pass = highest(from, HEARTS);
- *suit_to_pass = HEARTS;
- } else if (card_table[from].cards[CLUBS].length &&
- (highest(from,CLUBS)->rank >= 7) &&
- (card_table[from].cards[CLUBS].length <= NPASS-which_pass+2)) {
- /* create almost void in CLUBS */
- *card_to_pass = find_card(from,1,CLUBS);
- if (!*card_to_pass)
- *card_to_pass = highest(from, CLUBS);
- *suit_to_pass = CLUBS;
- } else if (card_table[from].cards[HEARTS].length &&
- (card_table[from].cards[HEARTS].length >= 5) &&
- (highest(from,HEARTS)->rlink->rank >= 7)) {
- /* get rid of some HEARTS */
- if (highest(from, HEARTS)->rank >= JACK)
- *card_to_pass = highest(from, HEARTS)->rlink;
- else
- *card_to_pass = highest(from, HEARTS);
- *suit_to_pass = HEARTS;
- } else if (card_table[from].cards[CLUBS].length &&
- (card_table[from].cards[CLUBS].length >= 5)) {
- /* get rid of some CLUBS */
- *card_to_pass = find_card(from,1,CLUBS);
- if (!*card_to_pass)
- *card_to_pass = highest(from, CLUBS);
- *suit_to_pass = CLUBS;
- } else if (card_table[from].cards[DIAMONDS].length &&
- !find_card(from,JACK,DIAMONDS) &&
- (card_table[from].cards[DIAMONDS].length >= 5)) {
- /* get rid of some DIAMONDS */
- *card_to_pass = highest(from, DIAMONDS);
- *suit_to_pass = DIAMONDS;
- } else if (card_table[from].cards[SPADES].length &&
- !find_card(from,QUEEN,SPADES) &&
- (card_table[from].cards[SPADES].length >= 5)) {
- /* get rid of some SPADES */
- *card_to_pass = highest(from, SPADES);
- *suit_to_pass = SPADES;
- } else if (find_card(from,1,CLUBS)) {
- *card_to_pass = find_card(from,1,CLUBS);
- *suit_to_pass = CLUBS;
- } else {
- find_high_card(from, card_to_pass, suit_to_pass, FALSE, TRUE, TRUE);
- }
- }
-
-
- /*
- * Pass card to player
- */
- pass_to(from, who_to, which_pass, card_to_pass, suit_to_pass)
- int from, who_to, which_pass;
- ptr card_to_pass;
- char suit_to_pass;
- {
- char buf[BUF_SIZE];
-
- card_table[who_to].passed_cards[which_pass].rank = card_to_pass->rank;
- card_table[who_to].passed_cards[which_pass].suit = suit_to_pass;
- --card_table[from].cards[suit_to_pass].length;
- card_table[who_to].passer = from;
- if (card_table[from].player_kind != COMPUTER) {
- erase_window(from, INP_WINDOW);
- (void) sprintf(buf, "P%d%c%c", which_pass,
- rnames[card_to_pass->rank], *snames[suit_to_pass]);
- send_buf(from, buf);
- toss_card(from, card_to_pass, suit_to_pass);
- }
- remove_node(card_to_pass);
- }
-
- player_pass(player)
- int player;
- {
- char buf[BUF_SIZE];
-
- (void) sprintf(buf, "M%dPass %d to %s:",
- TEXT_WINDOW, NPASS, get_name(map_player(player, hand)));
- send_buf(player, buf);
- (void) sprintf(buf, "M%dCard 1:", LEAD_WINDOW);
- send_buf(player, buf);
- send_buf(player, "G");
- }
-
- pass_cards()
- {
- int player, pass, suit, old_mask;
- int passed_mask = 0;
- ptr p;
- char buf[BUF_SIZE];
-
- human_type = HUMAN;
- for (player = 1; player <= PLAYERS; player++) {
- card_table[player].num_passed = 0;
- if (card_table[player].player_kind == HUMAN)
- player_pass(player);
- }
- while (player_mask != passed_mask) {
- old_mask = player_mask;
- if (read_card(player_mask, &player, &p, &suit)) {
- pass_to(player, map_player(player, hand),
- ++card_table[player].num_passed, p, suit);
- if (card_table[player].num_passed == NPASS)
- /*
- * Done passing
- */
- passed_mask |= 1 << player;
- else {
- (void) sprintf(buf, "M%dCard %d:", LEAD_WINDOW,
- card_table[player].num_passed + 1);
- /*
- * Ask for next card
- */
- send_buf(player, buf);
- send_buf(player, "G");
- }
- }
- else
- /*
- * Player left game
- */
- passed_mask &= ~(1 << player);
- /*
- * Player added?
- */
- for (player = 1; player <= PLAYERS; player++)
- if (~old_mask & player_mask & (1 << player)) {
- card_table[player].num_passed = 0;
- player_pass(player);
- }
- }
- erase_all_window(LEAD_WINDOW);
- human_type = VOYEUR;
- /*
- * Let computer pass.
- */
- for (player = 1; player <= PLAYERS; player++)
- if (card_table[player].player_kind != HUMAN)
- for (pass = ++card_table[player].num_passed;
- pass <= NPASS; pass++) {
- get_pass(player, pass, &p, &suit);
- pass_to(player, map_player(player, hand), pass, p, suit);
- }
- for (player = 1; player <= PLAYERS; player++) {
- for (pass = 1; pass <= NPASS; pass++)
- enter_card(card_table[player].passed_cards[pass],
- card_table[player].cards);
- if (card_table[player].player_kind != COMPUTER)
- print_pass(player);
- }
- }
-
- point_value(rank, suit)
- int rank, suit;
- {
- if (suit == HEARTS)
- return(1);
- else
- if ((suit == SPADES) && (rank == QUEEN))
- return(13);
- else
- if ((suit == DIAMONDS) && (rank == JACK) && MIKEYJ)
- return(-10);
- return(0);
- }
-
- show(player, card_to_play, suit_to_play)
- int player, suit_to_play;
- ptr card_to_play;
- {
- int rank_to_play;
- char buf[BUF_SIZE];
-
- rank_to_play = card_to_play->rank;
- if (card_table[player].player_kind != COMPUTER) {
- erase_window(player, INP_WINDOW);
- erase_window(player, LEAD_WINDOW);
- toss_card(player, card_to_play, suit_to_play);
- }
- remove_node(card_to_play);
- --card_table[player].cards[suit_to_play].length;
- if (suit_to_play == HEARTS)
- trick.any_hearts = TRUE;
- else {
- if ((suit_to_play == SPADES) && (rank_to_play == QUEEN))
- queen_played = TRUE;
- else
- if ((suit_to_play == DIAMONDS) &&
- (rank_to_play == JACK) &&
- MIKEYJ) {
- jack_played = TRUE;
- MIKEYJdintrick = TRUE;
- }
- }
- if ((suit_to_play == trick.suit_led) &&
- (rank_to_play > trick.highest_played)) {
- trick.highest_played = rank_to_play;
- trick.high_player = player;
- }
- trick.played[player].rank = rank_to_play;
- trick.played[player].suit = suit_to_play;
- trick.pts += point_value(rank_to_play, suit_to_play);
-
- enter_card(trick.played[player], cards_played);
- ++trick.card_count;
- (void) sprintf(buf, "P%d%c%c%s", player, rnames[rank_to_play],
- *snames[suit_to_play], card_table[player].name);
- send_to_all(buf);
- }
-
- really_safe(suit)
- int suit;
- {
- char safe;
- int losers_out, low_rank;
-
- low_rank = card_table[leader].cards[suit].tail->llink->rank;
- /*
- * Count # cards of _suit_ played that would be losers
- * to leaders lowest of _suit_.
- */
- losers_out = count_losers(low_rank,suit);
- /*
- * Card is guaranteed to lose the trick if:
- * -- All cards of suit lower than low_rank have been played;
- * -- There is at least one other card of the suit unplayed.
- *
- */
- safe = (losers_out == (low_rank - 1)) &&
- (card_table[leader].cards[suit].length +
- cards_played[suit].length != 13);
- safe &= (find_true(voided[suit]) == FALSE);
- if (suit == SPADES)
- safe &= ((card_table[leader].cards[SPADES].tail->llink->rank <
- QUEEN) || queen_played);
- return(safe);
- }
-
- find_low_lead(card_to_play, suit_to_play, play_hearts)
- ptr *card_to_play;
- int *suit_to_play;
- char play_hearts;
- {
- int pass, low_card, suit, f, last_gasp;
- ptr p, q;
-
- last_gasp = FALSE;
- *card_to_play = NULL;
- pass = 0;
- q = find_card(leader,QUEEN,SPADES);
- while (*card_to_play == NULL) {
- pass++;
- if (pass > 20)
- last_gasp = TRUE;
- low_card = MAX_RANK+1;
- for (suit = CLUBS; suit <= SPADES; suit++) {
- p = card_table[leader].cards[suit].tail->llink;
- if ((((p->rank == JACK) && (suit == DIAMONDS) && MIKEYJ) ||
- ((p->rank == QUEEN) && (suit == SPADES))) &&
- (card_table[leader].cards[suit].length > 1)) {
- p = p->llink;
- }
- if ((p->rank <= MAX_RANK) &&
- (p->rank-count_losers(p->rank,suit) < low_card) &&
- (play_hearts || (suit != HEARTS) || last_gasp)) {
- f = TRUE;
- switch(pass) {
- case 1:
- f = ((cards_out(suit) == card_table[leader].cards[suit].length+1) &&
- (!q || (suit != SPADES)) &&
- (highest_unplayed(suit,leader) > p->rank));
- break;
- case 2:
- f = (lowestp(p->rank, suit) &&
- (!q || (suit != SPADES)) &&
- (highest_unplayed(suit,leader) > p->rank));
- break;
- case 3:
- f = ((count_array(voided[suit],TRUE) == 2) &&
- (!q || (suit != SPADES)) &&
- (highest_unplayed(suit,leader) > p->rank) &&
- (lowest_unplayed(suit,leader) > p->rank));
- break;
- case 4:
- f = (safe_suit(suit) &&
- (!q || (suit != SPADES) ||
- (card_table[leader].cards[suit].length > 3)) &&
- (highest_unplayed(suit,leader) > p->rank) &&
- (count_array(voided[suit],TRUE) < 2) &&
- !((MIKEYJ && (suit == DIAMONDS) && (p->rank == JACK)) ||
- ((suit == SPADES) && (p->rank == QUEEN))));
- break;
- case 5:
- f = ((find_true(voided[suit]) == MAYBE) &&
- (!q || (suit != SPADES) ||
- (card_table[leader].cards[suit].length > 2)) &&
- (highest_unplayed(suit,leader) > p->rank) &&
- (count_array(voided[suit],TRUE) < 2) &&
- !((MIKEYJ && (suit == DIAMONDS) && (p->rank == JACK)) ||
- ((suit == SPADES) && (p->rank == QUEEN))));
- break;
- case 6:
- f = ((highest_unplayed(suit,leader) > p->rank) &&
- (count_array(voided[suit],TRUE) < 2) &&
- (!q || (suit != SPADES) ||
- (card_table[leader].cards[suit].length > 2)) &&
- !((MIKEYJ && (suit == DIAMONDS) && (p->rank == JACK)) ||
- ((suit == SPADES) && (p->rank == QUEEN))));
- break;
- case 7:
- f = ((highest_unplayed(suit,leader) > p->rank) &&
- (count_array(voided[suit],TRUE) < 2) &&
- !((MIKEYJ && (suit == DIAMONDS) && (p->rank == JACK)) ||
- ((suit == SPADES) && (p->rank == QUEEN))));
- break;
- case 8:
- f = ((highest_unplayed(suit,leader) > p->rank) &&
- (count_array(voided[suit],TRUE) < 2) &&
- ((suit != SPADES) || (p->rank != QUEEN)));
- break;
- case 9:
- f = ((highest_unplayed(suit,leader) > p->rank) &&
- (count_array(voided[suit],TRUE) < 2));
- break;
- }
- if (f) {
- low_card = p->rank-count_losers(p->rank,suit);
- *card_to_play = p;
- *suit_to_play = suit;
- }
- }
- }
- }
- #ifdef DEBUG
- fprintf(fp, "%2d ",pass);
- #endif
- }
-
-
- show_lead(card_to_play, suit_to_play)
- int suit_to_play;
- ptr card_to_play;
- {
- trick.card_count = 1;
- trick.highest_played = card_to_play->rank;
- trick.suit_led = suit_to_play;
- trick.high_player = leader;
- show(leader, card_to_play, suit_to_play);
- }
-
- read_lead(leader, card_to_play, suit_to_play)
- int leader, *suit_to_play;
- ptr *card_to_play;
- {
- char good, alive, buf[64];
- int t; /* Ignored */
-
- do {
- send_buf(leader, "G");
- if (alive = read_card(1 << leader, &t, card_to_play, suit_to_play)) {
- good = (((round != 1) ||
- (*card_to_play == card_table[leader].cards[CLUBS].tail->llink)) &&
- ((*suit_to_play != HEARTS) || hearts_broken || only_hearts(leader)));
- if (!good) {
- if (*suit_to_play == HEARTS)
- (void) sprintf(buf,"M%dHearts not broken yet!", TEXT_WINDOW);
- else
- (void) sprintf(buf,"M%dLead your lowest club!", TEXT_WINDOW);
- send_buf(leader, buf);
- send_buf(leader, "G");
- }
- }
- }
- while (alive && !good);
- }
-
- read_next_card(player, card_to_play, suit_to_play)
- int player, *suit_to_play;
- ptr *card_to_play;
- {
- char good, good_pts, alive, buf[64];
- int t; /* Ignored */
-
- do {
- send_buf(player, "G");
- if (alive = read_card(1 << player, &t, card_to_play, suit_to_play)) {
- good_pts = (((*suit_to_play != SPADES) ||
- ((*card_to_play)->rank != QUEEN))
- && ((*suit_to_play != HEARTS) || only_hearts(player)) ||
- (round != 1));
- good = (((*suit_to_play == trick.suit_led) ||
- (card_table[player].cards[trick.suit_led].length == 0)) && good_pts);
- if (!good) {
- if (!good_pts)
- (void) sprintf(buf, "M%dCan't dump points yet!", TEXT_WINDOW);
- else
- (void) sprintf(buf, "M%dTry following suit!", TEXT_WINDOW);
- send_buf(player, buf);
- send_buf(player, "G");
- }
- }
- }
- while (alive && !good);
- }
-
- int
- num_lower(player, rank, suit_to_play)
- int player, rank, suit_to_play;
- {
- ptr p;
- int mikey;
-
- mikey = 0;
- p = card_table[player].cards[suit_to_play].head->rlink;
- while (p && p->rank) {
- if (p->rank < rank)
- mikey++;
- p = p->rlink;
- }
- return(mikey);
- }
-
- char flushdiamonds(player)
- int player;
- {
- ptr mikey;
-
- mikey = find_card(player,JACK,DIAMONDS);
- if (MIKEYJ && mikey && (mikey->rank == JACK) &&
- (safe_suit(DIAMONDS) || queen_played) &&
- (cards_out(DIAMONDS) > PLAYERS) &&
- ((safe_suit(DIAMONDS) &&
- (card_table[player].cards[DIAMONDS].length >
- ((cards_out(DIAMONDS)/PLAYERS)+2))) ||
- (num_lower(player,JACK,DIAMONDS) >=
- (cards_out(DIAMONDS) - card_table[player].cards[DIAMONDS].length))))
- return(TRUE);
- else
- return(FALSE);
- }
-
- char gotthejack(player)
- int player;
- {
- ptr p,q;
-
- if (card_table[player].cards[DIAMONDS].length > 0)
- p = card_table[player].cards[DIAMONDS].head->rlink;
- else
- p = NULL;
- if (cards_played[DIAMONDS].length > 0)
- q = cards_played[DIAMONDS].head->rlink;
- else
- q = NULL;
-
- if (!((p&&(p->rank == ACE)) || ((q&&(q->rank == ACE)&&
- (not_in_trick(ACE,DIAMONDS))))))
- return(FALSE);
- if ((p&&(p->rank == ACE)))
- p = p->rlink;
- else
- q = q->rlink;
- if (!((p&&(p->rank == KING)) || ((q&&(q->rank == KING)&&
- (not_in_trick(KING,DIAMONDS))))))
- return(FALSE);
- if ((p&&(p->rank == KING)))
- p = p->rlink;
- else
- q = q->rlink;
- if (!((p&&(p->rank == QUEEN)) || ((q&&(q->rank == QUEEN)&&
- (not_in_trick(QUEEN,DIAMONDS))))))
- return(FALSE);
- if ((p&&(p->rank == QUEEN)))
- p = p->rlink;
- else
- q = q->rlink;
- if (p&&(p->rank == JACK))
- return(TRUE);
- else
- return(FALSE);
- }
-
- computer_lead(card_to_play, suit_to_play)
- int *suit_to_play;
- ptr *card_to_play;
- {
- ptr p;
-
- find_queen(leader, &p);
- if (round == 1) {
- /* Lead the 2 of clubs */
- *card_to_play = card_table[leader].cards[CLUBS].tail->llink;
- *suit_to_play = CLUBS;
- } else if (MIKEYJ && gotthejack(leader) &&
- (safe_suit(DIAMONDS) || queen_played)) {
- *card_to_play = find_card(leader,JACK,DIAMONDS);
- *suit_to_play = DIAMONDS;
- } else if (!queen_played && !p && spades_safe(leader) &&
- next_highest(leader,QUEEN,SPADES) &&
- (highest(leader,SPADES)->rank < QUEEN)) {
- /* try and flush the queen out */
- *suit_to_play = SPADES;
- *card_to_play = next_highest(leader, QUEEN, SPADES);
- } else if (flushdiamonds(leader)) {
- *suit_to_play = DIAMONDS;
- if (diamonds_safe(leader) || queen_safe(leader)) {
- *card_to_play = next_highest(leader,JACK,DIAMONDS);
- if (*card_to_play == NULL)
- *card_to_play = highest(leader,DIAMONDS);
- } else {
- *card_to_play = lowest(leader,DIAMONDS);
- if ((*card_to_play)->rank == JACK)
- *card_to_play = highest(leader,DIAMONDS);
- }
- } else {
- find_low_lead(card_to_play, suit_to_play,
- (hearts_broken || only_hearts(leader)));
- }
- }
-
-
- pick_a_loser(player, card_to_play, suit_to_play)
- int player, *suit_to_play;
- ptr *card_to_play;
- {
- ptr p;
-
- if (card_table[player].cards[trick.suit_led].length > 0) {
- *card_to_play = NULL;
- *suit_to_play = trick.suit_led;
- if ((trick.suit_led != SPADES) &&
- (trick.pts == 0) &&
- (!MIKEYJ || jack_played || (trick.suit_led != DIAMONDS) ||
- (((highest(player,DIAMONDS))->rank) < JACK)) &&
- ((trick.card_count == PLAYERS) ||
- (round == 1)))
- /*
- * Play the highest card of suit led if player is last
- * and there are no points in current trick.
- */
- *card_to_play = effective_highest(player, trick.suit_led);
- else
- switch (trick.suit_led) {
- case SPADES:
- if ((trick.card_count == PLAYERS) && (trick.pts == 0)) {
- /*
- * Play the highest spade. Don't play queen if
- * it will win the trick.
- */
- *card_to_play = effective_highest(player, SPADES);
- if (((*card_to_play)->rank == QUEEN) &&
- (QUEEN > trick.highest_played))
- *card_to_play = next_highest(player, QUEEN, SPADES);
- } else {
- find_queen(player,&p);
- if (p && (trick.highest_played > QUEEN))
- *card_to_play = p;
- else
- if (!queen_played &&
- (find_true(hasqs[player]) == FALSE) &&
- (spades_safe(player) ||
- ((highest(player, SPADES)->rank > QUEEN) &&
- (trick.pts < PLAYERS)))) {
- *card_to_play = effective_highest(player, SPADES);
- if ((p == NULL) || (p == *card_to_play))
- *card_to_play =
- next_highest(player,max(trick.highest_played,QUEEN),SPADES);
- }
- }
- break;
-
- case CLUBS:
- if (clubs_safe(player) && (trick.pts <= 0))
- *card_to_play = effective_highest(player, CLUBS);
- break;
-
- case DIAMONDS:
- if (MIKEYJ && (trick.pts < PLAYERS) && (trick.highest_played < JACK) &&
- find_card(player,JACK,DIAMONDS) && queen_safe(player) &&
- ((trick.card_count == PLAYERS) ||
- (find_false(voided[DIAMONDS]) == TRUE) ||
- gotthejack(player))) {
- *card_to_play = find_card(player,JACK,DIAMONDS);
- } else if (MIKEYJ && (trick.pts < 0)) {
- /* dump highest diamond if jd in trick */
- *card_to_play = highest(player,DIAMONDS);
- } else if (MIKEYJ && !jack_played && diamonds_safe(player)) {
- *card_to_play = next_highest(player,JACK,DIAMONDS);
- } else if ((!MIKEYJ || jack_played) && diamonds_safe(player)) {
- *card_to_play = highest(player,DIAMONDS);
- } else if (MIKEYJ && !jack_played && (trick.pts == 0)) {
- *card_to_play = next_highest(player,JACK,DIAMONDS);
- if ((*card_to_play == NULL) && find_card(player,JACK,DIAMONDS))
- *card_to_play = highest(player,DIAMONDS);
- } else if ((next_highest(player, trick.highest_played,
- DIAMONDS) == NULL) &&
- MIKEYJ &&
- ((trick.card_count == PLAYERS) ||
- (find_false(voided[DIAMONDS]) == TRUE)) &&
- find_card(player,JACK,DIAMONDS)) {
- *card_to_play = find_card(player,JACK,DIAMONDS);
- } else if ((next_highest(player, trick.highest_played,
- DIAMONDS) == NULL) &&
- (card_table[player].cards[DIAMONDS].length > 1) &&
- (lowest(player,DIAMONDS)->rank == JACK) &&
- MIKEYJ) {
- *card_to_play = lowest(player,DIAMONDS)->llink;
- }
- break;
-
- case HEARTS:
- break;
- }
-
- if (*card_to_play == NULL)
- *card_to_play = next_highest(player, trick.highest_played,
- *suit_to_play);
-
- if ((*card_to_play == NULL) &&
- (find_false(voided[*suit_to_play]) == TRUE))
- *card_to_play = highest(player, *suit_to_play);
-
- if (*card_to_play == NULL) {
- *card_to_play = card_table[player].cards[trick.suit_led].tail->llink;
- /*
- * Don't play the Q spades if:
- * 1. The Queen is your lowest spade and
- * 2. You have a higher spade.
- */
- if (((*card_to_play)->rank == QUEEN) && (trick.suit_led == SPADES) &&
- (card_table[player].cards[trick.suit_led].length > 1))
- *card_to_play = card_table[player].cards[trick.suit_led].head->rlink;
- }
- if (((*card_to_play)->rank > trick.highest_played) &&
- (*suit_to_play == trick.suit_led) &&
- ((*suit_to_play != SPADES) ||
- ((card_table[player].cards[trick.suit_led].head->rlink)->rank !=
- QUEEN)) &&
- ((trick.card_count == PLAYERS) ||
- (find_false(voided[trick.suit_led]) == TRUE)) &&
- ((*suit_to_play != DIAMONDS) || !MIKEYJ || jack_played))
- *card_to_play = card_table[player].cards[trick.suit_led].head->rlink;
- } else {
- /* void */
- if (round != 1) {
- /*
- * Play the queen of spades if player has it.
- */
- find_queen(player,card_to_play);
- if (*card_to_play)
- *suit_to_play = SPADES;
- if ((*card_to_play == NULL) &&
- !queen_played &&
- (card_table[player].cards[SPADES].length) &&
- ((effective_highest(player,SPADES))->rank > QUEEN)) {
- *card_to_play = effective_highest(player,SPADES);
- *suit_to_play = SPADES;
- }
- if ((*card_to_play == NULL) &&
- (card_table[player].cards[HEARTS].length)) {
- /* MIKEY: does this work? */
- if (someone_is_shooting &&
- (mikeyshooter != NONE) &&
- (mikeyshooter != player)) {
- if ((trick.high_player != mikeyshooter) &&
- trick.played[mikeyshooter].suit)
- *card_to_play = highest(player, HEARTS);
- else
- *card_to_play = next_highest(player, JACK, HEARTS);
- if (*card_to_play == NULL)
- *card_to_play = effective_lowest(player, HEARTS);
- } else if ((mikeyshooter != NONE) &&
- (mikeyshooter != player) &&
- someone_is_shooting &&
- (card_table[player].cards[HEARTS].length > 3)) {
- *card_to_play = highest(player, HEARTS)->rlink;
- } else {
- *card_to_play = effective_highest(player, HEARTS);
- }
- *suit_to_play = HEARTS;
- }
- }
- if (*card_to_play == NULL)
- find_high_card(player, card_to_play, suit_to_play,
- (round != 1),
- (find_card(player,QUEEN,SPADES) != NULL),
- (!MIKEYJ || jack_played));
- }
- }
-
- stop_the_bastard(player, card_to_play, suit_to_play)
- int player, *suit_to_play;
- ptr *card_to_play;
- {
- if (card_table[player].cards[trick.suit_led].length) {
- *suit_to_play = trick.suit_led;
- if ((trick.suit_led == SPADES) && !queen_safe(player)) {
- *card_to_play = next_highest(player, QUEEN, SPADES);
- if (*card_to_play == NULL)
- *card_to_play = effective_lowest(player, SPADES);
- }
- else
- *card_to_play = effective_highest(player, trick.suit_led);
- if ((trick.pts < PLAYERS) &&
- !(((cards_out(trick.suit_led) <
- (PLAYERS - player_count)) ||
- trick.any_hearts) &&
- ((*card_to_play)->rank > trick.highest_played) &&
- (mikeyshooter == trick.high_player)))
- *card_to_play = effective_lowest(player, trick.suit_led);
- }
- else
- if ((mikeyshooter != trick.high_player) &&
- (mikeyshooter != NONE) &&
- someone_is_shooting &&
- (card_table[player].cards[HEARTS].length > 0)) {
- *card_to_play = effective_highest(player, HEARTS);
- *suit_to_play = HEARTS;
- }
- else
- find_low_card(player, card_to_play, suit_to_play);
- }
-
- computer_pick(player, card_to_play, suit_to_play)
- int player, *suit_to_play;
- ptr *card_to_play;
- {
- *card_to_play = NULL;
-
- /* MIKEY: computer too stupid to shoot */
- if (someone_is_shooting && (player == mikeyshooter))
- someone_is_shooting = FALSE;
-
- if (someone_is_shooting && (player != mikeyshooter))
- stop_the_bastard(player, card_to_play, suit_to_play);
- else
- pick_a_loser(player, card_to_play, suit_to_play);
- }
-
- lead(leader)
- int leader;
- {
- int suit_to_play;
- ptr card_to_play;
- char buf[BUF_SIZE];
-
- if (card_table[leader].player_kind == HUMAN) {
- (void) sprintf(buf, "M%dYour lead:", LEAD_WINDOW);
- send_buf(leader, buf);
- read_lead(leader, &card_to_play, &suit_to_play);
- }
- if (card_table[leader].player_kind != HUMAN) /* If player left */
- computer_lead(&card_to_play, &suit_to_play);
- show_lead(card_to_play, suit_to_play);
- }
-
- play_next_card(player)
- int player;
- {
- int suit_to_play;
- ptr card_to_play;
- char buf[BUF_SIZE];
-
- if (card_table[player].player_kind == HUMAN) {
- (void) sprintf(buf, "M%dYour play:", LEAD_WINDOW);
- send_buf(player, buf);
- read_next_card(player, &card_to_play, &suit_to_play);
- }
- if (card_table[player].player_kind != HUMAN) /* If player left */
- computer_pick(player, &card_to_play, &suit_to_play);
-
- if (suit_to_play != trick.suit_led) {
- int each;
-
- voided[trick.suit_led][player] = TRUE;
- if (trick.suit_led == SPADES) {
- for (each=1; each<=PLAYERS; each++) {
- hasqs[each][player] = FALSE;
- }
- }
- } else if ((card_to_play->rank >= JACK) && (trick.pts > 0) &&
- (trick.card_count != PLAYERS)) {
- voided[suit_to_play][player] = MAYBE;
- }
- if ((suit_to_play == trick.suit_led) &&
- (suit_to_play == DIAMONDS) &&
- (card_to_play->rank > JACK) &&
- !jack_played) {
- voided[DIAMONDS][player] = MAYBE;
- }
-
- if (trick.suit_led == SPADES &&
- ((suit_to_play != SPADES) ||
- ((trick.highest_played > QUEEN) &&
- (card_to_play->rank != QUEEN)))) {
- int each;
-
- for (each=1; each<=PLAYERS; each++) {
- hasqs[each][player] = FALSE;
- }
- }
-
- show(player, card_to_play, suit_to_play);
- }
-
- find_winner(winner)
- int *winner;
- {
- char mikeyshoot;
- int maxscore, player, possibly_shooting;
-
- #ifdef DEBUG
- for (mikey=1; mikey<=PLAYERS; mikey++) {
- fprintf(fp, "%c%c ", rnames[trick.played[mikey].rank],
- *snames[trick.played[mikey].suit]);
- }
- fprintf(fp, "\n %d ", trick.high_player);
- #endif
-
- *winner = trick.high_player;
- if (trick.any_hearts)
- hearts_broken = TRUE;
- points_played += trick.pts;
- card_table[*winner].pts += trick.pts;
- if (MIKEYJdintrick) {
- MIKEYJder = *winner;
- MIKEYJdintrick = FALSE;
- }
- if ((trick.pts != 0) && (trick.pts != -10))
- if ((mikeyshooter == 0) || (mikeyshooter == *winner))
- mikeyshooter = *winner;
- else
- mikeyshooter = NONE;
-
- possibly_shooting = ((mikeyshooter != NONE) && (mikeyshooter != 0));
- if (MIKEYJ && jack_played && !queen_played)
- someone_is_shooting = (possibly_shooting &&
- (card_table[*winner].pts >= HEARTS_PANIC-10));
- else if (!jack_played && queen_played)
- someone_is_shooting = (possibly_shooting &&
- (card_table[*winner].pts >= HEARTS_PANIC+13));
- else
- someone_is_shooting = (possibly_shooting &&
- (card_table[*winner].pts >= HEARTS_PANIC));
-
- /* or if lead void */
- trick.card_count = 1;
- if ((*winner == leader) &&
- (find_false(voided[trick.suit_led]) == TRUE))
- someone_is_shooting = possibly_shooting;
-
- mikeyshoot = TRUE;
- maxscore = 0;
- for (player = 1; player <= PLAYERS; player++) {
- if ((maxscore != 0) && (card_table[player].pts != 0))
- mikeyshoot = FALSE;
- if ((card_table[player].pts != 0) &&
- (card_table[player].pts != -10) &&
- (maxscore == 0)) {
- maxscore = card_table[player].pts;
- }
- }
- someone_is_shooting = someone_is_shooting && mikeyshoot;
- }
-
-
- main()
- {
- int player;
- int mikeytemp;
-
- init();
- new_game();
-
- if (debug)
- human_type = VOYEUR;
- else
- #ifdef DEBUG
- human_type = VOYEUR;
- #else
- human_type = HUMAN;
- #endif
-
- if (debug)
- mikeytemp = 100;
- else
- mikeytemp = PLAYERS;
-
- get_first_player();
- add_player();
-
- #ifdef DEBUG
- fp = fopen("hearts.log", "w");
- if (fp == NULL) {
- fprintf(stderr, "Can't open file hearts.log for writing\n");
- exit(1);
- }
- for (mikeytemp=3; mikeytemp<=3; mikeytemp++) {
- #else
- for (;;) {
- #endif
- for (hand = 1; hand <= mikeytemp; hand++) {
- int mikey;
-
- #ifdef DEBUG
- fprintf(fp,"\n--- New Hand ---\n ");
- #endif
- for(mikey = 1;mikey <= PLAYERS;mikey++) {
- trick.played[mikey].rank = 0;
- trick.played[mikey].suit = 0;
- }
- round = 0;
- new_hand();
- if (hand != PLAYERS)
- pass_cards();
- find_low_club(&leader);
- for (mikey=1; mikey<=PLAYERS; mikey++) {
- if (find_card(mikey,QUEEN,SPADES)) {
- int each;
-
- for (each=1; each<=PLAYERS; each++) {
- hasqs[mikey][each] = (each == mikey);
- }
- }
- }
- for (round = 1; round <= NCARDS; round++) {
- new_round();
- lead(leader);
- for (player_count = 1; player_count <= PLAYERS - 1; player_count++)
- play_next_card(map_player(leader, player_count));
- find_winner(&leader);
- send_all_totals();
- }
- send_all_winner();
- #ifndef DEBUG
- if (!debug)
- for (player = 1; player <= PLAYERS; player++)
- if (card_table[player].player_kind == VOYEUR) {
- card_table[player].player_kind = HUMAN;
- player_mask |= 1 << player;
- }
- #endif
- }
- send_all_totals();
- send_final_winner();
- send_to_all("X");
- new_game();
- }
- #ifdef DEBUG
- fclose(fp);
- #endif
- }
-