home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
games
/
volume13
/
okbridge
/
part04
/
input.c.ab
Wrap
Text File
|
1992-01-12
|
31KB
|
1,106 lines
static int Reserved_message (message)
char *message;
/* Compares the given message to the list of card and bid names. If a
match is found, then returns true. Otherwise, returns false.
*/
{
char compare_buff[100], *ch;
int i;
if (!strlen(message))
return (1);
strcpy (compare_buff, message);
ch = compare_buff;
for (ch = compare_buff; *ch != '\0'; ch++)
*ch = toupper(*ch);
for (i=0; i < 52; i++)
if (!strcmp(card_names[i], compare_buff))
return (1);
for (i=0; i < 38; i++)
if (!strcmp(bid_names[i], compare_buff))
return (1);
return (0);
};
static load_email_file (filename)
char *filename;
/* Attempts to read a sequence of deals from the email duplicate file
. with name filename.
*/
{
char msg_buf [80];
total_no_deals = current_deal_no = 0;
current_board = NULL;
if (email_record != NULL)
Free_Email_Duplicate_Struct (email_record);
email_record = NULL;
current_deal_no =
Read_Email_Duplicate_File (filename, &email_record);
if (current_deal_no) {
if (email_record != NULL)
Free_Email_Duplicate_Struct
(email_record);
email_record = NULL;
if (current_deal_no > 0) {
sprintf (msg_buf, "%s %d: %s", "FORMAT ERROR NEAR LINE",
codefile_line_no, email_error_message);
Display_Player_Comment ("MODERATOR", msg_buf);
} else {
sprintf (msg_buf, "%s %s: %s", "ERROR IN READING", filename,
sys_errlist[errno]);
Display_Player_Comment ("MODERATOR", msg_buf);
};
email_record = New_Email_Duplicate_Struct ();
current_deal_no = 0;
replaying_mode = 0;
} else {
total_no_deals = email_record->nboards;
current_board = email_record->board_list;
replaying_mode = 1;
sprintf (msg_buf, "LOADED %d BOARDS FROM %s.",
total_no_deals, filename);
Display_Player_Comment ("MODERATOR", msg_buf);
};
ns_pair_no = Add_Email_Pair (email_record,
player_names[PLAYER_NORTH],
player_names[PLAYER_SOUTH]);
ew_pair_no = Add_Email_Pair (email_record,
player_names[PLAYER_EAST],
player_names[PLAYER_WEST]);
};
static void save_email_file (filename)
char *filename;
{
int error_flag;
char msg_buf[80];
error_flag = Write_Email_Duplicate_File (filename, 1, email_record);
if (error_flag) {
sprintf (msg_buf, "%s %s: %s", "ERROR IN WRITING", filename,
sys_errlist[errno]);
Display_Player_Comment ("MODERATOR", msg_buf);
} else {
sprintf (msg_buf, "WROTE %d %s %s.",
email_record->nboards, "ENCODED BOARDS TO", filename);
Display_Player_Comment ("MODERATOR", msg_buf);
sprintf (msg_buf, "%s.plain", filename);
error_flag = Write_Email_Duplicate_File (msg_buf, 0, email_record);
sprintf (filename,"%s", msg_buf);
if (error_flag) {
sprintf (msg_buf, "%s %s: %s",
"ERROR IN WRITING", filename, sys_errlist[errno]);
Display_Player_Comment ("MODERATOR", msg_buf);
error_flag = 0;
} else {
sprintf (msg_buf, "WROTE %d %s %s.",
email_record->nboards, "UNENCODED BOARDS TO", filename);
Display_Player_Comment ("MODERATOR", msg_buf);
};
};
};
static process_player_command (pc)
player_command pc;
/* Determines whether the player command pc should be handled internally
. by the input module, or whether it should be passed upwards. If it will
. be handled internally, then performs the appropriate action. If it will
. be passed upwards, then places it in an appropriate queue to be handled
. later.
*/
{
char msg_buf[100], *word, *filename;
int mils; /* milliseconds elapsed between ping and echo */
int error_flag;
struct timeval ping_end;
if ((pc->player_no == local_player) && disabled(pc->command)) {
Display_Status ("THIS COMMAND CANNOT BE USED NOW");
return;
};
/*
if ((pc->command != CMD_HELLO) && !players_here[pc->player_no])
return;
*/
switch (pc->command) {
case CMD_ERROR:
break; /* do nothing for erroneous commands. */
case CMD_VULN:
enqueue_command (pc);
break;
case CMD_RDEAL:
enqueue_command (pc);
if ((pc->player_no != local_player) &&
(game_mode != DEALING_MODE)) {
Display_Player_Comment ("MODERATOR",
"THE CARDS HAVE NOW BEEN DEALT.");
};
break;
case CMD_BID:
enqueue_command (pc);
break;
case CMD_PLAY:
enqueue_command (pc);
break;
case CMD_FINISH:
enqueue_command (pc);
break;
case CMD_HELLO:
if (players_here[pc->player_no]) {
sprintf (msg_buf,
"THERE ARE TWO PEOPLE CLAIMING THE SEAT OF %s",
local_player_names [pc->player_no]);
Display_Player_Comment ("MODERATOR", msg_buf);
send_message_talk (msg_buf);
Terminate_Program ("PROGRAM TERMINATING");
};
if (pc->player_no == local_player) {
/* The following statement should never
* be executed: */
break;
} else {
send_message_ack ();
player_names[pc->player_no] =
strdup(pc->data.version_name +
VERSION_LENGTH);
if (strlen(player_names[pc->player_no]) > 8)
player_names[pc->player_no][8] = '\0';
error_flag = verify_compatibility
(pc->player_no, pc->data.version_name);
if (!error_flag) {
sprintf (msg_buf,
"%s HAS JOINED THE GAME AS %s",
player_names[pc->player_no],
local_player_names[pc->player_no]);
Display_Player_Comment ("MODERATOR",
msg_buf);
if (ring_my_bell) ring_bell ();
players_here [pc->player_no] = 1;
}
};
#ifdef TWOPLAYER_MODE
players_here [player_partner[pc->player_no]] = 1;
#endif
break;
case CMD_ACK:
verify_compatibility (pc->player_no,
pc->data.version_name);
player_names[pc->player_no] =
strdup(pc->data.version_name+VERSION_LENGTH);
if (strlen(player_names[pc->player_no]) > 8)
player_names[pc->player_no][8] = '\0';
if (pc->player_no == local_player)
send_message_ack ();
/*
else if (game_mode != STARTUP_MODE) {
sprintf (msg_buf,
"ACKNOWLEDGMENT RECEIVED FROM %s",
player_names[pc->player_no]);
Display_Player_Comment ("MODERATOR", msg_buf);
}
*/
else if (!players_here[pc->player_no]) {
sprintf (msg_buf,
"%s HAS JOINED THE GAME AS %s",
player_names[pc->player_no],
local_player_names[pc->player_no]);
Display_Player_Comment ("MODERATOR", msg_buf);
};
players_here [pc->player_no] = 1;
#ifdef TWOPLAYER_MODE
players_here [player_partner[pc->player_no]] = 1;
#endif
break;
case CMD_TALK:
if (pc->player_no == local_player) {
if (Reserved_message (pc->data.message))
break;
send_message_talk (pc->data.message);
};
Display_Player_Comment (player_names[pc->player_no],
pc->data.message);
players_here [pc->player_no] = 1;
break;
case CMD_COMMENT:
Display_Player_Comment ("MODERATOR", pc->data.message);
break;
case CMD_QUIT:
if (pc->player_no == local_player)
Quit_program ();
else {
sprintf (msg_buf, "%s HAS QUIT.",
player_names[pc->player_no]);
Display_Player_Comment ("MODERATOR",
msg_buf);
if (game_mode == STARTUP_MODE)
players_here[pc->player_no] = 0;
Close_Network_Connection
(local_player_names[pc->player_no]);
};
/* soft_abort (); */
break;
case CMD_HELP:
display_help (pc->data.topic);
Refresh_Display ();
break;
case CMD_BELL:
if (pc->data.bell == 0) ring_my_bell = 0;
if (pc->data.bell == 1) ring_my_bell = 1;
if (ring_my_bell) word = "ON";
else word = "OFF";
sprintf (msg_buf, "THE BELL IS NOW %s", word);
Display_Player_Comment ("MODERATOR", msg_buf);
if (ring_my_bell) ring_bell ();
break;
case CMD_DEFAULT:
if (pc->data.defaalt == 0) default_plays = 0;
if (pc->data.defaalt == 1) default_plays = 1;
if (default_plays) word = "ON";
else word = "OFF";
sprintf (msg_buf, "DEFAULT INPUT MODE IS NOW %s",
word);
Display_Player_Comment ("MODERATOR", msg_buf);
break;
case CMD_REVIEW:
Review_Bidding ();
break;
case CMD_PROMPT:
if (pc->data.prompt == 0) prompt_dummy = 0;
if (pc->data.prompt == 1) prompt_dummy = 1;
if (prompt_dummy) word = "WILL";
else word = "WILL NOT";
sprintf (msg_buf,
"THE DUMMY %s BE PROMPTED AFTER EACH TRICK",
word);
Display_Player_Comment ("MODERATOR", msg_buf);
break;
case CMD_PING:
if (pc->player_no == local_player) {
gettimeofday (&ping_start, NULL);
send_message_ping ();
} else
send_message_echo (pc->player_no);
break;
case CMD_ECHO:
players_here[pc->player_no] = 1;
if (pc->data.ping_source == local_player) {
gettimeofday (&ping_end, NULL);
mils = (ping_end.tv_sec - ping_start.tv_sec)
* 1000;
mils += ping_end.tv_usec / 1000;
mils -= ping_start.tv_usec / 1000;
sprintf (msg_buf,
"ECHO RECEIVED FROM %-10s IN %7.2f SECONDS",
player_names[pc->player_no],
((float) mils) * 0.001);
Display_Player_Comment ("MODERATOR", msg_buf);
};
break;
case CMD_CLAIM:
if (pc->player_no == local_player)
process_claim_offer (pc->data.tricks);
else if (local_player != dummy)
process_claim_response (pc->data.tricks);
break;
case CMD_RESP:
claim_responses++;
if (!pc->data.response) {
/*
sprintf (msg_buf,
"THE CLAIM OFFER WAS DECLINED BY %s",
player_names[pc->player_no]);
*/
if (!claim_rejected) {
sprintf (msg_buf,
"THE CLAIM OFFER WAS DECLINED.");
Display_Player_Comment ("MODERATOR", msg_buf);
};
claim_rejected = 1;
};
break;
case CMD_SCORE:
scoring_mode_known = 1;
scoring_mode = pc->data.scoring;
switch (scoring_mode) {
case RUBBER_SCORING:
Display_Player_Comment ("MODERATOR",
"WE ARE PLAYING RUBBER BRIDGE.");
break;
case CHICAGO_SCORING:
Display_Player_Comment ("MODERATOR",
"WE ARE PLAYING CHICAGO BRIDGE.");
break;
case DUPLICATE_SCORING:
Display_Player_Comment ("MODERATOR",
"WE ARE PLAYING DUPLICATE BRIDGE.");
break;
case EMAIL_SCORING:
Display_Player_Comment ("MODERATOR",
"WE ARE PLAYING EMAIL DUPLICATE BRIDGE.");
break;
case IMP_SCORING:
Display_Player_Comment ("MODERATOR",
"WE ARE PLAYING IMP BRIDGE.");
break;
};
break;
case CMD_LOG:
if (pc->data.filename[0] == '\0') {
if (logfile == NULL)
Display_Player_Comment ("MODERATOR",
"THERE IS NO OPEN LOGFILE.");
else {
fclose (logfile);
logfile = NULL;
Display_Player_Comment ("MODERATOR",
"THE LOG FILE HAS BEEN CLOSED.");
};
} else {
if (logfile != NULL) fclose (logfile);
if (pc->data.filename[0] == '+') {
filename = pc->data.filename + 1;
logfile = fopen (filename, "a");
} else {
filename = pc->data.filename;
logfile = fopen (filename, "w");
};
if (logfile == NULL) {
sprintf (msg_buf, "%s ERROR OPENING %s",
sys_errlist[errno], filename);
Display_Player_Comment ("MODERATOR", msg_buf);
} else {
sprintf (msg_buf, "NOW LOGGING TO %s",
filename);
Display_Player_Comment ("MODERATOR", msg_buf);
};
};
break;
case CMD_DEAL:
total_no_deals = pc->data.nhands;
current_deal_no = 0;
if (email_record != NULL)
Free_Email_Duplicate_Struct (email_record);
email_record = New_Email_Duplicate_Struct ();
ns_pair_no = Add_Email_Pair (email_record,
player_names[PLAYER_NORTH],
player_names[PLAYER_SOUTH]);
ew_pair_no = Add_Email_Pair (email_record,
player_names[PLAYER_EAST],
player_names[PLAYER_WEST]);
if (total_no_deals < 0)
Display_Player_Comment ("MODERATOR",
"ENTERING CONTINUOUS DEAL MODE.");
else {
sprintf (msg_buf, "%s %d DEALS.",
"BEGINNING A SEQUENCE OF",
total_no_deals);
Display_Player_Comment ("MODERATOR", msg_buf);
};
replaying_mode = 0;
current_board = NULL;
break;
case CMD_LOAD:
load_email_file (pc->data.filename);
break;
case CMD_SAVE:
save_email_file (pc->data.filename);
break;
case CMD_REPLAY:
load_email_file (pc->data.filename);
if (replaying_mode)
autosave_file = strdup (pc->data.filename);
break;
default:
sprintf (msg_buf, "PLAYER %d, CODE %d\n",
pc->player_no, pc->command);
Display_Player_Comment ("INTERNAL ERROR!", msg_buf);
};
};
static player_input (rmt_player, ib, default_command)
int rmt_player; input_buffer ib; char *default_command;
/* This procedure monitors the network and the keyboard simultaneously,
. waiting for a command to arrive. The local player is free to type at the
. keyboard, placing characters into the buffer ib. When he presses
. enter, a command is issued. By default, the command which is issued
. is obtained by concatenating the player's input to the string given
. in default command. However, if the player's command begins with a
. slash '/', then it is interpreted directly as the command. The exit
. condition for this procedure is determined by the input value of player.
. If player = -1, then the procedure exits as soon as any kind of message
. is received. If player is in the range 0..3, then the procedure exits
. only when a play is received from the corresponding player. No other
. values for player are valid.
*/
{
struct player_command_struct pcs;
char command_buf[100];
int polling;
/* Clear_Status_Display(); */
print (ib->row, 1, default_command);
update_input_buffer (ib, '\0');
if (rmt_player < 0)
polling = 1;
else if (rmt_player < 4)
polling = !command_available(rmt_player);
polling = 1;
while (polling) {
if (message_available()) {
receive_player_command (&pcs);
if (pcs.player_no >= 0) {
process_player_command (&pcs);
polling = 0;
};
};
if (char_avail()) {
if (update_input_buffer(ib, input_char())) {
Clear_Status_Display ();
pcs.player_no = local_player;
if (ib->buf[0] == '/')
ps_copy (command_string, ib->buf+1);
else {
sprintf (command_buf, "%s %s",
default_command, ib->buf);
ps_copy (command_string, command_buf);
};
clear_input_buffer (ib);
parse_player_command (command_string, &pcs);
if (pcs.command == CMD_ERROR)
Display_Status (parsing_errmsg);
else {
process_player_command (&pcs);
polling = 0;
};
update_input_buffer (ib, '\0');
};
};
if ((3 >= rmt_player) && (rmt_player >= 0))
polling = !command_available(rmt_player);
};
};
static input_remote_play (rmt_player, play, pc)
int rmt_player; long play; player_command pc;
/* As input, receives the index of a remote player as rmt_player and
. a bit string of allowable plays as play. Waits for the specified
. player to make one of the plays listed in the bit string play.
. If we receive any other type of play, then an error message is
. generated. Otherwise, creates the play into the structure pc.
*/
{
char error_message [100];
int waiting;
waiting = 1;
while (waiting) {
if (QUEUE_EMPTY(rmt_player))
player_input (rmt_player, talk_buffer, "TALK ");
dequeue_command (rmt_player, pc);
if (pc != NULL) {
if (pc->command & play)
waiting = 0;
else {
sprintf (error_message,
"EXPECTING PLAY %ld FROM %d; RECEIVED PLAY %ld",
play, rmt_player, pc->command);
Display_Player_Comment ("NETWORK ERROR",
error_message);
};
};
};
};
Initialize_Input_Buffers ()
/* Establishes and initializes the buffers that are used for reading
. input from the terminal.
*/
{
talk_buffer=(input_buffer) malloc (sizeof(struct input_buffer_struct));
play_buffer=(input_buffer) malloc (sizeof(struct input_buffer_struct));
ask_buffer =(input_buffer) malloc (sizeof(struct input_buffer_struct));
talk_buffer->row = TALK_ROW;
talk_buffer->col = TALK_COL + 6;
talk_buffer->length = TALK_LENGTH - 6;
talk_buffer->pos = 0;
talk_buffer->buf[0] = '\0';
play_buffer->row = PLAY_ROW;
play_buffer->col = PLAY_COL + 6;
play_buffer->length = PLAY_LENGTH - 6;
play_buffer->pos = 0;
play_buffer->buf[0] = '\0';
ask_buffer->row = TALK_ROW + 1;
ask_buffer->col = 0;
ask_buffer->length = 5;
ask_buffer->pos = 0;
ask_buffer->buf[0] = '\0';
email_record = NULL;
};
Initialize_Input ()
/* Initializes the higher-level state of the network connections,
. including doing the initial handshaking with the other players.
*/
{
int i, wait;
char msg_buf[80];
initialize_command_queue();
command_string = ps_alloc (127);
command_disabled = 0;
disable(CMD_RDEAL);
disable(CMD_BID);
disable(CMD_PLAY);
disable(CMD_FINISH);
disable(CMD_HELLO);
disable(CMD_ACK);
disable(CMD_ECHO);
disable(CMD_RESP);
disable(CMD_SCORE);
disable(CMD_CLAIM);
disable(CMD_DEAL);
disable(CMD_LOAD);
enable(CMD_SAVE);
#ifdef LOOPBACK_MODE
for (i = 0; i < 4; i++) players_here[i] = 1; /* DBG */
wait = 0;
#else
for (i = 0; i < 4; i++) players_here[i] = 0;
players_here[local_player] = 1;
wait = 1;
#ifdef TWOPLAYER_MODE
players_here[player_partner[local_player]] = 1;
#endif
#endif
/* First, wait for the other players to arrive: */
send_message_hello ();
while (wait) {
player_input (-1, talk_buffer, "TALK ");
wait = 0;
for (i = 0; i < 4; i++)
if (!players_here[i]) wait = 1;
};
/* Now we reach an agreement about which scoring convention
will be used. In this implementation, north makes the decision
and the others follow this decision. */
if (local_player == PLAYER_NORTH)
send_message_score ();
else {
while (!scoring_mode_known)
player_input (-1, talk_buffer, "TALK ");
};
/* Now that we have all of this information we can initialize the
email duplicate structures. Even though we may not be playing
email duplicate, we still record all of the hands in case one
of the players would like to save them.
*/
email_record = New_Email_Duplicate_Struct ();
current_board = NULL;
ns_pair_no = Add_Email_Pair (email_record,
player_names[PLAYER_NORTH],
player_names[PLAYER_SOUTH]);
ew_pair_no = Add_Email_Pair (email_record,
player_names[PLAYER_EAST],
player_names[PLAYER_WEST]);
current_deal_no = total_no_deals = 0;
};
static shuffle_the_deck (cards)
deal cards;
/* Using the algorithm suggested by Douglas Foxvog. Thanks, Doug! */
{
int i, t, c;
deal shuffle;
for (i = 0; i < 52; i++)
shuffle [i] = i;
for (i = 0; i < 51; i++) {
c = random (52 - i);
t = shuffle[i+c];
shuffle[i+c] = shuffle[i];
shuffle[i] = t;
};
for (i = 0; i < 52; i++)
cards[shuffle[i]] = (i % 4);
};
static void Print_Continue_Message (saved_already)
int saved_already;
{
if ((total_no_deals == 0) && !replaying_mode) {
Display_Player_Comment ("MODERATOR",
"TO BEGIN PLAY, TYPE /DEAL [nhands] OR /LOAD filename.");
} else {
Display_Player_Comment ("MODERATOR",
"ALL BOARDS HAVE NOW BEEN PLAYED.");
if (!saved_already)
Display_Player_Comment ("MODERATOR",
"TYPE /SAVE filename TO SAVE THE RESULTS,");
Display_Player_Comment ("MODERATOR",
"THEN /DEAL [nhands] OR /LOAD filename TO CONTINUE PLAY.");
};
};
static int Email_Deal_Available ()
{
if (replaying_mode)
return (current_board != NULL);
else
return (current_deal_no != total_no_deals);
};
input_hand (current_deal)
deal current_deal;
/* If this player is the dealer, then shuffles the deck and deals the
cards to everyone. Otherwise, waits for the dealer to tell what
the new shuffle is. Stores the new deal in current_deal.
*/
{
struct player_command_struct pcs;
int i, saved;
char message_buf[80];
#ifdef LOOPBACK_MODE
int dealer;
dealer = local_player;
#endif
#ifdef TWOPLAYER_MODE
dealer = dealer % 2;
#endif
if (current_board != NULL)
current_board = current_board -> next;
if ((scoring_mode == EMAIL_SCORING) && (local_player == PLAYER_NORTH)){
if (!Email_Deal_Available()) {
saved = 0;
if (autoload_file != NULL) {
load_email_file (autoload_file);
autoload_file = NULL;
if (!replaying_mode)
autosave_file = NULL;
} else if (autosave_file != NULL) {
save_email_file (autosave_file);
autosave_file = NULL;
saved = 1;
};
enable (CMD_DEAL);
enable (CMD_LOAD);
enable (CMD_REPLAY);
if (!Email_Deal_Available())
Print_Continue_Message (saved);
while (!Email_Deal_Available ())
player_input (-1, talk_buffer, "TALK ");
disable (CMD_DEAL);
disable (CMD_LOAD);
disable (CMD_REPLAY);
};
if (replaying_mode) {
for (i = 0; i < 52; i++)
current_deal[i] = current_board->deal[i];
vulnerable[SIDE_NS] = current_board->ns_vulnerable;
vulnerable[SIDE_EW] = current_board->ew_vulnerable;
dealer = current_board->dealer;
} else {
shuffle_the_deck (current_deal);
current_board = Add_Email_Board (email_record,
current_deal);
current_board->ns_vulnerable = vulnerable[SIDE_NS];
current_board->ew_vulnerable = vulnerable[SIDE_EW];
current_board->dealer = dealer;
};
send_message_vuln (dealer, vulnerable[SIDE_NS],
vulnerable[SIDE_EW]);
send_message_rdeal (current_deal);
} else if (scoring_mode == EMAIL_SCORING) {
Display_Status ("WAITING FOR DEAL ... ");
input_remote_play (PLAYER_NORTH, CMD_VULN, &pcs);
vulnerable[SIDE_NS] =
(pcs.data.vulnerable >> SIDE_NS) & 1;
vulnerable[SIDE_EW] =
(pcs.data.vulnerable >> SIDE_EW) & 1;
dealer = pcs.data.vulnerable >> 2;
input_remote_play (PLAYER_NORTH, CMD_RDEAL, &pcs);
for (i = 0; i < 52; i++)
current_deal[i] = pcs.data.deal[i];
Clear_Status_Display ();
} else if (dealer == local_player) {
shuffle_the_deck (current_deal);
send_message_rdeal (current_deal);
} else {
Display_Status ("WAITING FOR DEAL ... ");
input_remote_play (dealer, CMD_RDEAL, &pcs);
for (i = 0; i < 52; i++)
current_deal[i] = pcs.data.deal[i];
Clear_Status_Display ();
};
if (current_board == NULL) {
current_board = Add_Email_Board (email_record, current_deal);
current_board->ns_vulnerable = vulnerable[SIDE_NS];
current_board->ew_vulnerable = vulnerable[SIDE_EW];
current_board->dealer = dealer;
};
current_deal_no += 1;
};
static display_valid_bids (minimum_bid, double_ok, redouble_ok)
int minimum_bid, double_ok, redouble_ok;
{
char double_string[40], bid_string[80];
if (double_ok)
sprintf (double_string, "; DOUBLE IS OK");
else if (redouble_ok)
sprintf (double_string, "; REDOUBLE IS OK");
else
double_string[0] = '\0';
sprintf (bid_string, "ERROR -- MINIMUM BID IS %s%s",
bid_names[minimum_bid], double_string);
Display_Status (bid_string);
};
static display_valid_plays (current_hand)
hand current_hand;
{
char card_string [60], card_message[80];
int i, j, c;
c = 0;
for (i = 0; i < 52; i++) {
if (current_hand[i]) {
for (j = 0; card_names[i][j] != '\0'; j++)
card_string[c++] = card_names[i][j];
card_string[c++] = ' ';
};
};
card_string[c++] = '\0';
sprintf (card_message,"ERROR -- VALID PLAYS ARE %s", card_string);
Display_Status (card_message);
};
static int legal_bid (bid, minimum, double_ok, redouble_ok)
int bid, double_ok, redouble_ok;
{
if (bid < 0)
return (0);
else if (bid == BID_PASS)
return (1);
else if (bid == BID_DOUBLE)
return (double_ok);
else if (bid == BID_REDOUBLE)
return (redouble_ok);
else
return (minimum <= bid);
};
int input_bid (rmt_player, minimum_bid, double_ok, redouble_ok)
int rmt_player, minimum_bid, double_ok, redouble_ok;
/* Waits for the indicated player to make a bid. If the player is the
* one sitting at this terminal, then prompts for the play from the screen.
* Otherwise, waits for the play to come from the network. Returns the
* index of the card played. The input parameter minimum gives the index
* of the minimum acceptable contract bid. The parameters double_ok and
* redouble_ok are boolean flags which indicate respectively if it is ok
* to bid double or redouble.
*/
{
int no_bid, bid;
struct player_command_struct pcs;
if (rmt_player == local_player) {
no_bid = 1;
enable (CMD_BID);
if (ring_my_bell) ring_bell ();
play_buffer->length = TALK_LENGTH - 6;
default_input = "PASS";
while (no_bid) {
player_input (local_player, play_buffer, "BID ");
dequeue_command (local_player, &pcs);
if (pcs.command != CMD_BID)
bid = -1;
else
bid = pcs.data.bid;
no_bid = !legal_bid(bid, minimum_bid, double_ok,
redouble_ok);
if (no_bid)
display_valid_bids (minimum_bid, double_ok,
redouble_ok);
};
play_buffer->length = PLAY_LENGTH - 6;
send_message_bid (bid);
disable (CMD_BID);
default_input = NULL;
} else {
input_remote_play (rmt_player, CMD_BID, &pcs);
bid = pcs.data.bid;
};
return (bid);
};
static int minimum_card (ch)
hand ch;
/* Returns the card of least rank held in the hand ch. */
{
int suit_order[4], suit, mc, i, j;
for (i = j = 0; i < 4; i++)
if (i != trump_suit)
suit_order [j++] = i;
if (trump_suit < 4)
suit_order [3] = trump_suit;
for (i = 0; i < 4; i++) {
suit = suit_order [i];
for (j = 0; j < 13; j++) {
mc = suit * 13 + j;
if (ch[mc]) return (mc);
};
};
return (-1);
};
static int no_cards (ch)
hand ch;
{
int i, n;
for (i = n = 0; i < 52; i++)
if (ch[i]) n++;
return (n);
};
static set_default_suit (ch)
hand ch;
/* Examines the cards in the hand ch. If all of the cards are from a single
suit, then sets default_suit to that suit. Otherwise, sets default_suit
to -1.
*/
{
int i, d;
d = default_suit = -1;
for (i = 0; i < 52; i++)
if (ch[i]) {
if (d == -1)
d = suit_of (i);
else if (d != suit_of(i))
return;
};
default_suit = d;
};
int input_play (rmt_player, current_hand)
int rmt_player; hand current_hand;
/* Waits for the indicated player to play a card. If that player is the
* one sitting at the terminal, then prompts from the screen for the play.
* In this case, current_hand gives a list of the valid cards which may
* be played. If the indicated player is a remote player, then waits for
* the play to arrive through the network. If the return value is
* nonnegative, then it is the index of card played. If the return value
* is -k-1, then k specifies the number of additional tricks claimed
* by the contracting team.
*/
{
int no_play, play;
struct player_command_struct pcs;
char *dp;
char temp_buffer[60];
if (local_player == rmt_player) {
no_play = 1;
enable (CMD_PLAY);
if (local_player == declarer) enable (CMD_CLAIM);
if (ring_my_bell) ring_bell ();
default_input = card_names[minimum_card(current_hand)];
if (default_plays && (no_cards(current_hand) == 1)) {
for (dp = default_input; *dp != '\0'; dp++)
play_buffer->buf[play_buffer->pos++] = *dp;
play_buffer->buf[play_buffer->pos] = '\0';
play_buffer->defaulted = 1;
};
set_default_suit (current_hand);
while (no_play) {
player_input (local_player, play_buffer, "PLAY ");
dequeue_command (local_player, &pcs);
if (pcs.command == CMD_FINISH) {
play = -pcs.data.tricks - 1;
no_play = 0;
} else if (pcs.command == CMD_PLAY) {
play = pcs.data.card;
no_play = !current_hand[play];
if (!no_play)
send_message_play (play);
};
if (no_play)
display_valid_plays (current_hand);
};
default_input = NULL;
disable (CMD_PLAY);
disable (CMD_CLAIM);
} else {
input_remote_play (rmt_player, CMD_PLAY | CMD_FINISH, &pcs);
if (pcs.command == CMD_FINISH)
play = -pcs.data.tricks - 1;
else
play = pcs.data.card;
};
return (play);
};
input_acknowledgment (line)
int line;
/* Displays the message "PRESS RETURN TO CONTINUE" on the given screen line,
* unless:
* line == -1, in which case the message is displayed on the
* status line, or
* line == -2, in which case no message is displayed,
* line == -3, in which case no message is displayed, and the
* program enters TALK mode, exiting when a RETURN is pressed
* on a blank line.
* Then waits for the user to press, RETURN.
*/
{
int ch;
struct player_command_struct pcs;
if (line == -1) {
Clear_Status_Display ();
Display_Status ("PRESS RETURN TO CONTINUE");
} else if (line >= 0) {
print (line, 1, "PRESS RETURN TO CONTINUE");
set_cursor (line, 1 + strlen("PRESS RETURN TO CONTINUE"));
};
if (ring_my_bell) ring_bell ();
waiting_for_acknowledgment = 1;
while (waiting_for_acknowledgment) {
if (line == -3)
player_input (-1, talk_buffer, "TALK ");
else {
if (message_available()) {
receive_player_command (&pcs);
if (pcs.player_no >= 0)
process_player_command (&pcs);
};
if (char_avail()) {
ch = input_char ();
waiting_for_acknowledgment = (ch != '\012')
&& (ch != '\015');
if (ch == '\022')
Refresh_Display ();
};
};
};
if (line != -3)
while (char_avail()) input_char ();
Clear_Status_Display ();
};
input_answer (question)
char *question;
/* Displays the question on the status line and waits for the
* local player to press 'y' or 'n'. Returns 1 if 'y' was entered
* and 0 if 'n' was entered.
*/
{
int polling, ch;
struct player_command_struct pcs;
waiting_for_acknowledgment = 0;
Display_Status (question);
ask_buffer->col = strlen(question) + 2;
clear_input_buffer (ask_buffer);
default_input = "NO";
if (ring_my_bell) ring_bell ();
for (polling = 1; polling;) {
if (message_available()) {
receive_player_command (&pcs);
if (pcs.player_no >= 0)
process_player_command (&pcs);
};
if (char_avail())
if(update_input_buffer (ask_buffer, input_char())) {
ch = ask_buffer->buf[0];
polling = ((ch != 'y') && (ch != 'Y')
&& (ch != 'n') && (ch != 'N'));
clear_input_buffer (ask_buffer);
};
};
default_input = NULL;
Clear_Status_Display ();
update_input_buffer (talk_buffer, '\0');
return ((ch == 'y') || (ch == 'Y'));
};
process_claim_offer (t)
int t;
{
char error_buf[80];
struct player_command_struct pcs;
if ((t + trick) > 14) {
sprintf (error_buf, "THERE ARE ONLY %d TRICKS WHICH CAN BE CLAIMED",
14 - trick);
Display_Status (error_buf);
return;
};
claim_responses = 0;
claim_rejected = 0;
send_message_claim (t);
Display_Status ("WAITING FOR A RESPONSE TO YOUR OFFER...");
disable (CMD_CLAIM);
while (claim_responses < 2)
player_input (-1, talk_buffer, "TALK ");
enable (CMD_CLAIM);
Clear_Status_Display ();
if (!claim_rejected) {
send_message_finish (t);
pcs.command = CMD_FINISH;
pcs.player_no = local_player;
pcs.data.tricks = t;
enqueue_command (&pcs);
};
};
process_claim_response (t)
int t;
{
int response;
char question_buffer [80];
Display_Hand (declarer);
sprintf (question_buffer, "DECLARER CLAIMS %d TRICKS. DO YOU ACCEPT [YN]?",
t);
response = input_answer (question_buffer);
Clear_Hand (declarer);
update_input_buffer (talk_buffer, '\0');
send_message_respond (response);
};