|
|
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);
}
}