|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T b
Length: 17979 (0x463b) Types: TextFile Names: »bidding.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Bidding/bidding.c«
/* bidding.c */ /* Bridge Bidder Version 3.0 by John Oswalt and Nathan Glasser ..!sun!megatest!jao (usenet) nathan@brokaw.lcs.mit.edu (internet) nathan@mit-eddie.uucp (usenet) June, 1989 ------------------------------------------------------------------------------ Copyright 1988, 1989 by Nathan Glasser and John Oswalt. You may feel free to distribute this program in its current form. Please do not remove this copyright information. */ #include "bidding.h" char *vuln_relative[] = {"Your side","Other side"}; char *vuln_absolute[] = {"1st side","2nd side","Neither side","Both sides"}; char *suit_strings[4] = {"Spades","Hearts","Diamonds","Clubs"}; char *vuln_format[2][2] = { {"Declarer side","Defender side"}, {"North/South","East/West"}}; char seperator[] = "\n---------------------------------------------------------------------\n\n"; #define PASSED_OUT(pdeal) \ ((pdeal)->num_bids == 4 && (pdeal)->bids->bid.suit == PASS) /* Functions used for deal qualification */ extern int twoclubq(), twoclub1stq(), threentq(), twontq(), flanneryq(), longsuitq(), losersq(), flannery1stq(), voidhandsq(), totalvoidsq(), fitq(), doublefitq(), misfitq(), badmisfitq(); wildq(), goulash(), experimentq(), onentq(); extern int default_predeal(), experiment_predeal(); struct deal_type deal_types[] = { {"2clubs",default_predeal,twoclubq,-1, ": Someone has at least game - 1 trick (but not a 2NT hand)."}, {"2clubs1st",default_predeal,twoclub1stq,-1, ": Dealer has at least game - 1 trick (but not a 2NT hand)."}, {"goulash",default_predeal,goulash,-1, ": Hands delt normally, sorted, cut, and redelt 5-5-3."}, {"3nt",default_predeal,threentq,-1, ": Someone has a 7 or 8 card minor to AKQ with no outside A or K."}, {"2nt",default_predeal,twontq,-1, ": Someone has a 20-21 HCP hand with no 5 card major,\n\ \tno 6 card minor, no singleton, and no void."}, {"1nt",default_predeal,onentq,-1, ": Someone has a 15-17 HCP hand with no 5 card major,\n\ \tno 6 card minor, no singleton, and no void."}, {"misfit",default_predeal,misfitq,-1, ": All fits are 6 or 7 cards."}, {"flannery",default_predeal,flanneryq,-1, ": Someone has 5 hearts, 4 spades, and 11-15 HCP."}, {"flannery1st",default_predeal,flannery1stq,-1, ": Dealer has 5 hearts, 4 spades, and 11-15 HCP."}, {"longsuit",default_predeal,longsuitq,13, " N: Someone's longest suit is N cards long."}, {"losers",default_predeal,losersq,12, " N: Someone has exactly N losers."}, {"voidhands",default_predeal,voidhandsq,4, " N: N hands contain at least 1 void."}, {"totalvoids",default_predeal,totalvoidsq,12, " N: There are N voids in the deal."}, {"fit",default_predeal,fitq,13, " N: At least 1 partnership has exactly N cards in some suit."}, {"doublefit",default_predeal,doublefitq,26, " N: At least 1 partnership has exactly N cards in two suits."}, {"badmisfit",default_predeal,badmisfitq,26, "N: For at least 1 hand the following is true:\n\ \tLet A and B be two suits, and misfit(x) be the total cards\n\ \tof suit x contained in the hand and in some opponent's\n\ \thand. Misfit(A) + Misfit(B) >= N for some A and B."}, {"wild",default_predeal,wildq,0, ": Equal parts of 2clubs, 2nt, flannery1st, longsuit 8, losers 3,\n\ \ttotalvoids 2, doublefit 19, badmisfit 20, 3nt, and goulash."}, {"experiment",experiment_predeal,experimentq,-1, ": Uses custom code in exper.c to generate and qualify\n\ \tdeals. See exper.doc and exper.c."}, }; #define NUM_DEAL_TYPES (sizeof(deal_types) / sizeof(struct deal_type)) PFI predeal = default_predeal; deal *deals; int totaltried = 0; int totalfound = 0; PFI handqfunc = (PFI)NULL; int handqparm; int cardsused[52]; int hand_setup[4]; int cardsleft; int num_deals; int dobidding = 1; main(argc,argv) int argc; char **argv; { int i,j; int num_deals_left; int deal_num; int origargc = argc; char **origargv = argv; if (argc < 2) { usage(argv[0]); exit(0); } while (argc--, (++argv)[0][0] == '-') switch (argv[0][1]) { case 'l': case 'L': list_dealtypes(); exit(0); case 'd': case 'D': dobidding = 0; break; default: printf("Unknown option: %s.\n",argv[0]); exit(1); } num_deals = atoi((argv++)[0]); argc--; /* Handle a deal_type. Look up the name in the table. If we find it there, then we may have to process a parameter. A param_max value of < 0 means it takes no parameter. A parameter of 0 means that it takes no parameter, but the function is automatically given num_deals as its parameter. A positive value means that it takes a parameter, which must be positive and is not allowed to exceed that value. */ if (argc) { for (i = NUM_DEAL_TYPES - 1; i >= 0; i--) if (!strcmp(argv[0],deal_types[i].deal_name)) { predeal = deal_types[i].predeal_func; handqfunc = deal_types[i].hand_func; if (deal_types[i].param_max == 0) handqparm = num_deals; else if (deal_types[i].param_max > 0) { if (argc < 2) { printf("Missing required parameter.\n"); exit(1); } if ((handqparm = atoi(argv[1])) < 1 || handqparm > deal_types[i].param_max) { printf("Parameter %d not in the range 1-%d.\n", handqparm,deal_types[i].param_max); exit(1); } } break; } if (i < 0) { printf("Unknown deal_type %s.\n",argv[0]); exit(1); } } printf("Dealing %d hand%s...\n",num_deals_left = num_deals, num_deals == 1 ? "" : "s"); deals = (deal *)malloc(num_deals * sizeof(deal)); srandom((unsigned)time(NULL)); for (i = 0; i < num_deals; i++) deal_qualified(i); write_log_header(origargc,origargv); if (!dobidding) { bid tmp; tmp.bid.suit = PASS; /* Make it look like all hands were passed out so that print_complete_deal will work right. Kludge. */ for (i = 0; i < num_deals; i++) { deals[i].num_bids = 4; deals[i].bids = &tmp; } write_deals(); printf("All dealing complete.\n"); exit(0); } /* Accept bids */ while (num_deals_left) { deal_num = random() % num_deals; if (deals[deal_num].bidding_done) continue; clear_screen(); for (;;) { print_bidding(stdout,&deals[deal_num],deals[deal_num].num_bids, BIDDING); printf("Your hand (%s vulnerable):\n", (deals[deal_num].vulnerability <= RELATIVE) ? vuln_relative[(deals[deal_num].num_bids & 1) ^ deals[deal_num].vulnerability] : vuln_absolute[deals[deal_num].vulnerability]); print_hand(stdout, deals[deal_num].hands[deals[deal_num].num_bids % 4]); if (!accept_bid(&deals[deal_num])) break; printf("Bad bid.\n\n"); } if (deals[deal_num].bidding_done) { num_deals_left--; /* If hand was passed out */ if (PASSED_OUT(&deals[deal_num])) display_complete_deal(&deals[deal_num],1); } } /* Accept opening leads */ for (deal_num = 0; deal_num < num_deals; deal_num++) { /* Make sure hand wasn't passed out */ if (PASSED_OUT(&deals[deal_num])) continue; clear_screen(); j = figure_out_leader(&deals[deal_num]); for (;;) { print_bidding(stdout,&deals[deal_num],j,LEADING); printf("Your hand (%s vulnerable):\n", (deals[deal_num].vulnerability <= RELATIVE) ? vuln_relative[(j & 1) ^ deals[deal_num].vulnerability] : vuln_absolute[deals[deal_num].vulnerability]); print_hand(stdout,deals[deal_num].hands[j]); if (!get_lead(&deals[deal_num],j)) break; printf("Bad lead.\n\n"); } display_complete_deal(&deals[deal_num],((j + 1) % 4)); } printf("All bidding complete.\n"); } display_complete_deal(pdeal,top_hand) deal *pdeal; int top_hand; { print_complete_deal(stdout,pdeal,top_hand); more(); log_deal(pdeal,top_hand); } print_complete_deal(fp,pdeal,top_hand) FILE *fp; deal *pdeal; int top_hand; { int i; char top_h[4][80],left_h[4][80],right_h[4][80],bottom_h[4][80]; format_hand(top_h,pdeal->hands[top_hand]); format_hand(right_h,pdeal->hands[(top_hand + 1) % 4]); format_hand(bottom_h,pdeal->hands[(top_hand + 2) % 4]); format_hand(left_h,pdeal->hands[(top_hand + 3) % 4]); fprintf(fp,"\t\tComplete deal (%s vulnerable):\n", ((pdeal->vulnerability <= RELATIVE) ? vuln_format[PASSED_OUT(pdeal)][(top_hand & 1) ^ pdeal->vulnerability] : vuln_absolute[pdeal->vulnerability])); for (i = 0; i < 4; i++) fprintf(fp,"\t\t\t%s\n",top_h[i]); for (i = 0; i < 4; i++) fprintf(fp,"%-43s%s\n",left_h[i],right_h[i]); for (i = 0; i < 4; i++) fprintf(fp,"\t\t\t%s\n",bottom_h[i]); } print_bidding(fp,pdeal,your_position,status) FILE *fp; deal *pdeal; int your_position; int status; { bid *bids; static char *bid_suits[] = {"S","H","D","C","NT","DB","RD","P"}; static char *bid_labels[] = {"*You*","LHO","Partner","RHO"}; #ifdef LISTING_FIRST_COL static char *lead_labels[] = {"*You*","Dummy","Partner","Declarer"}; #endif #ifdef LISTING_ANY_COL static char *lead_labels[] = {"*You*","Dummy","Partner","Decl."}; #endif static char *passed_labels[] = {"West","North","East","South"}; char **labels; int bid_num; int i; int lastnum; if (status == BIDDING) labels = bid_labels; else if (status == PASSING) labels = passed_labels; else if (status == LEADING) labels = lead_labels; your_position = your_position % 4; putc('\t',fp); for (i = 0; i < 4; i++) #ifdef LISTING_FIRST_COL fprintf(fp,"\t%s",labels[i]); #endif #ifdef LISTING_ANY_COL fprintf(fp,"\t%s",labels[(i + 4 - your_position) % 4]); #endif fprintf(fp,"\nBidding:\t--------------------------------\n"); #ifdef LISTING_FIRST_COL bid_num = (4 - your_position) % 4; if (bid_num) putc('\t',fp); for (i = 0; i < bid_num; i++) fprintf(fp,"\t-"); lastnum = bid_num + pdeal->num_bids; #endif #ifdef LISTING_ANY_COL bid_num = 0; lastnum = pdeal->num_bids; #endif for (bids = pdeal->bids; bid_num < lastnum; bids = bids->next) { if ((bid_num % 4) == 0) putc('\t',fp); if (bids->bid.suit <= RANK_USED) fprintf(fp,"\t%d%s",bids->bid.rank,bid_suits[bids->bid.suit]); else fprintf(fp,"\t%s",bid_suits[bids->bid.suit]); if ((++bid_num % 4) == 0) putc('\n',fp); } #ifdef LISTING_FIRST_COL if (status == BIDDING) fprintf(fp,"\t\t?\n\n"); else { #endif putc('\n',fp); if (bid_num % 4) putc('\n',fp); #ifdef LISTING_FIRST_COL } #endif } accept_bid(pdeal) deal *pdeal; { int ch; int rank = -1,suit; bid *newbid; static int suit_cvt[] = {3,2,1,0,4}; bid *tmp; int i; printf("\nEnter your bid: "); /* Get optional rank */ while (isspace(ch = getchar())); if (isdigit(ch)) { rank = ch - '0'; while (isspace(ch = getchar())); } /* Get suit, notrump, pass, double, or redouble */ if (islower(ch)) ch = toupper(ch); switch (ch) { case 'S': suit = SPADES; break; case 'H': suit = HEARTS; break; case 'D': suit = (rank >= 0) ? DIAMONDS : DOUBLE; break; case 'C': suit = CLUBS; break; case 'N': suit = NOTRUMP; break; case 'P': suit = PASS; break; case 'R': suit = REDOUBLE; break; default: suit = -1; break; } while (getchar() != '\n'); if (suit < 0) return(1); /* Make sure numerical bid is ok */ if (suit <= RANK_USED) { if (rank < 1 || rank > 7) { char tmp[10]; printf("Do you wish to restart the bidding for this hand? "); fgets(tmp,10,stdin); if (tmp[0] != 'y' && tmp[0] != 'Y') return(1); pdeal->num_bids = 0; pdeal->bids = NULL; return(0); } if (pdeal->num_bids > 0) for (tmp = pdeal->bids->prev, i = pdeal->num_bids; i; tmp = tmp->prev, i--) if (tmp->bid.suit <= RANK_USED) { if (rank < tmp->bid.rank || rank == tmp->bid.rank && suit_cvt[suit] <= suit_cvt[tmp->bid.suit]) return(1); break; } } /* Make sure double or redouble is valid */ else if (suit == DOUBLE || suit == REDOUBLE) { if (pdeal->num_bids <= 0) return(1); for (tmp = pdeal->bids->prev, i = pdeal->num_bids; i; tmp = tmp->prev, i--) if (tmp->bid.suit != PASS) { /* Double or redouble by wrong side */ /* The person bidding in the num_bids position was an opponent. The last valid bidder must have had this parity. */ if (((i ^ pdeal->num_bids) & 1) == 1) return(1); /* Double of a double or redouble */ if (suit == DOUBLE && tmp->bid.suit > RANK_USED) return(1); /* Redouble of a bid other than double */ if (suit == REDOUBLE && tmp->bid.suit != DOUBLE) return(1); break; } /* Double or redouble as first non-pass bid */ if (!i) return(1); } newbid = (bid *)malloc(sizeof(bid)); newbid->bid.rank = rank; newbid->bid.suit = suit; if (++(pdeal->num_bids) == 1) newbid->next = newbid->prev = pdeal->bids = newbid; else { (newbid->next = pdeal->bids)->prev = (newbid->prev = pdeal->bids->prev)->next = newbid; if (newbid->bid.suit == PASS && newbid->prev->bid.suit == PASS && newbid->prev->prev->bid.suit == PASS && pdeal->num_bids >= 4) pdeal->bidding_done = 1; } return(0); } more() { printf("---Hit return to continue---"); while (getchar() != '\n'); } log_deal(pdeal,top_hand) deal *pdeal; int top_hand; { FILE *fp; int i; if ((fp = fopen(LOGFILE,"a")) == NULL) { perror(LOGFILE); return; } print_bidding(fp,pdeal,top_hand + 7, ((PASSED_OUT(pdeal)) ? PASSING : LEADING)); if (pdeal->opening_lead.suit >= 0) fprintf(fp,"Opening lead: %c of %s\n\n",pdeal->opening_lead.rank, suit_strings[pdeal->opening_lead.suit]); print_complete_deal(fp,pdeal,top_hand); fprintf(fp,seperator); fclose(fp); } write_deals() { FILE *fp; int i; if ((fp = fopen(LOGFILE,"a")) == NULL) { perror(LOGFILE); return; } for (i = 0; i < num_deals; i++) { print_complete_deal(fp,&deals[i],1); fprintf(fp,seperator); } fclose(fp); } figure_out_leader(pdeal) deal *pdeal; { int contract_maker; bid *finalsuit,*tmp; int suit_bidder; /* Find out which bid specified the basic contract */ for (contract_maker = pdeal->num_bids - 1, finalsuit = pdeal->bids->prev; contract_maker >= 0 && finalsuit->bid.suit > RANK_USED; contract_maker--, finalsuit = finalsuit->prev); if (contract_maker < 0) return(-1); /* Reduce this to a single side */ contract_maker &= 1; /* Find the first player of this side to bid this suit. */ suit_bidder = contract_maker; tmp = (suit_bidder) ? pdeal->bids->next : pdeal->bids; while (tmp->bid.suit != finalsuit->bid.suit) { suit_bidder += 2; tmp = tmp->next->next; } return((suit_bidder + 1) % 4); } get_lead(pdeal,handnum) deal *pdeal; int handnum; { int rank,suit,i; char *tmp; static char valid_ranks[] = "23456789TJQKA"; static char valid_suits[] = "SHDC"; printf("\nEnter your opening lead: "); /* Get rank */ while (isspace(rank = getchar())); /* Get suit */ while (isspace(suit = getchar())); if (islower(rank)) rank = toupper(rank); if (index(valid_ranks,rank) == NULL) { if (rank == '1' && suit == '0') { rank = 'T'; /* Get suit again */ while (isspace(suit = getchar())); } else rank = -1; } if (islower(suit)) suit = toupper(suit); if ((tmp = index(valid_suits,suit)) == NULL) suit = -1; while (getchar() != '\n'); if (rank < 0 || suit < 0) return(1); pdeal->opening_lead.rank = rank; pdeal->opening_lead.suit = tmp - valid_suits; /* Check to see if it's in the hand */ for (i = 0; i < 13; i++) if (pdeal->hands[handnum][i].suit == pdeal->opening_lead.suit && valid_ranks[pdeal->hands[handnum][i].rank - 2] == pdeal->opening_lead.rank) return(0); return(1); } clear_screen() { #ifdef SCREEN_CLEAR_SIZE int i; for (i = 0; i < SCREEN_CLEAR_SIZE; i++) putchar('\n'); #else putchar('\f'); #endif } write_log_header(argc,argv) int argc; char **argv; { FILE *fp; int i; if ((fp = fopen(LOGFILE,"a")) == NULL) { perror(LOGFILE); return; } fprintf(fp,"** "); for (i = 0; i < argc; i++) fprintf(fp,"%s ",argv[i]); fprintf(fp,"**"); fprintf(fp,"\n\n"); fclose(fp); } /* * Keep dealing cards into deal i until it qualifies according to handqfunc(). * If there is no handqfunc(), then it automaticaly qualifies. */ deal_qualified(i) int i; { int keepdealing = 1; do { (*predeal)(&deals[i]); deal_hands(&deals[i]); if ((++totaltried % 1000) == 0) printf("%d/%d\n",totalfound,totaltried); if (handqfunc && (*handqfunc)(&deals[i],handqparm)) keepdealing = 0; } while (keepdealing && handqfunc); totalfound++; printf("%d/%d\n",totalfound,totaltried); } usage(program) char *program; { printf("Bridge Bidder version 3.0 by John Oswalt and Nathan Glasser\n"); printf("Usage: %s [-l] [-d] number_of_deals [deal_type [parameter]]\n", program); printf("\t-l = list deal types\n"); printf("\t-d = deal hands without bidding; save in the log file only\n"); } list_dealtypes() { int i; printf("\t\t\tImplemented deal_type's:\n\n"); for (i = 0; i < NUM_DEAL_TYPES; i++) { if ((i + 1) % 10 == 0) more(); printf("%s%s\n",deal_types[i].deal_name,deal_types[i].description); } }