home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume14 / okbrdge2 / part10 < prev    next >
Encoding:
Internet Message Format  |  1993-01-26  |  54.4 KB

  1. Path: uunet!zephyr.ens.tek.com!master!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v14i088:  okbridge2 - computer-mediated bridge game, Part10/14
  5. Message-ID: <3527@master.CNA.TEK.COM>
  6. Date: 7 Sep 92 21:42:37 GMT
  7. Sender: news@master.CNA.TEK.COM
  8. Lines: 1806
  9. Approved: billr@saab.CNA.TEK.COM
  10.  
  11. Submitted-by: mclegg@cs.UCSD.EDU (Matthew Clegg)
  12. Posting-number: Volume 14, Issue 88
  13. Archive-name: okbridge2/Part10
  14. Supersedes: okbridge: Volume 13, Issue 16-22
  15. Environment: BSD-derived Unix, NeXT, curses, sockets
  16.  
  17.  
  18.  
  19. #! /bin/sh
  20. # This is a shell archive.  Remove anything before this line, then unpack
  21. # it by saving it into a file and typing "sh file".  To overwrite existing
  22. # files, type "sh file -c".  You can also feed this as standard input via
  23. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  24. # will see the following message at the end:
  25. #        "End of archive 10 (of 14)."
  26. # Contents:  WhatsNew conversation.c log.c oktally.c
  27. # Wrapped by billr@saab on Mon Sep  7 14:33:38 1992
  28. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  29. if test -f 'WhatsNew' -a "${1}" != "-c" ; then 
  30.   echo shar: Will not clobber existing file \"'WhatsNew'\"
  31. else
  32. echo shar: Extracting \"'WhatsNew'\" \(2491 characters\)
  33. sed "s/^X//" >'WhatsNew' <<'END_OF_FILE'
  34. XWhat's New in Okbridge version 1.7
  35. X------ --- -- -------- ------- ---
  36. X
  37. X1. GPS Duplicate Play
  38. X
  39. XThe GPS now supports duplicate play.  The /DUP command can be used
  40. Xto download duplicate boards from the GPS.  After each board is played,
  41. Xthe results of play by other tables are displayed.  The /RESULTS
  42. Xcommand can be used to find out how well other tables have done at
  43. Xboards you have already played.
  44. X
  45. X
  46. X2. Improved Scoring Modes
  47. X
  48. XOKbridge 1.7 now contains only four scoring modes: Rubber, Duplicate,
  49. XIMP and MP.  The Rubber and Duplicate modes are the same as before.
  50. XThe IMP mode scores Mono-IMP points for boards which have only been
  51. Xplayed by one table and scores true IMP points for boards which have 
  52. Xbeen played by multiple tables.  Similarly, the MP mode scores
  53. Xsimulated match points for boards which have only been played by
  54. Xone table and true match points for boards which have been played
  55. Xby multiple tables.
  56. X
  57. XAll players now see the same scores, regardless of when they join.
  58. X
  59. X
  60. X3. A Two-player Practice Mode has been added.
  61. X
  62. XFollowing a suggestion of Alan Truscott, a "practice" mode has been
  63. Xadded whereby two (or more) players may practice bidding together.
  64. XOKbridge supplies PASS bids for absent players, and after the bidding
  65. Xis completed, the hand has is displayed so that the partnership may
  66. Xdiscuss the bidding and plan the play.
  67. X
  68. X
  69. X4. User Interface Improvements
  70. X
  71. XSwitching between bidding/playing and talking is now completely 
  72. Xunder user control.  OKbridge never switches into bidding/playing
  73. Xmode on its own.  Instead the <TAB> key is used to switch between
  74. Xbidding/playing and talking.  
  75. X
  76. XMost of those annoying "PRESS RETURN TO CONTINUE" messages have
  77. Xbeen replaced by "PRESS ESC TO CONTINUE" messages.  This will
  78. Xsubstantially reduce the chance that pressing return will have
  79. Xan unintended effect.
  80. X
  81. X
  82. X5. Increased Fault Tolerance
  83. X
  84. XIf your connection to the server is temporarily lost, it is possible
  85. Xto rejoin the game and continue playing from exactly where you left off.
  86. XIt is possible to save a board which has been partially played and to
  87. Xresume playing it at a later date.  Observers can take over in the
  88. Xmiddle of a hand.
  89. X
  90. X
  91. X6. Defaults can be saved and restored
  92. X
  93. XMany of the program's settings, such as the player name, email address,
  94. Xbell and prompt toggles, etc., are now saved automatically to the
  95. Xfile ".okdefaults" when the program terminates.  This file is then
  96. Xread at startup time, restoring the prior settings.
  97. X
  98. X
  99. X6. Spectators can now talk to each other.
  100. X
  101. END_OF_FILE
  102. if test 2491 -ne `wc -c <'WhatsNew'`; then
  103.     echo shar: \"'WhatsNew'\" unpacked with wrong size!
  104. fi
  105. # end of 'WhatsNew'
  106. fi
  107. if test -f 'conversation.c' -a "${1}" != "-c" ; then 
  108.   echo shar: Will not clobber existing file \"'conversation.c'\"
  109. else
  110. echo shar: Extracting \"'conversation.c'\" \(14993 characters\)
  111. sed "s/^X//" >'conversation.c' <<'END_OF_FILE'
  112. X/* conversation.c -- processor for conversation level messages.
  113. X *
  114. X ! Copyright (C) 1990-1992 by Matthew Clegg.  All Rights Reserved
  115. X ! 
  116. X ! OKbridge is made available as a free service to the Internet.
  117. X ! Accordingly, the following restrictions are placed on its use:
  118. X ! 
  119. X ! 1.  OKbridge may not be modified in any way without the explicit 
  120. X !     permission of Matthew Clegg.  
  121. X ! 
  122. X ! 2.  OKbridge may not be used in any way for commercial advantage.
  123. X !     It may not be placed on for-profit networks or on for-profit
  124. X !     computer systems.  It may not be bundled as part of a package
  125. X !     or service provided by a for-profit organization.
  126. X ! 
  127. X ! If you have questions about restrictions on the use of OKbridge,
  128. X ! write to mclegg@cs.ucsd.edu.
  129. X ! 
  130. X ! DISCLAIMER:  The user of OKbridge accepts full responsibility for any
  131. X ! damage which may be caused by OKbridge.
  132. X *
  133. X * This module is responsible for processing messages at the conversation
  134. X * level of the okbridge protocol.
  135. X */
  136. X
  137. X#include <stdio.h>
  138. X#include <string.h>
  139. X#include <sys/time.h>
  140. X
  141. X#include "network.h"
  142. X#include "state.h"
  143. X#include "display.h"
  144. X#include "terminal.h"
  145. X#include "cs.h"
  146. X#include "input.h"
  147. X#include "conversation.h"
  148. X
  149. X#ifdef GCC
  150. Xextern gettimeofday (), strcasecmp ();
  151. Xextern fprintf ();
  152. X#endif
  153. X
  154. Xextern int pause_mode;
  155. X
  156. Xextern char *strdup ();
  157. Xextern void free ();
  158. X
  159. Xextern void Generate_reset ();
  160. X
  161. X
  162. Xchar msg_buf[100];  /* A buffer used for formatting messages that will
  163. X               be displayed or sent to other players. */
  164. X
  165. Xstruct timeval ping_start;  /* time at which last ping command
  166. X                   was issued. */
  167. X
  168. X#ifdef LOGFILE
  169. Xextern FILE *net_log;
  170. X#endif
  171. X
  172. Xstatic void Respond_to_Echo (msg)
  173. X     Message msg;
  174. X/* Responds to an echo message. */
  175. X{
  176. X  int mils;    /* milliseconds elapsed between ping and echo */
  177. X  struct timeval ping_end;
  178. X
  179. X  if (!strcmp(msg->p.data.echo.ping_source, local_player_name)) {
  180. X    gettimeofday (&ping_end, NULL);
  181. X    mils = (ping_end.tv_sec - ping_start.tv_sec)
  182. X      * 1000;
  183. X    mils += ping_end.tv_usec / 1000;
  184. X    mils -= ping_start.tv_usec / 1000;
  185. X    sprintf (msg_buf, "ECHO RECEIVED FROM (%c) %-10s IN %7.2f SECONDS",
  186. X         *("NESWO" + msg->p.player_no), msg->p.player_name, 
  187. X         ((float) mils) * 0.001);
  188. X    Moderator_Comment (msg_buf);
  189. X  }
  190. X}
  191. X
  192. Xvoid Handle_Conversation_Message (msg)
  193. X     Message msg;
  194. X/* Processes the message m.  If the message is a protocol message, then
  195. X   takes appropriate action based on the message.  Appends the message
  196. X   to the appropriate conversation queue if further action is warranted.
  197. X*/
  198. X{
  199. X  char message_buf [100];
  200. X  int i, s;
  201. X  int  pass_upwards;
  202. X    /* A boolean flag indicating that the message should be passed upwards
  203. X       to the game queue. */
  204. X  Table t = msg->source->table;
  205. X
  206. X  pass_upwards = 1;
  207. X  switch (msg->p.command) {
  208. X  case CMD_ERROR  :
  209. X    sprintf (message_buf, "ERROR IN MESSAGE FROM %s (%s):",
  210. X         msg->source->player_name, 
  211. X         (msg->source->seat < 4)? seat_names[msg->source->seat]: 
  212. X         "OBSERVER");
  213. X    Network_Comment (message_buf);
  214. X    Network_Comment (msg->p.data.error.message);
  215. X    Network_Comment (msg->p.command_text);
  216. X    pass_upwards = 0;
  217. X    break;
  218. X
  219. X  case CMD_ACK:
  220. X    sprintf (message_buf, "%s HAS JOINED THE GAME AS %s.",
  221. X         msg->p.data.ack.player_name,
  222. X         (msg->p.data.ack.position == PLAYER_OBS)? "AN OBSERVER":
  223. X         seat_names[msg->p.data.ack.position]);
  224. X    Network_Comment (message_buf);
  225. X    break;
  226. X
  227. X  case CMD_CC:
  228. X    if (conventions[side_of(msg->p.player_no)] != NULL)
  229. X      free (conventions[side_of(msg->p.player_no)]);
  230. X    conventions[side_of(msg->p.player_no)] = strdup(msg->p.data.cc);
  231. X    Display_Player_Comment 
  232. X      (COMMENT_PUBLIC, side_of(msg->p.player_no)? "E-W CC": "N-S CC",
  233. X       msg->p.data.cc);
  234. X    break;
  235. X
  236. X  case CMD_CLAIMREQ:
  237. X    if (IS_PLAYER(local_player)  && 
  238. X    (side_of(local_player) != side_of(Local_play->declarer))) {
  239. X      Set_Display_Mode (PLAYING_DISPLAY);
  240. X      Display_Hand (Local_play->declarer);
  241. X      Display_Hand (player_partner[local_player]);
  242. X      Display_Hand (player_partner[Local_play->declarer]);
  243. X      sprintf (message_buf,
  244. X           "DECLARER CLAIMS %d TRICKS.  DO YOU ACCEPT? ",
  245. X           msg->p.data.claimreq.no_tricks);
  246. X      Send_claimresp (Local_table, Ask(message_buf));
  247. X      Clear_Hand (Local_play->declarer);
  248. X      Clear_Hand (player_partner[local_player]);
  249. X    } else {
  250. X      sprintf (message_buf, "DECLARER IS CLAIMING %d TRICKS ...",
  251. X           msg->p.data.claimreq.no_tricks);
  252. X      Moderator_Comment (message_buf);
  253. X    }
  254. X    claim_responses = 0;
  255. X    claim_accepted  = 1;
  256. X    break;
  257. X
  258. X  case CMD_CLAIMRESP:
  259. X    claim_responses += 1;
  260. X    claim_accepted  = claim_accepted && msg->p.data.claimresp;
  261. X    if ((claim_responses == 2) && !claim_accepted)
  262. X      Status ("THE CLAIM OFFER HAS BEEN DECLINED.");
  263. X    break;
  264. X
  265. X  case CMD_COMMENT:
  266. X    Moderator_Comment (msg->p.data.comment);
  267. X    break;
  268. X
  269. X  case CMD_ECHO:
  270. X    Respond_to_Echo (msg);
  271. X    break;
  272. X    
  273. X  case CMD_HELLO  :
  274. X    if (strcmp(major_revision_level, msg->p.data.hello.version)) {
  275. X      sprintf (message_buf, "%s HAS ATTEMPTED TO CONNECT USING VERSION %s",
  276. X           msg->p.data.hello.player_name, msg->p.data.hello.version);
  277. X      Network_Comment (message_buf);
  278. X    } else {
  279. X      if (IS_OBSERVER(msg->p.data.hello.seat_req))
  280. X    sprintf (message_buf, "%s HAS JOINED THE GAME.", 
  281. X         msg->p.data.hello.player_name);
  282. X      else {
  283. X    sprintf (message_buf, "%s HAS JOINED THE GAME AS %s.",
  284. X         msg->p.data.hello.player_name, 
  285. X         seat_names[msg->p.data.hello.seat_req]);
  286. X    sprintf (PLAYER_NAME(t, msg->p.data.hello.seat_req), "%s",
  287. X         msg->p.data.hello.player_name);
  288. X    Refresh_Player_Names ();
  289. X      }
  290. X      Network_Comment (message_buf);
  291. X      ring_bell ();
  292. X    }
  293. X    break;
  294. X
  295. X  case CMD_MODE:
  296. X    if (msg->p.data.mode != t->playing_mode) {
  297. X      switch (msg->p.data.mode) {
  298. X      case CLUB_PLAYING_MODE:
  299. X    Moderator_Comment ("WE ARE PLAYING CLUB STYLE BRIDGE.");
  300. X    break;
  301. X      case PRACTICE_PLAYING_MODE:
  302. X    Moderator_Comment ("WE ARE PLAYING PRACTICE BRIDGE.");
  303. X    break;
  304. X      case FORMAL_PLAYING_MODE:
  305. X    Moderator_Comment ("WE ARE PLAYING FORMAL BRIDGE.");
  306. X    break;
  307. X      }
  308. X    }
  309. X    break;
  310. X
  311. X  case CMD_NAME:
  312. X    sprintf (message_buf, "%s IS NOW NAMED %s.", msg->p.player_name,
  313. X         msg->p.data.name.new_name);
  314. X    Network_Comment (message_buf);
  315. X    if (IS_PLAYER(msg->p.player_no)) {
  316. X      sprintf (PLAYER_NAME(t, msg->p.player_no), "%s",
  317. X           msg->p.data.name.new_name);
  318. X      Refresh_Player_Names ();
  319. X    }
  320. X    break;
  321. X
  322. X  case CMD_QUIT:
  323. X    sprintf (message_buf, "%s HAS QUIT.", msg->p.player_name);
  324. X    Network_Comment (message_buf);
  325. X    if (IS_PLAYER(msg->p.player_no)) {
  326. X      Refresh_Player_Names ();
  327. X      Refresh_Input_Buffers ();
  328. X    }
  329. X    pass_upwards = 0;
  330. X    break;
  331. X
  332. X  case CMD_PING:
  333. X    if (!msg->loopback)
  334. X      Send_echo (msg->source->table, msg->p.player_name);
  335. X    break;
  336. X
  337. X  case CMD_RESET:
  338. X    Moderator_Comment ("RESET RECEIVED!");
  339. X    Generate_reset (RESET_FULL);
  340. X    break;
  341. X
  342. X  case CMD_SKIP:
  343. X    Moderator_Comment ("SKIPPING TO NEXT HAND ... ");
  344. X    pause_mode = 0;
  345. X    break;
  346. X
  347. X  case CMD_SEAT:
  348. X    if (strcasecmp(msg->p.data.seat.player_name, local_player_name)) {
  349. X      s = msg->p.data.seat.new_pos;
  350. X      sprintf (message_buf, "%s IS SITTING AS %s.", 
  351. X           msg->p.data.seat.player_name,
  352. X           IS_PLAYER(s)? seat_names[s]: "AN OBSERVER");
  353. X      Network_Comment (message_buf);
  354. X      if (IS_PLAYER(msg->p.data.seat.new_pos) ||
  355. X      IS_PLAYER(msg->p.data.seat.old_pos)) {
  356. X    Refresh_Player_Names ();
  357. X    Refresh_Input_Buffers ();
  358. X      }
  359. X    } else
  360. X      Display_Player_Position ();
  361. X    break;
  362. X
  363. X  case CMD_SEATERR:
  364. X    Network_Comment ("THE SEAT WHICH YOU REQUESTED IS OCCUPIED.");
  365. X    if (msg->p.data.seaterr.free_seats[0] >= 4)
  366. X      Network_Comment ("THERE ARE NO FREE SEATS CURRENTLY.");
  367. X    else {
  368. X      sprintf (message_buf, "THE CURRENTLY FREE SEATS ARE:");
  369. X      for (i = 0; i < 3; i++)
  370. X    if (msg->p.data.seaterr.free_seats[i] < 4)
  371. X      sprintf (message_buf + strlen(message_buf), " %s,",
  372. X           seat_names[msg->p.data.seaterr.free_seats[i]]);
  373. X      message_buf[strlen(message_buf)-1] = '.';
  374. X      Network_Comment (message_buf);
  375. X    }
  376. X    break;
  377. X
  378. X  case CMD_SEATPOS:
  379. X    Assign_seat (Local_table, Local_Player_Connection, msg->p.data.seatpos);
  380. X    local_player = msg->p.data.seatpos;
  381. X    if (Local_table->game_mode == BIDDING_MODE) {
  382. X      if (IS_OBSERVER(msg->p.data.seatpos))
  383. X    Set_Input_Mode (TALK_INPUT);
  384. X      else
  385. X    Set_Input_Mode (BID_INPUT);
  386. X      Refresh_Player_Names ();
  387. X      Refresh_Input_Buffers ();
  388. X    } else if (Local_table->game_mode == PLAYING_MODE) {
  389. X      if (PRACTICE(Local_table) && IS_PLAYER(msg->p.data.seatpos))
  390. X    Set_Input_Mode (PLAY_INPUT);
  391. X      else if (IS_OBSERVER(msg->p.data.seatpos) || 
  392. X      (msg->p.data.seatpos == player_partner[Local_play->declarer]))
  393. X    Set_Input_Mode (TALK_INPUT);
  394. X      else
  395. X    Set_Input_Mode (PLAY_INPUT);
  396. X      Refresh_Player_Names ();
  397. X      Refresh_Input_Buffers ();
  398. X      if (IS_PLAYER(local_player))
  399. X    Display_Hand (local_player);
  400. X    }
  401. X    Display_Player_Position ();
  402. X    sprintf (message_buf, "YOU ARE NOW SITTING AS %s.",
  403. X         IS_PLAYER(local_player)? seat_names[local_player]: 
  404. X         "AN OBSERVER");
  405. X    Network_Comment (message_buf);
  406. X    break;
  407. X
  408. X  case CMD_SPEC:
  409. X    sprintf (message_buf, "%s HAS ENTERED SPECTATOR MODE.", 
  410. X         msg->p.player_name);
  411. X    Moderator_Comment (message_buf);
  412. X    msg->source->spectator = 1;
  413. X    break;
  414. X
  415. X  case CMD_TABLE:
  416. X    if (t->table_no == msg->p.data.table) {
  417. X      sprintf (message_buf, "YOU HAVE JOINED TABLE %d.", t->table_no);
  418. X      Moderator_Comment (message_buf);
  419. X    } else {
  420. X      sprintf (message_buf, "ERROR IN ASSIGNMENT TO TABLE %d", 
  421. X           msg->p.data.table);
  422. X      Moderator_Comment (message_buf);
  423. X    }
  424. X    break;
  425. X
  426. X  case CMD_TALK:
  427. X    switch (msg->p.data.talk.recipients) {
  428. X    case TALK_RCPT_LHO:
  429. X      if (player_next[msg->p.player_no] == local_player)
  430. X    Display_Player_Comment
  431. X      (COMMENT_PRIVATE, msg->p.player_name, msg->p.data.talk.message);
  432. X      break;
  433. X    case TALK_RCPT_RHO:
  434. X      if (player_prev[msg->p.player_no] == local_player)
  435. X    Display_Player_Comment
  436. X      (COMMENT_PRIVATE, msg->p.player_name, msg->p.data.talk.message);
  437. X      break;
  438. X    case TALK_RCPT_OPPS:
  439. X      if (player_partner[msg->p.player_no] != local_player)
  440. X    Display_Player_Comment
  441. X      (COMMENT_FORMAL, msg->p.player_name, msg->p.data.talk.message);
  442. X      break;
  443. X    case TALK_RCPT_SPEC:
  444. X      if (spectator_mode)
  445. X    Display_Player_Comment
  446. X      (COMMENT_FORMAL, msg->p.player_name, msg->p.data.talk.message);
  447. X      break;
  448. X    case TALK_RCPT_ALL:
  449. X    default:
  450. X      Display_Player_Comment
  451. X    (COMMENT_PUBLIC, msg->p.player_name, msg->p.data.talk.message);
  452. X      break;
  453. X    }
  454. X    break;
  455. X    
  456. X  case CMD_WAKEUP:
  457. X    if (!strcasecmp(msg->p.data.wakeup.recipient, "ALL")) {
  458. X      Display_Player_Comment (COMMENT_PUBLIC, msg->p.player_name, "WAKE UP!");
  459. X      ring_bell ();
  460. X    } else if (!strcasecmp(msg->p.data.wakeup.recipient, local_player_name)) {
  461. X      Display_Player_Comment (COMMENT_PRIVATE, msg->p.player_name, "WAKE UP!");
  462. X      ring_bell ();
  463. X    }
  464. X    break;
  465. X    
  466. X  case CMD_WHORESP:
  467. X    sprintf (message_buf, "WHOIS %s", msg->p.data.whoresp.recipient);
  468. X    Display_Player_Comment (COMMENT_PUBLIC, message_buf,
  469. X                msg->p.data.whoresp.message);
  470. X    break;
  471. X    
  472. X  default:
  473. X    break;
  474. X  }
  475. X
  476. X  if (pass_upwards)
  477. X    enqueue_message(t->game_queue, msg);
  478. X  else
  479. X    deallocate_message (msg);
  480. X}
  481. X
  482. Xstatic int Handle_Protocol_Messages ()
  483. X/* Handles all messages which are on protocol queues.  If any messages
  484. X   were found, returns TRUE.
  485. X*/
  486. X{
  487. X  Table t;
  488. X  Message m;
  489. X  int message_found = 0;
  490. X  
  491. X  for (t = Table_List; t != NULL; t = t->next) {
  492. X    while (message_available(t->protocol_queue)) {
  493. X      m = dequeue_message (t->protocol_queue);
  494. X      message_found = 1;
  495. X      if (server_mode)
  496. X    Handle_Protocol_Message_for_Server (m);
  497. X      else
  498. X    Handle_Protocol_Message_for_Client (m);
  499. X    }
  500. X  }
  501. X  
  502. X  return (message_found);
  503. X}
  504. X
  505. Xstatic int Handle_Conversation_Messages ()
  506. X/* Handles all messages which are on conversation queues.  If any messages
  507. X   were found, returns TRUE.
  508. X*/
  509. X{
  510. X  Table t;
  511. X  Message m;
  512. X  int message_found = 0;
  513. X
  514. X  for (t = Table_List; t != NULL; t = t->next) {
  515. X    while (message_available(t->conversation_queue)) {
  516. X      message_found = 1;
  517. X      m = dequeue_message (t->conversation_queue);
  518. X      Handle_Conversation_Message (m);
  519. X    }
  520. X  }
  521. X  
  522. X  return (message_found);
  523. X}
  524. X
  525. Xvoid Wait_for_event_at_conversation_level (e)
  526. X     event_signal e;
  527. X/* Receives incoming messages at all tables.  Handles keyboard characters
  528. X * and messages which arrive on the protocol queues.  Each time a keyboard
  529. X * character is received or a new message is processed, the event_signal
  530. X * routine is called.  If it returns true, then the procedure exits.
  531. X */
  532. X{
  533. X  do {
  534. X    Handle_Protocol_Messages ();
  535. X    if ((*e)()) return;
  536. X    restore_cursor ();
  537. X    Wait_for_network_event ();
  538. X    if ((*e)()) return;
  539. X    Accept_Keyboard_Characters ();
  540. X  } while (1);
  541. X    
  542. X}
  543. X
  544. Xvoid Wait_for_event_at_game_level (e)
  545. X     event_signal e;
  546. X/* Receives incoming messages at all tables.  Handles keyboard characters
  547. X * and messages which arrive on the protocol and conversation queues.  Each
  548. X * time a keyboard character is received or a new message is processed, the
  549. X * event_signal e routine is called.  If it returns true, then the procedure
  550. X * exits.  
  551. X */
  552. X{
  553. X  int protocol_message_handled, 
  554. X      conversation_message_handled;
  555. X  
  556. X  do {
  557. X    do {
  558. X      protocol_message_handled = Handle_Protocol_Messages ();
  559. X      conversation_message_handled = Handle_Conversation_Messages ();
  560. X     } while (protocol_message_handled || conversation_message_handled);
  561. X
  562. X    if ((*e)()) return;
  563. X    restore_cursor ();
  564. X    Wait_for_network_event ();
  565. X    if ((*e)()) return;
  566. X    Accept_Keyboard_Characters ();
  567. X  } while (1);
  568. X}
  569. X
  570. XTable Wait_for_conversation_message ()
  571. X/* Receives incoming message at all tables.  Handles keyboard characters
  572. X * and messages which arrive on the protocol queues.  When a message is
  573. X * placed onto the conversation queue of a table, returns a pointer to
  574. X * the table. */
  575. X{
  576. X  Table t;
  577. X
  578. X  do {
  579. X    Handle_Protocol_Messages ();
  580. X    for (t = Table_List; t != NULL; t = t->next)
  581. X      if (message_available(t->conversation_queue))
  582. X    return (t);
  583. X    restore_cursor ();
  584. X    Wait_for_network_event ();
  585. X    Accept_Keyboard_Characters ();
  586. X  } while (1);
  587. X}
  588. X
  589. XTable Wait_for_game_message ()
  590. X/* Receives incoming messages at all tables.  Handles keyboard characters
  591. X * and messages which arrive on the protocol and game queues.  When a message
  592. X * is placed onto the game queue of a table, returns a pointer to the table.
  593. X */
  594. X{
  595. X  Table t;
  596. X  int protocol_message_handled, 
  597. X      conversation_message_handled;
  598. X  
  599. X  do {
  600. X    do {
  601. X      protocol_message_handled = Handle_Protocol_Messages ();
  602. X      conversation_message_handled = Handle_Conversation_Messages ();
  603. X     } while (protocol_message_handled || conversation_message_handled);
  604. X
  605. X    for (t = Table_List; t != NULL; t = t->next)
  606. X      if (message_available(t->game_queue))
  607. X    return (t);
  608. X
  609. X    restore_cursor ();
  610. X    Wait_for_network_event ();
  611. X    Accept_Keyboard_Characters ();
  612. X  } while (1);
  613. X}
  614. END_OF_FILE
  615. if test 14993 -ne `wc -c <'conversation.c'`; then
  616.     echo shar: \"'conversation.c'\" unpacked with wrong size!
  617. fi
  618. # end of 'conversation.c'
  619. fi
  620. if test -f 'log.c' -a "${1}" != "-c" ; then 
  621.   echo shar: Will not clobber existing file \"'log.c'\"
  622. else
  623. echo shar: Extracting \"'log.c'\" \(17424 characters\)
  624. sed "s/^X//" >'log.c' <<'END_OF_FILE'
  625. X/* log.c -- module for recording boards to log files.
  626. X *
  627. X ! Copyright (C) 1990-1992 by Matthew Clegg.  All Rights Reserved
  628. X ! 
  629. X ! OKbridge is made available as a free service to the Internet.
  630. X ! Accordingly, the following restrictions are placed on its use:
  631. X ! 
  632. X ! 1.  OKbridge may not be modified in any way without the explicit 
  633. X !     permission of Matthew Clegg.  
  634. X ! 
  635. X ! 2.  OKbridge may not be used in any way for commercial advantage.
  636. X !     It may not be placed on for-profit networks or on for-profit
  637. X !     computer systems.  It may not be bundled as part of a package
  638. X !     or service provided by a for-profit organization.
  639. X ! 
  640. X ! If you have questions about restrictions on the use of OKbridge,
  641. X ! write to mclegg@cs.ucsd.edu.
  642. X ! 
  643. X ! DISCLAIMER:  The user of OKbridge accepts full responsibility for any
  644. X ! damage which may be caused by OKbridge.
  645. X *
  646. X */
  647. X#include <stdio.h>
  648. X#include <sys/types.h>
  649. X#include <sys/time.h>
  650. X#ifdef AIX
  651. X#include <time.h>
  652. X#endif
  653. X
  654. X#include "types.h"
  655. X#include "boards.h"
  656. X#include "scoring.h"
  657. X#include "log.h"
  658. X
  659. X#ifdef GCC
  660. Xextern time_t time ();
  661. Xextern fprintf ();
  662. Xextern fflush ();
  663. X#endif
  664. X
  665. Xextern void *qsort ();
  666. X
  667. X
  668. Xtypedef int (* play_comparator) ();
  669. Xtypedef int sorted_play_array [4][13];
  670. X
  671. Xstatic Play_record *Play_record_buffer [1000];
  672. X
  673. Xstatic void format_suit (buffer, h, p, s)
  674. X/* Searches the hand h for cards held by the player p in the suit s.
  675. X   For each such card found, places an ascii character representing its
  676. X   rank into the buffer.
  677. X*/
  678. X     char *buffer; hand h; int p, s;
  679. X{
  680. X  int i;
  681. X
  682. X  for (i = 12; i >= 0; i--)
  683. X    if (h[card_code(s, i)] == p)
  684. X      *(buffer++) = *rank_names[i];
  685. X  *buffer = '\0';
  686. X}
  687. X
  688. Xstatic void Sort_cards_by_trick 
  689. X  (trumps, leader, plays, no_plays, s, leaders)
  690. X     int trumps;
  691. X     int leader;
  692. X     card_type *plays;
  693. X     int no_plays;
  694. X     sorted_play_array s;
  695. X     int *leaders;
  696. X/* Sorts the set of plays for a hand by trick and player.  */
  697. X{
  698. X  int player = leader;
  699. X  int trick_no = 0;
  700. X  int i, j;
  701. X
  702. X  for (i = 0; i < 4; i++)
  703. X    for (j = 0; j < 13; j++)
  704. X      s[i][j] = -1;
  705. X
  706. X  leaders[0] = leader;
  707. X  for (i = 0; i < no_plays; i++) {
  708. X    s[player][trick_no] = plays[i];
  709. X    player = player_next[player];
  710. X    if (i % 4 == 3) {
  711. X      player =
  712. X    Winning_card (trumps, player,
  713. X              s[player][trick_no], 
  714. X              s[player_next[player]][trick_no],
  715. X              s[player_partner[player]][trick_no],
  716. X              s[player_prev[player]][trick_no]);
  717. X      if (trick_no < 12)
  718. X    leaders[++trick_no] = player;
  719. X    }
  720. X  }
  721. X}
  722. X
  723. Xvoid Write_hand (logfile, b, p)
  724. X     FILE *logfile;
  725. X     Board *b;
  726. X     Play_record *p;
  727. X/* Writes the board b with play record p to the file f in an expanded
  728. X * format which is similar to that found in bridge books.
  729. X */
  730. X{
  731. X  int i, j;
  732. X  char buf1[80], buf2[80];
  733. X  time_t current_time;
  734. X
  735. X  /* We always make the declarer appear as south: */
  736. X  int vsouth = p->declarer;
  737. X  int vwest  = player_next[p->declarer];
  738. X  int vnorth = player_partner[p->declarer];
  739. X  int veast  = player_prev[p->declarer];
  740. X
  741. X  char *north_name = p->player_names[vnorth],
  742. X       *west_name  = p->player_names[vwest],
  743. X       *south_name = p->player_names[vsouth],
  744. X       *east_name  = p->player_names[veast],
  745. X       *player_names[4];
  746. X
  747. X  sorted_play_array sorted_plays;
  748. X    /* The list of cards each played by each player, indexed by trick no. */
  749. X  int leader[13];
  750. X    /* For each trick, the index of the player who was on lead. */
  751. X  int lead, follow;
  752. X    /* Boolean flags indicating if the current player is on lead. */
  753. X  int round;
  754. X    /* The current round of bidding. */
  755. X  int bidder, player;
  756. X
  757. X  player_names[PLAYER_NORTH] = north_name;
  758. X  player_names[PLAYER_EAST]  = east_name;
  759. X  player_names[PLAYER_WEST]  = west_name;
  760. X  player_names[PLAYER_SOUTH] = south_name;
  761. X
  762. X  if (logfile == NULL) return;
  763. X
  764. X  time (¤t_time);
  765. X  fprintf (logfile, "%s%s Board %d\n\n", ctime(¤t_time),
  766. X       b->source, b->serial_no);
  767. X  fprintf (logfile, "%s Dealer\n", p->player_names[b->dealer]);
  768. X  if (b->vulnerable[side_of(vsouth)] && b->vulnerable[side_of(veast)])
  769. X    fprintf (logfile, "All vul\n");
  770. X  else if (b->vulnerable[side_of(vsouth)])
  771. X    fprintf (logfile, "N-S vul\n");
  772. X  else if (b->vulnerable[side_of(veast)])
  773. X    fprintf (logfile, "E-W vul\n");
  774. X  else
  775. X    fprintf (logfile, "None vul\n");
  776. X
  777. X  fprintf (logfile, "\n");
  778. X  fprintf (logfile, "%15s North (%s)\n", " ", north_name);
  779. X  format_suit (buf1, b->deal, vnorth, SUIT_SPADES);
  780. X  fprintf (logfile, "%15s S %s\n", " ", buf1);
  781. X  format_suit (buf1, b->deal, vnorth, SUIT_HEARTS);
  782. X  fprintf (logfile, "%15s H %s\n", " ", buf1);
  783. X  format_suit (buf1, b->deal, vnorth, SUIT_DIAMONDS);
  784. X  fprintf (logfile, "%15s D %s\n", " ", buf1);
  785. X  format_suit (buf1, b->deal, vnorth, SUIT_CLUBS);
  786. X  fprintf (logfile, "%15s C %s\n", " ", buf1);
  787. X
  788. X  sprintf (buf1, "West (%s)", west_name);
  789. X  fprintf (logfile, "%-15s %15s East (%s)\n", buf1, " ", east_name);
  790. X  format_suit (buf1, b->deal, vwest, SUIT_SPADES);
  791. X  format_suit (buf2, b->deal, veast, SUIT_SPADES);
  792. X  fprintf (logfile, "S %-13s %15s S %s\n", buf1, " ", buf2);
  793. X  format_suit (buf1, b->deal, vwest, SUIT_HEARTS);
  794. X  format_suit (buf2, b->deal, veast, SUIT_HEARTS);
  795. X  fprintf (logfile, "H %-13s %15s H %s\n", buf1, " ", buf2);
  796. X  format_suit (buf1, b->deal, vwest, SUIT_DIAMONDS);
  797. X  format_suit (buf2, b->deal, veast, SUIT_DIAMONDS);
  798. X  fprintf (logfile, "D %-13s %15s D %s\n", buf1, " ", buf2);
  799. X  format_suit (buf1, b->deal, vwest, SUIT_CLUBS);
  800. X  format_suit (buf2, b->deal, veast, SUIT_CLUBS);
  801. X  fprintf (logfile, "C %-13s %15s C %s\n", buf1, " ", buf2);
  802. X
  803. X  fprintf (logfile, "\n");
  804. X  fprintf (logfile, "%15s South (%s)\n", " ", south_name);
  805. X  format_suit (buf1, b->deal, vsouth, SUIT_SPADES);
  806. X  fprintf (logfile, "%15s S %s\n", " ", buf1);
  807. X  format_suit (buf1, b->deal, vsouth, SUIT_HEARTS);
  808. X  fprintf (logfile, "%15s H %s\n", " ", buf1);
  809. X  format_suit (buf1, b->deal, vsouth, SUIT_DIAMONDS);
  810. X  fprintf (logfile, "%15s D %s\n", " ", buf1);
  811. X  format_suit (buf1, b->deal, vsouth, SUIT_CLUBS);
  812. X  fprintf (logfile, "%15s C %s\n", " ", buf1);
  813. X
  814. X  fprintf (logfile, "\n");
  815. X  if (p->hand_completed && p->contract == 0)
  816. X    fprintf (logfile, "  All Passed.\n");
  817. X  else if (p->hand_completed) {
  818. X    fprintf (logfile, "\n%5s %-8s %-8s %-8s %-8s\n", " ",
  819. X         "West", "North", "East", "South");
  820. X    fprintf (logfile, "%5s %-8s %-8s %-8s %-8s\n", " ",
  821. X         west_name, north_name, east_name, south_name);
  822. X    fprintf (logfile, "\n%5s ", " ");
  823. X    round = -1;
  824. X    bidder = vwest;
  825. X    for (i = 0; i < p->no_bids - 2;) {
  826. X      if (bidder == b->dealer) round++;
  827. X      if (round < 0)
  828. X    fprintf (logfile, "%-8s ", "--");
  829. X      else if (i >= p->no_bids - 3) {
  830. X    fprintf (logfile, "(all pass)");
  831. X    i++;
  832. X      } else{
  833. X    sprintf (buf1, "%s%c", 
  834. X         (p->bids[i] == BID_PASS)? "pass": bid_names[p->bids[i]],
  835. X         p->alerts[i]? '*': ' ');
  836. X    fprintf (logfile, "%-8s ", buf1);
  837. X    i++;
  838. X      }
  839. X      bidder = player_next[bidder];
  840. X      if (bidder == vwest)
  841. X    fprintf (logfile, "\n%5s ", " ");
  842. X    }
  843. X    if (bidder != vwest)
  844. X      fprintf (logfile, "\n");
  845. X
  846. X    if (p->no_plays > 0)
  847. X      fprintf (logfile, "\n%5s Opening Lead: %s\n\n", " ",
  848. X           card_names[(int) (p->play_list[0])]);
  849. X  }
  850. X
  851. X  if (p->hand_completed && (p->no_plays > 0)) {
  852. X    Sort_cards_by_trick (trumpsuit_of(p->contract), player_next[p->declarer],
  853. X             p->play_list, p->no_plays, sorted_plays, leader);
  854. X
  855. X    fprintf (logfile, "\n          ");
  856. X    for (i = 0; i < 13; i++)
  857. X      fprintf (logfile, "%2d  ", i+1);
  858. X    fprintf (logfile, "\n          ");
  859. X    for (i = 0; i < 4*13-2; i++) fprintf (logfile, "-");
  860. X    player = vwest;
  861. X    for (i = 0; i < 4; i++) {
  862. X      fprintf (logfile, "\n%8s  ", p->player_names[player]);
  863. X      for (j = 0; j < 13; j++) {
  864. X    if (sorted_plays[player][j] != -1) {
  865. X      lead = (leader[j] == player)? '>': ' ';
  866. X      if ((j < 12) && (leader[j+1] == player))
  867. X        follow = '-';
  868. X      else
  869. X        follow = ' ';
  870. X      fprintf (logfile, "%c%2s%c", lead, 
  871. X           card_names[sorted_plays[player][j]], follow);
  872. X    } else
  873. X      fprintf (logfile, "    ");
  874. X      }
  875. X      player = player_next [player];
  876. X    }
  877. X    fprintf (logfile, "\n\n          > indicates the lead\n\n");
  878. X  }
  879. X
  880. X  if (p->hand_completed) {
  881. X    fprintf (logfile, "\nResult: %+d\n\n", p->result);
  882. X    switch (b->scoring_mode) {
  883. X    case RUBBER_SCORING:
  884. X      fprintf (logfile, "%-10s %8s %8s\n", " ", "N-S", "E-W");
  885. X      fprintf (logfile, "%-10s %8s %8s\n", " ", "------", "------");
  886. X      fprintf (logfile, "%-10s %8d %8d\n", "Above",
  887. X           p->above_line[side_of(vsouth)], p->above_line[side_of(veast)]);
  888. X      fprintf (logfile, "%-10s %8s %8s\n", " ", "------", "------");
  889. X      fprintf (logfile, "%-10s %8d %8d\n", "Part Score",
  890. X           b->part_score[side_of(vsouth)], b->part_score[side_of(veast)]);
  891. X      fprintf (logfile, "%-10s %8d %8d\n", "Below",
  892. X           p->below_line[side_of(vsouth)], p->below_line[side_of(veast)]);
  893. X      fprintf (logfile, "\n");
  894. X      break;
  895. X
  896. X    case DUPLICATE_SCORING:
  897. X    case MP_SCORING:
  898. X      Sort_play_records_by_matchpoints (b);
  899. X      Write_summary_of_play (logfile, b);
  900. X      break;
  901. X      
  902. X    case IMP_SCORING:
  903. X      Sort_play_records_by_imps (b);
  904. X      Write_summary_of_play (logfile, b);
  905. X      break;
  906. X    }
  907. X  }
  908. X
  909. X  fprintf (logfile, "\n\n");
  910. X  for (i = 0; i < 72; i++)
  911. X    fprintf (logfile, "=");
  912. X  fprintf (logfile, "\n%c\n", 12);
  913. X  fflush (logfile);
  914. X}
  915. X
  916. X
  917. Xvoid Write_hand_compactly (zhang_logfile, table_no, b, p)
  918. X     FILE *zhang_logfile;
  919. X     int table_no;
  920. X     Board *b;
  921. X     Play_record *p;
  922. X/* Writes the board b with play record p to the file f in a brief format
  923. X * which was introduced by S. Zhang.
  924. X */
  925. X{ 
  926. X  int i, j;
  927. X  char format_buffer [80];
  928. X  char *bid_zhang[4][20];
  929. X  char zhang[4];
  930. X  time_t current_time;
  931. X  struct tm *decoded_time;
  932. X  sorted_play_array sorted_plays;
  933. X  int leading_play [13];
  934. X  int contractor = side_of (p->declarer);
  935. X  int trump_suit = trumpsuit_of (p->contract);
  936. X  int down, excess, round, lead, bidder;
  937. X  int contract = level_of (p->contract);
  938. X
  939. X  zhang[0]='N'; zhang[1]='E';  zhang[2]='S'; zhang[3]='W';
  940. X
  941. X  if (zhang_logfile == NULL) return;
  942. X  for (i = 0; i < 4; i++){fprintf(zhang_logfile, 
  943. X         " %-8.8s ", p->player_names[i]);
  944. X    for (j = 3; j >= 0; j--) {
  945. X      format_suit (format_buffer, b->deal, i, j);
  946. X      fprintf (zhang_logfile, " %-13s", format_buffer);
  947. X    }    fprintf (zhang_logfile, "\n");
  948. X  }
  949. X
  950. X  fprintf(zhang_logfile, "%3d.(tab%3d)", b->serial_no, table_no);
  951. X
  952. X  fprintf (zhang_logfile,"   %6.6s-%c:", p->player_names[p->declarer],
  953. X              zhang[p->declarer]);   
  954. X  fprintf (zhang_logfile, "%d%1.1s", 
  955. X       contract, long_suit_names [trump_suit] );  
  956. X
  957. X  if (p->doubled == 2)
  958. X    fprintf (zhang_logfile, "XX"); 
  959. X  else if (p->doubled)
  960. X    fprintf (zhang_logfile, "X ");
  961. X  else  
  962. X    fprintf (zhang_logfile, "  ");
  963. X
  964. X  if (p->tricks[contractor] >= contract+6) {
  965. X    fprintf (zhang_logfile, " -- Made %2d  |  ", 
  966. X         (contract == 0)? 0: p->tricks[contractor]-6);
  967. X  } else { down = contract + 6 - p->tricks[contractor];
  968. X    fprintf (zhang_logfile, " -- Down %2d  |  ", down);
  969. X  }
  970. X
  971. X  if (b->vulnerable[SIDE_NS] && b->vulnerable[SIDE_EW])  
  972. X                                   fprintf (zhang_logfile, "Vul:BOTH |  ");
  973. X  else if (b->vulnerable[SIDE_NS]) fprintf (zhang_logfile, "Vul:N&S  |  ");
  974. X  else if (b->vulnerable[SIDE_EW]) fprintf (zhang_logfile, "Vul:E&W  |  ");
  975. X  else                             fprintf (zhang_logfile, "Vul:NONE |  ");
  976. X
  977. X
  978. X  if (p->tricks[contractor] >= contract+6) {
  979. X    if ( contractor == SIDE_NS )  {fprintf (zhang_logfile, " NS:  ");} 
  980. X                             else  fprintf (zhang_logfile, "*NS: -");
  981. X    excess = p->tricks[contractor] - contract - 6;
  982. X    if (contract == 0)
  983. X      fprintf (zhang_logfile, "0  ");
  984. X    else
  985. X      fprintf (zhang_logfile, "%d ", 
  986. X           Duplicate_score_made 
  987. X             (b->vulnerable[contractor], level_of(p->contract),
  988. X          trumpsuit_of(p->contract), p->doubled, p->result));
  989. X  } else {
  990. X    down = contract + 6 - p->tricks[contractor];
  991. X    if ( contractor == SIDE_NS )  {fprintf (zhang_logfile, " NS: -");} 
  992. X                             else  fprintf (zhang_logfile, "*NS:  ");
  993. X    fprintf (zhang_logfile, "%d ", 
  994. X         Duplicate_score_set
  995. X         (b->vulnerable[contractor], level_of(p->contract),
  996. X          trumpsuit_of(p->contract), p->doubled, p->result));
  997. X  }
  998. X
  999. X  for (i=0; i<4; i++) for (j=0; j<20; j++) bid_zhang[i][j]="  ";
  1000. X
  1001. X  bidder = b->dealer;
  1002. X  round = 0;
  1003. X  for (i = 0; i < p->no_bids; i++) {
  1004. X    bid_zhang[bidder][round] = bid_names[p->bids[i]];
  1005. X    bidder = player_next[bidder];
  1006. X    if (bidder == PLAYER_NORTH) round++;
  1007. X  }
  1008. X
  1009. X  Sort_cards_by_trick (trumpsuit_of(p->contract), player_next[p->declarer],
  1010. X               p->play_list, p->no_plays, sorted_plays, leading_play);
  1011. X  for (i = 0; i < 4; i++) {
  1012. X    fprintf(zhang_logfile,"\n%c-%-8.8s",zhang[i],p->player_names[i]);
  1013. X    for (j = 0; j < 13; j++) {
  1014. X      if (sorted_plays[i][j] != -1) {
  1015. X    lead = (leading_play[j] == i)? '*': ' ';
  1016. X    if ((lead ==' ')&&(i==3) ) lead='_';
  1017. X    fprintf (zhang_logfile, "%2s%c", card_names[sorted_plays[i][j]], lead);
  1018. X      } else
  1019. X    fprintf (zhang_logfile, "   ");
  1020. X    } fprintf (zhang_logfile, "|");
  1021. X    for (j = 0; j <= p->no_bids/4; j++) {
  1022. X      fprintf (zhang_logfile, "%-2.2s ", bid_zhang[i][j]);
  1023. X    }
  1024. X  }
  1025. X
  1026. X  fprintf (zhang_logfile, "\n==========");
  1027. X  for (i = 0; i < 13; i++)    fprintf (zhang_logfile, "%2d=", i+1);
  1028. X  time (¤t_time);
  1029. X  for (i = 0; i < 6; i++)     fprintf (zhang_logfile, "=%2d", i+1);
  1030. X  decoded_time = localtime (¤t_time);    
  1031. X  fprintf (zhang_logfile, " %s %2d\n%c\n", 
  1032. X       month_names[decoded_time->tm_mon], decoded_time->tm_mday, 12);
  1033. X  fflush (zhang_logfile);
  1034. X}
  1035. X
  1036. Xvoid sprint_summary_header (buf)
  1037. X     char *buf;
  1038. X{
  1039. X  sprintf (buf, "%-11s %3s %3s %-4s %-21s %-8s %2s %3s %-5s %5s %4s",
  1040. X       "Board", "No", "Dlr", "Vul", "Players", "Contract", 
  1041. X       "By", "Res", "Score", "IMPs", "MPs");
  1042. X}
  1043. X
  1044. Xstatic char *seat_letters [4] = {"N", "E", "S", "W"};
  1045. Xstatic char *double_names [3] = {"", "-X", "-XX"};
  1046. X
  1047. Xvoid sprint_summary_record (buf1, buf2, b, p)
  1048. X     char *buf1;
  1049. X     char *buf2;
  1050. X     Board *b;
  1051. X     Play_record *p;
  1052. X{
  1053. X  char *vul_string;
  1054. X  char contract_buf[10];
  1055. X
  1056. X  if (b->vulnerable[SIDE_NS] && b->vulnerable[SIDE_EW])
  1057. X    vul_string = "both";
  1058. X  else if (b->vulnerable[SIDE_NS])
  1059. X    vul_string = "N-S";
  1060. X  else if (b->vulnerable[SIDE_EW])
  1061. X    vul_string = "E-W";
  1062. X  else
  1063. X    vul_string = "none";
  1064. X
  1065. X  if (p->contract == BID_PASS)
  1066. X    sprintf (contract_buf, "Passed");
  1067. X  else
  1068. X    sprintf (contract_buf, "%s%s", bid_names[p->contract], 
  1069. X         double_names[p->doubled]);
  1070. X
  1071. X  sprintf (buf1, 
  1072. X       "%-11s %3d %-3s %-4s N %-8s S %-8s %-8s %-2s %+3d %5d %5.1f %4.2f",
  1073. X       b->source, b->serial_no, seat_letters[b->dealer], vul_string, 
  1074. X       p->player_names[PLAYER_NORTH], p->player_names[PLAYER_SOUTH],
  1075. X       contract_buf, seat_letters[p->declarer], p->result,
  1076. X       p->below_line[SIDE_NS], 
  1077. X       p->imatch_points[SIDE_NS],
  1078. X       p->match_points[SIDE_NS]);
  1079. X
  1080. X  sprintf (buf2,
  1081. X       "%-11s %3s %3s %-4s E %-8s W %-8s %-8s %2s %3s %5d %5.1f %4.2f",
  1082. X       " ", " ", " ", " ", 
  1083. X       p->player_names[PLAYER_EAST], p->player_names[PLAYER_WEST],
  1084. X       " ", " ", " ", p->below_line[SIDE_EW],
  1085. X       p->imatch_points[SIDE_EW],
  1086. X       p->match_points[SIDE_EW]);
  1087. X
  1088. X}
  1089. X
  1090. Xvoid Write_summary_of_play (f, b)
  1091. X     FILE *f;
  1092. X     Board *b;
  1093. X/* For each play record associated to the board b, writes a single line
  1094. X * summary describing the result of play.
  1095. X */
  1096. X{
  1097. X  char buf1 [100], buf2[100];
  1098. X  Play_record *p;
  1099. X
  1100. X  sprint_summary_header (buf1);
  1101. X  fprintf (f, "%s\n", buf1);
  1102. X
  1103. X  for (p = b->play_records; p != NULL; p = p->next) {
  1104. X    sprint_summary_record (buf1, buf2, b, p);
  1105. X    fprintf (f, "%s\n", buf1);
  1106. X    fprintf (f, "%s\n", buf2);
  1107. X  }
  1108. X  fprintf (f, "\n");
  1109. X}
  1110. X
  1111. Xstatic void Sort_play_records (b, pc)
  1112. X     Board *b;
  1113. X     play_comparator pc;
  1114. X{
  1115. X  int i, n = 0;
  1116. X  Play_record *p;
  1117. X
  1118. X  if ((b->play_records == NULL) || (b->play_records->next == NULL))
  1119. X    return;
  1120. X
  1121. X  for (p = b->play_records; p != NULL; p = p->next)
  1122. X    Play_record_buffer[n++] = p;
  1123. X
  1124. X  qsort (Play_record_buffer, n, sizeof(Play_record *), pc);
  1125. X
  1126. X  p = b->play_records = Play_record_buffer[0];
  1127. X  for (i = 1; i < n; i++)
  1128. X    p = (p->next = Play_record_buffer[i]);
  1129. X  p->next = NULL;
  1130. X}
  1131. X
  1132. Xstatic int match_point_comparator (q1, q2)
  1133. X     Play_record **q1;
  1134. X     Play_record **q2;
  1135. X{
  1136. X  float d1, d2;
  1137. X  Play_record *p1 = *q1;
  1138. X  Play_record *p2 = *q2;
  1139. X
  1140. X  if (!p1->hand_completed && !p2->hand_completed)
  1141. X    return (0);
  1142. X  else if (!p2->hand_completed)
  1143. X    return (-1);
  1144. X  else if (!p1->hand_completed)
  1145. X    return (1);
  1146. X
  1147. X  d1 = p1->match_points[SIDE_NS] - p1->match_points[SIDE_EW];
  1148. X  d2 = p2->match_points[SIDE_NS] - p2->match_points[SIDE_EW];
  1149. X  if (d2 < d1)
  1150. X    return (-1);
  1151. X  else if (d1 < d2)
  1152. X    return (1);
  1153. X  else
  1154. X    return (0);
  1155. X}
  1156. X
  1157. X
  1158. Xvoid Sort_play_records_by_matchpoints (b)
  1159. X     Board *b;
  1160. X/* Sorts the set of play records for the board b according to the match
  1161. X * point scores.
  1162. X */
  1163. X{
  1164. X  Sort_play_records (b, match_point_comparator);
  1165. X}
  1166. X
  1167. Xstatic int imp_comparator (q1, q2)
  1168. X     Play_record **q1;
  1169. X     Play_record **q2;
  1170. X{
  1171. X  float d1, d2;
  1172. X  Play_record *p1 = *q1;
  1173. X  Play_record *p2 = *q2;
  1174. X
  1175. X  if (!p1->hand_completed && !p2->hand_completed)
  1176. X    return (0);
  1177. X  else if (!p2->hand_completed)
  1178. X    return (-1);
  1179. X  else if (!p1->hand_completed)
  1180. X    return (1);
  1181. X
  1182. X  d1 = p1->imatch_points[SIDE_NS] - p1->imatch_points[SIDE_EW];
  1183. X  d2 = p2->imatch_points[SIDE_NS] - p2->imatch_points[SIDE_EW];
  1184. X  if (d2 < d1)
  1185. X    return (-1);
  1186. X  else if (d1 < d2)
  1187. X    return (1);
  1188. X  else
  1189. X    return (0);
  1190. X}
  1191. X
  1192. Xvoid Sort_play_records_by_imps (b)
  1193. X     Board *b;
  1194. X/* Sorts the set of play records for the board b according to the
  1195. X * imp scores.
  1196. X */
  1197. X{
  1198. X  Sort_play_records (b, imp_comparator);
  1199. X}
  1200. X
  1201. END_OF_FILE
  1202. if test 17424 -ne `wc -c <'log.c'`; then
  1203.     echo shar: \"'log.c'\" unpacked with wrong size!
  1204. fi
  1205. # end of 'log.c'
  1206. fi
  1207. if test -f 'oktally.c' -a "${1}" != "-c" ; then 
  1208.   echo shar: Will not clobber existing file \"'oktally.c'\"
  1209. else
  1210. echo shar: Extracting \"'oktally.c'\" \(16133 characters\)
  1211. sed "s/^X//" >'oktally.c' <<'END_OF_FILE'
  1212. X/* oktally.c
  1213. X *
  1214. X ! Copyright (C) 1990-1992 by Matthew Clegg.  All Rights Reserved
  1215. X ! 
  1216. X ! OKbridge is made available as a free service to the Internet.
  1217. X ! Accordingly, the following restrictions are placed on its use:
  1218. X ! 
  1219. X ! 1.  OKbridge may not be modified in any way without the explicit 
  1220. X !     permission of Matthew Clegg.  
  1221. X ! 
  1222. X ! 2.  OKbridge may not be used in any way for commercial advantage.
  1223. X !     It may not be placed on for-profit networks or on for-profit
  1224. X !     computer systems.  It may not be bundled as part of a package
  1225. X !     or service provided by a for-profit organization.
  1226. X ! 
  1227. X ! If you have questions about restrictions on the use of OKbridge,
  1228. X ! write to mclegg@cs.ucsd.edu.
  1229. X ! 
  1230. X ! DISCLAIMER:  The user of OKbridge accepts full responsibility for any
  1231. X ! damage which may be caused by OKbridge.
  1232. X *
  1233. X * This program merges email duplicate files, totaling the match
  1234. X * points for corresponding pairs in each file, generating an output
  1235. X * describing the results for each board.
  1236. X *
  1237. X * Usage:
  1238. X *
  1239. X *   tally [-c] [-i] [-l] [-m] [-p player_name] [-sn] [-t[b]] [-z] 
  1240. X *     file_1 file_2 ... file_n
  1241. X *
  1242. X * Reads each of file_1, file_2, ..., file_n.  Merges the boards
  1243. X * from these files and totals the match points for each pair.
  1244. X * Writes the merged set of boards to standard output.  
  1245. X *
  1246. X * Parameters:
  1247. X *
  1248. X *   -c
  1249. X *    Coded output.  Writes an encoded email duplicate file as output.
  1250. X *
  1251. X *   -i
  1252. X *    IMP scoring. Sorts the output play records by IMPs.  The default is 
  1253. X *    to sort by match points.
  1254. X *
  1255. X *   -l
  1256. X *    Long output.  Writes each board in a format which is similar to 
  1257. X *    that used for presentation in bridge books and magazines.
  1258. X *
  1259. X *   -m
  1260. X *    Merge.  Does a selective merge.  Boards appearing in the second files
  1261. X *    which do not appear in the file are ignored.
  1262. X *
  1263. X *   -p player_name
  1264. X *    specifies that only boards which have been played by the specified
  1265. X *    player should be considered.
  1266. X *
  1267. X *   -sn
  1268. X *    Skip count.  Specifies a skip count.  The first n boards read into 
  1269. X *    memory are ignored.
  1270. X *
  1271. X *   -t
  1272. X *    Totals.  Computes the totals for each player and prints out the
  1273. X *    list of totals, sorted either by match points or IMPs.  If -tb
  1274. X *    is specified, then a two-column output is generated, the first
  1275. X *    column given the match point score totals and the second giving
  1276. X *    the match point score totals.
  1277. X *
  1278. X *   -z
  1279. X *    Zhang format.  Writes each board out in a compact format which was 
  1280. X *    first introduced by Shangyou Zhang.
  1281. X */
  1282. X
  1283. X#include <stdio.h>
  1284. X#include <string.h>
  1285. X
  1286. X#define _BRIDGE_
  1287. X
  1288. X#include "types.h"
  1289. X#include "boards.h"
  1290. X#include "log.h"
  1291. X
  1292. X#ifdef GCC
  1293. Xextern fprintf (), fclose ();
  1294. X#endif
  1295. X
  1296. Xextern int errno;
  1297. Xextern char *sys_errlist [];
  1298. Xextern char *malloc ();
  1299. Xextern void exit ();
  1300. Xextern int  atoi ();
  1301. Xextern char *strdup ();
  1302. X
  1303. Xchar **filename;
  1304. X  /* The list of files from which we are to read email duplicate hands. */
  1305. X
  1306. Xint no_files;
  1307. X  /* The number of entries in the filename array. */
  1308. X
  1309. Xint coded_format;
  1310. X  /* A boolean variable which is true if the output should be written
  1311. X     in coded format. */
  1312. X
  1313. Xchar *player_name_of_interest = NULL;
  1314. X  /* If non-NULL, then we only consider boards which have been played by
  1315. X     the given player. */
  1316. X
  1317. X#define OUTPUT_SUMMARY    0
  1318. X#define OUTPUT_EMAIL      1
  1319. X#define OUTPUT_LOG        2
  1320. X#define OUTPUT_ZLOG       3
  1321. X#define OUTPUT_TOTALS     4
  1322. X
  1323. Xint output_mode = OUTPUT_SUMMARY;
  1324. X  /* Defines the output mode which will be used:
  1325. X     SUMMARY:  Default.  For each board, prints out a listing of how
  1326. X               each table bid the board and the score which was made.
  1327. X     EMAIL:    Writes the set boards out in email duplicate format.
  1328. X     LOG:      Writes each board and play record out in a detailed format
  1329. X               which shows the bidding and the playing.
  1330. X     ZLOG:     Writes the boards out in a compact format developed by
  1331. X               Shangyou Zhang.
  1332. X     TOTALS:   Writes the total score for each player.
  1333. X  */
  1334. X
  1335. Xint sort_by_matchpoints = 1;
  1336. X  /* A boolean flag which if true indicates that we will sort the play 
  1337. X     records by matchpoints.  Otherwise, we will sort them by IMPs. */
  1338. X
  1339. Xint two_column_output = 0;
  1340. X  /* If true, indicates that the output will consist of two columns
  1341. X     of score totals. */
  1342. X
  1343. Xint merge_only = 0;
  1344. X  /* Indicates that boards read from the second and succeeding files will
  1345. X     be merged into those already read. */
  1346. X
  1347. X/* The following structure is used for maintaining the array of player
  1348. X   scores. 
  1349. X*/
  1350. Xtypedef struct Player_score_struct {
  1351. X  char  *player_name;
  1352. X  float score;          /* In MP or IMP scoring, the total of the individual
  1353. X               scores received by the player. */
  1354. X  float total_score;    /* In MP scoring, the total number of match points
  1355. X               received by the player. */
  1356. X  float total_possible; /* In MP scoring, the total number of match points
  1357. X               which were available to the player. */
  1358. X  int   total_boards;   /* The total number of boards played by this player.*/
  1359. X} Player_score;
  1360. X
  1361. X
  1362. X
  1363. Xvoid Abort (m)
  1364. X     char *m;
  1365. X{
  1366. X  fprintf (stderr, "tally: %s\n", m);
  1367. X  exit (1);
  1368. X}
  1369. X
  1370. Xstatic void Read_File (filename)
  1371. X     char *filename;
  1372. X{
  1373. X  FILE *fp;
  1374. X  int status;
  1375. X  char error_buf[80];
  1376. X
  1377. X  if (strcmp(filename, "-")) {
  1378. X    fp = fopen (filename, "r");
  1379. X    if (fp == NULL) {
  1380. X      sprintf (error_buf, "Error opening file %s: %s", filename,
  1381. X           sys_errlist[errno]);
  1382. X      Abort (error_buf);
  1383. X    }
  1384. X  } else
  1385. X    fp = stdin;
  1386. X
  1387. X  status = Load_Email_Duplicate_File (fp);
  1388. X  if (status == 1) {
  1389. X    sprintf (error_buf, "%s is not an email duplicate file", filename);
  1390. X    Abort (error_buf);
  1391. X  } else if (status == -1) {
  1392. X    sprintf (error_buf, "Error reading file %s", filename);
  1393. X    Abort (error_buf);
  1394. X  }
  1395. X
  1396. X  if (strcmp(filename, "-"))
  1397. X    fclose (fp);
  1398. X}
  1399. X
  1400. Xstatic void Merge_File (filename)
  1401. X     char *filename;
  1402. X{
  1403. X  FILE *fp;
  1404. X  int status;
  1405. X  char error_buf[80];
  1406. X
  1407. X  if (strcmp(filename, "-")) {
  1408. X    fp = fopen (filename, "r");
  1409. X    if (fp == NULL) {
  1410. X      sprintf (error_buf, "Error opening file %s: %s", filename,
  1411. X           sys_errlist[errno]);
  1412. X      Abort (error_buf);
  1413. X    }
  1414. X  } else
  1415. X    fp = stdin;
  1416. X
  1417. X  status = Merge_Email_Duplicate_File (fp, Unplayed_boards);
  1418. X  if (status == 1) {
  1419. X    sprintf (error_buf, "%s is not an email duplicate file", filename);
  1420. X    Abort (error_buf);
  1421. X  } else if (status == -1) {
  1422. X    sprintf (error_buf, "Error reading file %s", filename);
  1423. X    Abort (error_buf);
  1424. X  }
  1425. X
  1426. X  if (strcmp(filename, "-"))
  1427. X    fclose (fp);
  1428. X}
  1429. X
  1430. Xint Count_Total_Players (blist)
  1431. X     Board *blist;
  1432. X{
  1433. X  Play_record *p;
  1434. X  int n;
  1435. X
  1436. X  n = 0;
  1437. X  for (; blist != NULL; blist = blist->next)
  1438. X    for (p = blist->play_records; p != NULL; p = p->next)
  1439. X      n += 4;
  1440. X
  1441. X  return (n);
  1442. X}
  1443. X
  1444. Xint Compare_Score_List_Entries (p, q)
  1445. X     Player_score *p, *q;
  1446. X{
  1447. X  if (p->score == q->score)
  1448. X    return (strcasecmp(p->player_name, q->player_name));
  1449. X  else if (p->score > q->score)
  1450. X    return (-1);
  1451. X  else
  1452. X    return (1);
  1453. X}
  1454. X
  1455. Xint Compare_Score_List_Names (p, q)
  1456. X     Player_score *p, *q;
  1457. X{
  1458. X  return(strcasecmp(p->player_name, q->player_name));
  1459. X}
  1460. X
  1461. Xint Sort_and_Merge_Scores (scores, entries)
  1462. X     Player_score *scores; int entries;
  1463. X{
  1464. X  int i, n;
  1465. X
  1466. X  if (entries == 0)
  1467. X    return (0);
  1468. X
  1469. X  qsort (scores, entries, sizeof(Player_score), Compare_Score_List_Names);
  1470. X  
  1471. X  n = 0;
  1472. X  for (i = 1; i < entries; i++)
  1473. X    if (strcasecmp(scores[n].player_name, scores[i].player_name)) {
  1474. X      n += 1;
  1475. X      bcopy (scores+i, scores+n, sizeof(Player_score));
  1476. X    } else {
  1477. X      scores[n].score += scores[i].score;
  1478. X      scores[n].total_score += scores[i].total_score;
  1479. X      scores[n].total_possible += scores[i].total_possible;
  1480. X      scores[n].total_boards += scores[i].total_boards;
  1481. X    }
  1482. X
  1483. X  qsort (scores, n+1, sizeof(Player_score), Compare_Score_List_Entries);
  1484. X  return (n+1);
  1485. X}
  1486. X
  1487. Xstatic int Tables_Played (b)
  1488. X     Board *b;
  1489. X/* Returns the number of tables which have played the board b. */
  1490. X{
  1491. X  int i = 0;
  1492. X  Play_record *p;
  1493. X
  1494. X  for (p = b->play_records; p != NULL; p = p->next) 
  1495. X    if (p->hand_completed) i++;
  1496. X
  1497. X  return (i);
  1498. X}
  1499. X
  1500. Xvoid Create_Matchpoint_List (blist, scores, no_scores)
  1501. X     Board *blist; Player_score **scores; int *no_scores;
  1502. X{
  1503. X  int i, ns;
  1504. X  int no_players = Count_Total_Players (blist);
  1505. X  Player_score *score_list;
  1506. X  Board *b;
  1507. X  Play_record *p;
  1508. X
  1509. X  score_list = *scores = (Player_score *)
  1510. X    malloc (no_players * sizeof(Player_score));
  1511. X
  1512. X  ns = 0;
  1513. X  for (b = blist; b != NULL; b = b->next)
  1514. X    if ((b->scoring_mode == MP_SCORING) && (Tables_Played(b) >= 4))
  1515. X      for (p = b->play_records; p != NULL; p = p->next)
  1516. X    for (i = 0; i < 4; i++) {
  1517. X      score_list[ns].player_name = p->player_names[i];
  1518. X      score_list[ns].score = p->match_points[side_of(i)];
  1519. X      score_list[ns].total_possible = (float) (Tables_Played(b) - 1);
  1520. X      score_list[ns].total_score = 
  1521. X        p->match_points[side_of(i)] * score_list[ns].total_possible;
  1522. X      score_list[ns].total_boards = 1;
  1523. X      ns += 1;
  1524. X    }
  1525. X
  1526. X  *no_scores = Sort_and_Merge_Scores (score_list, ns);
  1527. X}
  1528. X
  1529. Xvoid Create_IMP_List (blist, scores, no_scores)
  1530. X     Board *blist; Player_score **scores; int *no_scores;
  1531. X{
  1532. X  int i, ns;
  1533. X  int no_players = Count_Total_Players (blist);
  1534. X  Player_score *score_list;
  1535. X  Board *b;
  1536. X  Play_record *p;
  1537. X
  1538. X  score_list = *scores = (Player_score *)
  1539. X    malloc (no_players * sizeof(Player_score));
  1540. X
  1541. X  ns = 0;
  1542. X  for (b = blist; b != NULL; b = b->next)
  1543. X    if ((b->scoring_mode == IMP_SCORING) && (Tables_Played(b) >= 4))
  1544. X      for (p = b->play_records; p != NULL; p = p->next)
  1545. X    for (i = 0; i < 4; i++) {
  1546. X      score_list[ns].player_name = p->player_names[i];
  1547. X      score_list[ns].score = p->imatch_points[side_of(i)];
  1548. X      score_list[ns].total_score = score_list[ns].score;
  1549. X      score_list[ns].total_possible = 0.0;
  1550. X      score_list[ns].total_boards = 1;
  1551. X      ns += 1;
  1552. X    }
  1553. X
  1554. X  *no_scores = Sort_and_Merge_Scores (score_list, ns);
  1555. X}
  1556. X
  1557. Xvoid Write_Match_Point_Totals (blist)
  1558. X     Board *blist;
  1559. X{
  1560. X  Player_score *matchpoint_list;
  1561. X  int no_matchpoint_scores;
  1562. X  int i;
  1563. X
  1564. X  Create_Matchpoint_List (blist, &matchpoint_list, &no_matchpoint_scores);
  1565. X
  1566. X  printf ("%4s %-10s %12s %8s %8s\n", " ", "Name", "Match Points", "Percent",
  1567. X      "Boards");
  1568. X
  1569. X  for (i = 0; i < no_matchpoint_scores; i++)
  1570. X    printf ("%4d %-10s %12.2f %8.1f %8d\n", 
  1571. X        i+1,
  1572. X        matchpoint_list[i].player_name,
  1573. X        matchpoint_list[i].score,
  1574. X        100.0 * matchpoint_list[i].total_score /
  1575. X          matchpoint_list[i].total_possible,
  1576. X        matchpoint_list[i].total_boards
  1577. X        );
  1578. X}
  1579. X
  1580. Xvoid Write_IMP_Totals (blist)
  1581. X     Board *blist;
  1582. X{
  1583. X  Player_score *IMP_list;
  1584. X  int no_imp_scores;
  1585. X  int i;
  1586. X
  1587. X  Create_IMP_List (blist, &IMP_list, &no_imp_scores);
  1588. X
  1589. X  printf ("%4s %-10s %8s %8s %8s\n",
  1590. X      " ", "Name", "IMPs", "Average", "Boards");
  1591. X
  1592. X  for (i = 0; i < no_imp_scores; i++)
  1593. X    printf ("%4d %-10s %8.1f %8.1f %8d\n",
  1594. X        i+1, 
  1595. X        IMP_list[i].player_name,
  1596. X        IMP_list[i].score,
  1597. X        IMP_list[i].total_score / ((float) IMP_list[i].total_boards),
  1598. X        IMP_list[i].total_boards);
  1599. X}
  1600. X
  1601. Xvoid Write_Totals_in_Two_Columns (blist)
  1602. X     Board *blist;
  1603. X{
  1604. X  Player_score *matchpoint_list, *IMP_list;
  1605. X  int no_matchpoint_scores, no_imp_scores, max_scores;
  1606. X  int i;
  1607. X
  1608. X  Create_Matchpoint_List (blist, &matchpoint_list, &no_matchpoint_scores);
  1609. X  Create_IMP_List (blist, &IMP_list, &no_imp_scores);
  1610. X
  1611. X  printf ("%4s %-10s %12s %4s %5s %-10s %12s %4s\n", 
  1612. X      " ", "Name", "Match Points", "Pct", " ", "Name", "IMPs", "Avg");
  1613. X
  1614. X  if (no_matchpoint_scores > no_imp_scores)
  1615. X    max_scores = no_matchpoint_scores;
  1616. X  else
  1617. X    max_scores = no_imp_scores;
  1618. X
  1619. X  for (i = 0; i < max_scores; i++)
  1620. X    if ((i < no_matchpoint_scores) && (i < no_imp_scores))
  1621. X      printf ("%4d %-10s %12.2f %4d %5s %-10s %12.1f %4.1f\n", 
  1622. X          i+1, 
  1623. X          matchpoint_list[i].player_name,
  1624. X          matchpoint_list[i].score, 
  1625. X          (int) (100.0 * matchpoint_list[i].total_score /
  1626. X          matchpoint_list[i].total_possible + 0.5),
  1627. X          " ",
  1628. X          IMP_list[i].player_name,
  1629. X          IMP_list[i].score,
  1630. X          IMP_list[i].total_score / ((float) IMP_list[i].total_boards)
  1631. X          );
  1632. X
  1633. X    else if (i < no_matchpoint_scores)
  1634. X      printf ("%4d %-10s %12.2f %4d\n",
  1635. X          i+1, 
  1636. X          matchpoint_list[i].player_name,
  1637. X          matchpoint_list[i].score,
  1638. X          (int) (100.0 * matchpoint_list[i].total_score /
  1639. X          matchpoint_list[i].total_possible + 0.5));
  1640. X    else
  1641. X      printf ("%4d %-10s %12s %10s %-10s %12.1f %4.1f\n", 
  1642. X          i+1, " ", " ", " ",
  1643. X          IMP_list[i].player_name,
  1644. X          IMP_list[i].score,
  1645. X          IMP_list[i].total_score / ((float) IMP_list[i].total_boards)
  1646. X          );
  1647. X          
  1648. X}
  1649. X
  1650. Xint Has_Played (b, n)
  1651. X     Board *b; char *n;
  1652. X/* Returns true if the board b has been played by n. */
  1653. X{
  1654. X  Play_record *p;
  1655. X  int i;
  1656. X
  1657. X  for (p = b->play_records; p != NULL; p = p->next)
  1658. X    for (i = 0; i < 4; i++)
  1659. X      if (!strcasecmp(p->player_names[i], n))
  1660. X    return (1);
  1661. X
  1662. X  return (0);
  1663. X}
  1664. X
  1665. Xvoid main (argc, argv)
  1666. X     int argc; char *argv[];
  1667. X{
  1668. X  int i, skip_count;
  1669. X  char error_buf [80];
  1670. X  Board *b;
  1671. X  Play_record *p;
  1672. X  Board *output_list, *output_list_tail;
  1673. X
  1674. X  no_files = 0;
  1675. X  skip_count = 0;
  1676. X  filename = (char **) malloc ((argc - 1) * sizeof(char *));
  1677. X  for (i = 1; i < argc; i++) {
  1678. X    if (*argv[i] == '-') {
  1679. X      if(argv[i][1] == '\0')
  1680. X    filename[no_files++] = argv[i];
  1681. X      else if (argv[i][1] == 's') {
  1682. X    skip_count = atoi (argv[i]+2);
  1683. X    if (skip_count == 0) {
  1684. X      sprintf (error_buf, "Error in skip count: %s", argv[i]+2);
  1685. X      Abort (error_buf);
  1686. X    }
  1687. X      } else if (!strcmp(argv[i], "-c"))
  1688. X    output_mode = OUTPUT_EMAIL;
  1689. X      else if (!strcmp(argv[i], "-i"))
  1690. X    sort_by_matchpoints = 0;
  1691. X      else if (!strcmp(argv[i], "-l"))
  1692. X    output_mode = OUTPUT_LOG;
  1693. X      else if (!strcmp(argv[i], "-m"))
  1694. X    merge_only = 1;
  1695. X      else if (!strcmp(argv[i], "-p")) {
  1696. X    if (++i == argc)
  1697. X      Abort ("Player name must follow -p parameter");
  1698. X    player_name_of_interest = strdup(argv[i]);
  1699. X      } else if (!strcmp(argv[i], "-t"))
  1700. X    output_mode = OUTPUT_TOTALS;
  1701. X      else if (!strcmp(argv[i], "-tb")) {
  1702. X    output_mode = OUTPUT_TOTALS;
  1703. X    two_column_output = 1;
  1704. X      } else if (!strcmp(argv[i], "-z"))
  1705. X    output_mode = OUTPUT_ZLOG;
  1706. X      else if (!strcmp(argv[i], "-S"))
  1707. X    output_mode = OUTPUT_SUMMARY;
  1708. X      else
  1709. X    Abort ("Error in parameters");
  1710. X    } else
  1711. X      filename[no_files++] = argv[i];
  1712. X  }
  1713. X
  1714. X  if (no_files < 1)
  1715. X    Abort ("At least one email file name must be given.");
  1716. X
  1717. X  Read_File (filename[0]);
  1718. X
  1719. X  for (i = 1; i < no_files; i++) {
  1720. X    if (merge_only)
  1721. X      Merge_File (filename[i]);
  1722. X    else
  1723. X      Read_File (filename[i]);
  1724. X  }
  1725. X
  1726. X  for (i = 0; i < skip_count; i++)
  1727. X    b = Next_Unplayed_Board ();
  1728. X
  1729. X  if (Unplayed_boards != NULL) {
  1730. X    output_list = output_list_tail = Unplayed_boards;
  1731. X    Unplayed_boards = output_list->next;
  1732. X  } else
  1733. X    output_list = output_list_tail = NULL;
  1734. X
  1735. X  while (Unplayed_boards != NULL) {
  1736. X    if ((player_name_of_interest == NULL) || 
  1737. X    Has_Played (Unplayed_boards, player_name_of_interest)) {
  1738. X      output_list_tail->next = Unplayed_boards;
  1739. X      output_list_tail = output_list_tail->next;
  1740. X    }
  1741. X    Unplayed_boards = Unplayed_boards->next;
  1742. X  }
  1743. X  if (output_list != NULL)
  1744. X    output_list_tail->next = NULL;
  1745. X  else
  1746. X    Abort ("There are no boards on the output list.");
  1747. X
  1748. X  for (b = output_list; b != NULL; b = b->next) {
  1749. X    for (p = b->play_records; p != NULL; p = p->next) {
  1750. X      Compute_contract (b, p);
  1751. X      Compute_MIMP_points (b, p);
  1752. X    }
  1753. X    Compute_Matchpoints (b);
  1754. X    Compute_Intl_Matchpoints (b);
  1755. X    if (sort_by_matchpoints)
  1756. X      Sort_play_records_by_matchpoints (b);
  1757. X    else
  1758. X      Sort_play_records_by_imps (b);
  1759. X  }
  1760. X
  1761. X  switch (output_mode) {
  1762. X  case OUTPUT_SUMMARY:
  1763. X    for (b = output_list; b != NULL; b = b->next)
  1764. X      if (b->play_records != NULL)
  1765. X    Write_summary_of_play (stdout, b);
  1766. X    break;
  1767. X
  1768. X  case OUTPUT_EMAIL:
  1769. X    Played_boards = output_list;
  1770. X    Write_Email_Duplicate_File (stdout);
  1771. X    break;
  1772. X
  1773. X  case OUTPUT_LOG:
  1774. X    for (b = output_list; b != NULL; b = b->next)
  1775. X      for (p = b->play_records; p != NULL; p = p->next)
  1776. X    Write_hand (stdout, b, p);
  1777. X    break;
  1778. X
  1779. X  case OUTPUT_ZLOG:
  1780. X    for (b = output_list; b != NULL; b = b->next)
  1781. X      for (p = b->play_records; p != NULL; p = p->next)
  1782. X    Write_hand_compactly (stdout, 1, b, p);
  1783. X    break;
  1784. X
  1785. X  case OUTPUT_TOTALS:
  1786. X    if (two_column_output)
  1787. X      Write_Totals_in_Two_Columns (output_list);
  1788. X    else if (sort_by_matchpoints)
  1789. X      Write_Match_Point_Totals (output_list);
  1790. X    else 
  1791. X      Write_IMP_Totals (output_list);
  1792. X  }
  1793. X}
  1794. END_OF_FILE
  1795. if test 16133 -ne `wc -c <'oktally.c'`; then
  1796.     echo shar: \"'oktally.c'\" unpacked with wrong size!
  1797. fi
  1798. # end of 'oktally.c'
  1799. fi
  1800. echo shar: End of archive 10 \(of 14\).
  1801. cp /dev/null ark10isdone
  1802. MISSING=""
  1803. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  1804.     if test ! -f ark${I}isdone ; then
  1805.     MISSING="${MISSING} ${I}"
  1806.     fi
  1807. done
  1808. if test "${MISSING}" = "" ; then
  1809.     echo You have unpacked all 14 archives.
  1810.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1811. else
  1812.     echo You still need to unpack the following archives:
  1813.     echo "        " ${MISSING}
  1814. fi
  1815. ##  End of shell archive.
  1816. exit 0
  1817.