home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume14 / okbrdge2 / part05 < 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: v14i083:  okbridge2 - computer-mediated bridge game, Part05/14
  5. Message-ID: <3522@master.CNA.TEK.COM>
  6. Date: 7 Sep 92 21:41:34 GMT
  7. Sender: news@master.CNA.TEK.COM
  8. Lines: 1926
  9. Approved: billr@saab.CNA.TEK.COM
  10.  
  11. Submitted-by: mclegg@cs.UCSD.EDU (Matthew Clegg)
  12. Posting-number: Volume 14, Issue 83
  13. Archive-name: okbridge2/Part05
  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 5 (of 14)."
  26. # Contents:  boards.c network.h
  27. # Wrapped by billr@saab on Mon Sep  7 14:33:36 1992
  28. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  29. if test -f 'boards.c' -a "${1}" != "-c" ; then 
  30.   echo shar: Will not clobber existing file \"'boards.c'\"
  31. else
  32. echo shar: Extracting \"'boards.c'\" \(36085 characters\)
  33. sed "s/^X//" >'boards.c' <<'END_OF_FILE'
  34. X/* boards.c -- routines for manipulating boards.
  35. X *
  36. X ! Copyright (C) 1990-1992 by Matthew Clegg.  All Rights Reserved
  37. X ! 
  38. X ! OKbridge is made available as a free service to the Internet.
  39. X ! Accordingly, the following restrictions are placed on its use:
  40. X ! 
  41. X ! 1.  OKbridge may not be modified in any way without the explicit 
  42. X !     permission of Matthew Clegg.  
  43. X ! 
  44. X ! 2.  OKbridge may not be used in any way for commercial advantage.
  45. X !     It may not be placed on for-profit networks or on for-profit
  46. X !     computer systems.  It may not be bundled as part of a package
  47. X !     or service provided by a for-profit organization.
  48. X ! 
  49. X ! If you have questions about restrictions on the use of OKbridge,
  50. X ! write to mclegg@cs.ucsd.edu.
  51. X ! 
  52. X ! DISCLAIMER:  The user of OKbridge accepts full responsibility for any
  53. X ! damage which may be caused by OKbridge.
  54. X *
  55. X */
  56. X
  57. X/* This module provides routines for manipulating the set of boards.
  58. X   Conceptually, the interface to this module is a local database for
  59. X   accessing and updating boards.  However, this module also contains
  60. X   routines for reading and writing boards from files and also
  61. X   routines for transmitting and receiving boards over the network.
  62. X*/
  63. X
  64. X#include <stdio.h>
  65. X#include <sys/types.h>
  66. X#include <time.h>
  67. X#include <string.h>
  68. X
  69. X#define _BOARDS_
  70. X
  71. X#include "types.h"
  72. X#include "cipher.h"
  73. X#include "boards.h"
  74. X/* #include "socket.h" */
  75. X/* #include "parser.h" */
  76. X/* #include "protocol.h" */
  77. X/* #include "network.h" */
  78. X#include "scoring.h"
  79. X
  80. X#ifdef GCC
  81. Xextern sscanf (), strcasecmp (), fgetc (), fprintf (), bcopy ();
  82. Xextern time_t time ();
  83. X#endif
  84. X
  85. Xextern char *month_names[];
  86. Xextern char *malloc ();
  87. Xextern char *strdup ();
  88. Xextern void free ();
  89. Xextern void qsort ();
  90. Xextern int  rand  ();
  91. X
  92. X#define random(n) ((rand()/64) % (n))
  93. X
  94. Xint Header_has_been_generated = 0;
  95. Xchar Email_header_buffer[80];
  96. X
  97. Xchar *local_source = NULL;
  98. X  /* The source to which locally generated boards will be attributed. */
  99. Xint   local_seq_no = 0;
  100. X  /* The sequence number which will be assigned to the next locally
  101. X     generated board. */
  102. X
  103. Xstatic Board *board_freelist = NULL;
  104. Xstatic Play_record *play_record_freelist = NULL;
  105. X
  106. X/* The following primitives are for manipulating the boards and play
  107. X   records. */
  108. X
  109. XBoard *Allocate_board ()
  110. X/* Returns a pointer to a newly allocated board.  Does not fill in any
  111. X   of the fields. */
  112. X{
  113. X  Board *b;
  114. X
  115. X  if (board_freelist == NULL)
  116. X    b = (Board *) malloc(sizeof(Board));
  117. X  else {
  118. X    b = board_freelist;
  119. X    board_freelist = b->next;
  120. X  }
  121. X
  122. X  b->source = NULL;
  123. X  b->serial_no = 0;
  124. X  b->part_score[0] = b->part_score[1] = 0;
  125. X  b->mps_computed = b->imps_computed = 0;
  126. X  b->startup_comment = NULL;
  127. X  b->play_records = NULL;
  128. X
  129. X  return (b);
  130. X}
  131. X
  132. X
  133. Xvoid Deallocate_board (b)
  134. X     Board *b;
  135. X/* Deallocates the board b.  This includes freeing up strings which are
  136. X   part of the structure and de-allocating the play records associated to
  137. X   this board. */
  138. X{
  139. X  Play_record *p;
  140. X
  141. X  if (b->source != NULL) free(b->source);
  142. X  if (b->startup_comment != NULL) free (b->startup_comment);
  143. X
  144. X  while (b->play_records != NULL) {
  145. X    p = b->play_records;
  146. X    b->play_records = p->next;
  147. X    Deallocate_play_record (p);
  148. X  }
  149. X
  150. X  b->next = board_freelist;
  151. X  board_freelist = b;
  152. X
  153. X}
  154. X
  155. X
  156. XPlay_record *Allocate_play_record (n, e, s, w)
  157. X     char *n;
  158. X     char *e;
  159. X     char *s;
  160. X     char *w;
  161. X/* Returns a pointer to a newly allocated play record.  Does not fill in any
  162. X   of the fields. */
  163. X{
  164. X  Play_record *p;
  165. X
  166. X  if (play_record_freelist == NULL)
  167. X    p = (Play_record *) malloc(sizeof(Play_record));
  168. X  else {
  169. X    p = play_record_freelist;
  170. X    play_record_freelist = p->next;
  171. X  }
  172. X
  173. X  p->player_names[0] = NULL;
  174. X  p->player_names[1] = NULL;
  175. X  p->player_names[2] = NULL;
  176. X  p->player_names[3] = NULL;
  177. X
  178. X  if (n != NULL)
  179. X    p->player_names[PLAYER_NORTH] = strdup (n);
  180. X  if (e != NULL)
  181. X    p->player_names[PLAYER_EAST]  = strdup (e);
  182. X  if (s != NULL)
  183. X    p->player_names[PLAYER_SOUTH] = strdup (s);
  184. X  if (w != NULL)
  185. X    p->player_names[PLAYER_WEST]  = strdup (w);
  186. X
  187. X  p->table = 0;
  188. X  p->no_bids = 0;
  189. X  p->no_plays = 0;
  190. X  p->bidding_completed = 0;
  191. X  p->hand_completed = 0;
  192. X  p->contract = p->doubled = p->declarer = 0;
  193. X  p->result = 0;
  194. X  p->tricks[0] = p->tricks[1] = 0;
  195. X  p->above_line[0] = p->above_line[1] = 0;
  196. X  p->below_line[0] = p->below_line[1] = 0;
  197. X  p->match_points[0] = p->match_points[1] = 0.0;
  198. X  p->imatch_points[0] = p->imatch_points[1] = 0.0;
  199. X  p->mimp_points[0] = p->mimp_points[1] = 0;
  200. X  p->next = 0;
  201. X
  202. X  return (p);
  203. X}
  204. X
  205. Xvoid Deallocate_play_record (p)
  206. X     Play_record *p;
  207. X/* Deallocates the play record p.  This includes freeing up strings
  208. X   which are part of the structure. */
  209. X{
  210. X  if (p->player_names[0] != NULL) free (p->player_names[0]);
  211. X  if (p->player_names[1] != NULL) free (p->player_names[1]);
  212. X  if (p->player_names[2] != NULL) free (p->player_names[2]);
  213. X  if (p->player_names[3] != NULL) free (p->player_names[3]);
  214. X
  215. X  p->next = play_record_freelist;
  216. X  play_record_freelist = p;
  217. X
  218. X}
  219. X
  220. X
  221. Xvoid Erase_board_list (list)
  222. X     Board **list;
  223. X/* Deallocates all of the boards in the Board_list. */
  224. X{
  225. X  Board *b;
  226. X
  227. X  while (*list != NULL) {
  228. X    b = *list;
  229. X    *list = b->next;
  230. X    Deallocate_board (b);
  231. X  }
  232. X}
  233. X
  234. Xvoid Append_board (list, b)
  235. X     Board **list;
  236. X     Board *b;
  237. X/* Appends the board b to the list of unplayed boards. */
  238. X{
  239. X  Board *l;
  240. X
  241. X  if (*list == NULL)
  242. X    *list = b;
  243. X  else {
  244. X    for (l = *list; l->next != NULL; l = l->next);
  245. X    l->next = b;
  246. X  }
  247. X  b->next = NULL;
  248. X}
  249. X
  250. Xvoid Append_play_record (b, p)
  251. X     Board *b;
  252. X     Play_record *p;
  253. X/* Appends the play record p to the list of play records associated to the
  254. X   board b. */
  255. X{
  256. X  Play_record *q;
  257. X
  258. X  if (b->play_records == NULL)
  259. X    b->play_records = p;
  260. X  else {
  261. X    for (q = b->play_records; q->next != NULL; q = q->next);
  262. X    q->next = p;
  263. X  }
  264. X  p->next = NULL;
  265. X}
  266. X
  267. Xstatic int  Locate_field (buf, field_no)
  268. X     char *buf;
  269. X     int field_no;
  270. X/* Returns the index in buf of the first character of field_no. */
  271. X{
  272. X  int i, n;
  273. X
  274. X  for (i = 0; (buf[i] == ' ') || (buf[i] == '\t'); i++);
  275. X  n = 1;
  276. X  while ((buf[i] != '\0') && (n < field_no)) {
  277. X    while ((buf[i] != ' ') && (buf[i] != '\t') && (buf[i] != '\0')) i++;
  278. X    while ((buf[i] == ' ') || (buf[i] == '\t')) i++;
  279. X    n++;
  280. X  }
  281. X  return (i);
  282. X}
  283. X
  284. Xvoid Encode_board (b, buf1, buf2)
  285. X     Board *b;
  286. X     char *buf1;
  287. X     char *buf2;
  288. X/* Encodes the board in the string array buf1, buf2.  This encoding does not 
  289. X   include the play records. */
  290. X{
  291. X  int i;
  292. X
  293. X  sprintf (buf1, "%d %d %d %d %s %s", b->serial_no, 
  294. X       b->scoring_mode, b->part_score[0], b->part_score[1],
  295. X       b->source, (b->startup_comment == NULL)? " ": b->startup_comment);
  296. X  buf2[0] = b->dealer + '0';
  297. X  buf2[1] = b->vulnerable[0] + '0';
  298. X  buf2[2] = b->vulnerable[1] + '0';
  299. X  for (i = 0; i < 52; i++)
  300. X    buf2[i+3] = b->deal[i] + '0';
  301. X  buf2[52+3] = '\0';
  302. X}
  303. X
  304. X
  305. XBoard *Decode_board (buf1, buf2)
  306. X     char *buf1;
  307. X     char *buf2;
  308. X/* Decodes the string array buf and returns a corresponding board structure. */
  309. X{
  310. X  Board *b;
  311. X  char source_buf[80];
  312. X  int i, comment_index;
  313. X
  314. X  b = Allocate_board ();
  315. X  sscanf (buf1, "%d %d %d %d %s", &(b->serial_no), &(b->scoring_mode),
  316. X      &(b->part_score[0]), &(b->part_score[1]),
  317. X      source_buf);
  318. X  comment_index = Locate_field (buf1, 6);
  319. X  b->source = strdup (source_buf);
  320. X  b->startup_comment = strdup (buf1 + comment_index);
  321. X  
  322. X  b->dealer = buf2[0] - '0';
  323. X  b->vulnerable[0] = buf2[1] - '0';
  324. X  b->vulnerable[1] = buf2[2] - '0';
  325. X  for (i = 0; i < 52; i++)
  326. X    b->deal[i] = buf2[i+3] - '0';
  327. X
  328. X  return (b);
  329. X}
  330. X
  331. X
  332. Xvoid Encode_play_record (p, buf1, buf2, buf3)
  333. X     Play_record *p;
  334. X     char *buf1;
  335. X     char *buf2;
  336. X     char *buf3;
  337. X/* Encodes the play_record p into buffers buf1 .. buf3. */
  338. X{
  339. X  int i, j;
  340. X
  341. X  sprintf (buf1, "%d %d %d %d %d %d %d %d %d %s %s %s %s",
  342. X       p->bidding_completed, p->hand_completed, p->result,
  343. X       p->tricks[0], p->tricks[1],
  344. X       p->above_line[0], p->above_line[1], 
  345. X       p->below_line[0], p->below_line[1],
  346. X       p->player_names[0], p->player_names[1],
  347. X       p->player_names[2], p->player_names[3]);
  348. X
  349. X  for (i = j = 0; i < p->no_bids; i++) {
  350. X    buf2[j++] = p->bids[i] + 'A';
  351. X    if (p->alerts[i]) buf2[j++] = '!';
  352. X  }
  353. X  buf2[j++] = '\0';
  354. X
  355. X  for (i = 0; i < p->no_plays; i++)
  356. X    buf3[i] = (p->play_list[i] < 26)? 
  357. X      'a' + p->play_list[i]: 'A' + p->play_list[i]-26;
  358. X  buf3[p->no_plays] = '\0';
  359. X  
  360. X}
  361. X
  362. XPlay_record *Decode_play_record (buf1, buf2, buf3)
  363. X     char *buf1;
  364. X     char *buf2;
  365. X     char *buf3;
  366. X/* Decodes the strings buf1 .. buf3, returning a corresponding play record
  367. X   structure.  Returns NULL if an error occurs in the decoding.  */
  368. X{
  369. X  Play_record *p;
  370. X  int i, n;
  371. X  char p0[15], p1[15], p2[15], p3[15];
  372. X
  373. X  p = Allocate_play_record (NULL, NULL, NULL, NULL);
  374. X  n = sscanf (buf1, "%d %d %d %d %d %d %d %d %d %s %s %s %s",
  375. X          &(p->bidding_completed), &(p->hand_completed), &(p->result),
  376. X          &(p->tricks[0]), &(p->tricks[1]), 
  377. X          &(p->above_line[0]), &(p->above_line[1]), 
  378. X          &(p->below_line[0]), &(p->below_line[1]),
  379. X          p0, p1, p2, p3);
  380. X
  381. X  if (n < 9) {
  382. X    Deallocate_play_record (p);
  383. X    return (NULL);
  384. X  }
  385. X
  386. X  p->player_names[0] = strdup(p0);
  387. X  p->player_names[1] = strdup(p1);
  388. X  p->player_names[2] = strdup(p2);
  389. X  p->player_names[3] = strdup(p3);
  390. X
  391. X  for (i = p->no_bids = 0; buf2[i] != '\0';) {
  392. X    p->bids[p->no_bids] = buf2[i++] - 'A';
  393. X    if ((p->bids[p->no_bids] < 0) || (37 < p->bids[p->no_bids])) {
  394. X      Deallocate_play_record (p);
  395. X      return (NULL);
  396. X    }
  397. X    if (buf2[i] == '!') {
  398. X      p->alerts[p->no_bids] = 1;
  399. X      i++;
  400. X    } else
  401. X      p->alerts[p->no_bids] = 0;
  402. X    p->no_bids++;
  403. X  }
  404. X  
  405. X  p->no_plays = strlen(buf3);
  406. X  for (i = 0; i < p->no_plays; i++)
  407. X    if (('a' <= buf3[i]) && (buf3[i] <= 'z'))
  408. X      p->play_list[i] = buf3[i] - 'a';
  409. X    else if (('A' <= buf3[i]) && (buf3[i] <= 'Z'))
  410. X      p->play_list[i] = buf3[i] - 'A' + 26;
  411. X    else {
  412. X      Deallocate_play_record (p);
  413. X      return (NULL);
  414. X    }
  415. X
  416. X  return (p);
  417. X}
  418. X
  419. X
  420. X/* Routines for searching boards and play records. */
  421. X
  422. Xstatic Board *Search_for_board (list, b)
  423. X     Board *list;
  424. X     Board *b;
  425. X/* Searches the current set of email duplicate boards for a board which
  426. X   matches b.  Returns a pointer to the matching board if it is found,
  427. X   or NULL otherwise. */
  428. X{
  429. X  int j, matches;
  430. X  Board *c;
  431. X
  432. X  for (c = list; c != NULL; c = c->next) {
  433. X    matches = 1;
  434. X    for (j = 0; (j < 52) && matches; j++)
  435. X      if (b->deal[j] != c->deal[j])
  436. X    matches = 0;
  437. X    if (matches)
  438. X      return (c);
  439. X  }
  440. X  return (NULL);
  441. X}
  442. X
  443. XPlay_record *Search_for_play_record (b, p)
  444. X     Board *b;
  445. X     Play_record *p;
  446. X/* Searches the list of play records associated with the board b for a
  447. X   record of play by the same players as mentioned in p.  If such a
  448. X   record is found, then returns a pointer to it.  Otherwise, returns
  449. X   NULL. */
  450. X{
  451. X  Play_record *q;
  452. X  int i, match;
  453. X
  454. X  for (q = b->play_records; q != NULL; q = q->next) {
  455. X    match = 1;
  456. X    for (i = 0; (i < 4) && match; i++)
  457. X      if (strcasecmp(p->player_names[i], q->player_names[i]))
  458. X    match = 0;
  459. X    if (match)
  460. X      return (q);
  461. X  }
  462. X  return (NULL);
  463. X}
  464. X
  465. XPlay_record *Locate_play_record_by_foursome 
  466. X  (b, n, e, s, w)
  467. X     Board *b;
  468. X     char *n;
  469. X     char *e;
  470. X     char *s;
  471. X     char *w;
  472. X/* Searches the list of play records associated with the board b for a record
  473. X   where the names of the players exactly match n, e, s, and w, in order.
  474. X   Returns the play record if found, or NULL if no matching record is found. 
  475. X*/
  476. X{
  477. X  Play_record *p;
  478. X
  479. X  for (p = b->play_records; p != NULL; p = p->next) {
  480. X    if (!strcmp(p->player_names[PLAYER_NORTH], n) &&
  481. X    !strcmp(p->player_names[PLAYER_EAST], e)  &&
  482. X    !strcmp(p->player_names[PLAYER_SOUTH], s) &&
  483. X    !strcmp(p->player_names[PLAYER_WEST], w))
  484. X      return (p);
  485. X  }
  486. X  return (NULL);
  487. X
  488. X}
  489. X
  490. Xstatic Play_record *Locate_play_record_by_partnership 
  491. X  (bd, a, b, side)
  492. X     Board *bd;
  493. X     char *a;
  494. X     char *b;
  495. X     int *side;
  496. X/* Searches the list of play records associated with the board b for a
  497. X   record where the names of one of the partnerships matches those of a
  498. X   and b. If such a record is found, returns a pointer to the play record
  499. X   and sets side to the side of the matching partnership.  If no match
  500. X   is found, returns NULL.
  501. X*/
  502. X{
  503. X  Play_record *p;
  504. X
  505. X  for (p = bd->play_records; p != NULL; p = p->next) {
  506. X    if ((!strcmp(p->player_names[PLAYER_NORTH], a) &&
  507. X     !strcmp(p->player_names[PLAYER_SOUTH], b)) ||
  508. X    (!strcmp(p->player_names[PLAYER_SOUTH], a) &&
  509. X     !strcmp(p->player_names[PLAYER_NORTH], b))) {
  510. X      *side = SIDE_NS;
  511. X      return (p);
  512. X    }
  513. X    if ((!strcmp(p->player_names[PLAYER_EAST], a) &&
  514. X     !strcmp(p->player_names[PLAYER_WEST], b)) ||
  515. X    (!strcmp(p->player_names[PLAYER_WEST], a) &&
  516. X     !strcmp(p->player_names[PLAYER_EAST], b))) {
  517. X      *side = SIDE_EW;
  518. X      return (p);
  519. X    }
  520. X  }
  521. X  return (NULL);
  522. X}
  523. X
  524. Xstatic Play_record *Locate_play_record_by_player (b, p, pos)
  525. X     Board *b;
  526. X     char *p;
  527. X     int *pos;
  528. X/* Searches the list of play records associated with the board b for a
  529. X   record where one the players has the same name as p.  If such a record
  530. X   is found, returns a pointer to the play record and sets pos to the
  531. X   position of the matching name.  If no match is found, returns NULL.
  532. X*/
  533. X{
  534. X  Play_record *pr;
  535. X  int i;
  536. X
  537. X  for (pr = b->play_records; pr != NULL; pr = pr->next) {
  538. X    for (i = 0; i < 4; i++) {
  539. X      if (!strcasecmp(pr->player_names[i], p)) {
  540. X    *pos = i;
  541. X    return (pr);
  542. X      }
  543. X    }
  544. X  }
  545. X  return (NULL);
  546. X}
  547. X
  548. X
  549. X/* Primitives for accessing email duplicate files: */
  550. X
  551. Xstatic void Generate_email_header ()
  552. X{
  553. X  if (Header_has_been_generated)
  554. X    return;
  555. X
  556. X  sprintf (Email_header_buffer,"%s %s",
  557. X       "This is an email duplicate file for OKBridge version",
  558. X       major_revision_level);
  559. X  Header_has_been_generated = 1;
  560. X}
  561. X
  562. Xstatic int Get_line (f, buf, buflen)
  563. X     FILE *f;
  564. X     char *buf;
  565. X     int buflen;
  566. X/* Reads a line from file f, placing up to buflen-1 characters into buf,
  567. X   terminated by a '\0'.  Returns the number of characters actually read
  568. X   or -1 if EOF.
  569. X*/
  570. X{
  571. X    int n, ch;
  572. X
  573. X    if (fgets(buf, buflen, f) == NULL)
  574. X      return (-1);
  575. X
  576. X    n = strlen(buf);
  577. X    if ((n >= buflen) && (buf[n-1] != '\n'))
  578. X      do
  579. X        { ch = fgetc (f); }
  580. X      while ((ch != '\n') && (ch != EOF));
  581. X    else
  582. X      buf[--n] = '\0';
  583. X
  584. X    return (n);
  585. X}
  586. X
  587. Xint Read_Email_Header (f)
  588. X     FILE *f;
  589. X/* Searches the file f until an email header is found.  If the header
  590. X   is found, then returns 0.  Otherwise, returns 1. */
  591. X{
  592. X  char buf[100];
  593. X
  594. X  Generate_email_header ();
  595. X  while (Get_line (f, buf, 100) >= 0) {
  596. X    if (!strcmp(buf, Email_header_buffer))
  597. X      return (0);
  598. X  }
  599. X
  600. X  return (1);
  601. X}
  602. X
  603. Xvoid Write_Email_Header (f)
  604. X     FILE *f;
  605. X/* Writes an email header to the file f. */
  606. X{
  607. X  Generate_email_header ();
  608. X  fprintf (f, "%s\n", Email_header_buffer);
  609. X}
  610. X
  611. X
  612. Xint Read_Email_Board (f, c, b)
  613. X     FILE *f;
  614. X     Cipher *c;
  615. X     Board **b;
  616. X/* Reads a board from the file f using the cipher descriptor c.
  617. X   Stores in b a pointer to an allocated board record containing the
  618. X   data which has been read.  If successful, returns 0.  If the end of 
  619. X   file is reached, returns 1.  If some other error occurs, returns -1.
  620. X*/
  621. X{
  622. X  char buf1[100], buf2[100], buf3[100];
  623. X  Play_record *p;
  624. X
  625. X  if (Read_Ciphered_Line (f, c, buf1, 100) < 0)
  626. X    return (1);
  627. X
  628. X  if (Read_Ciphered_Line (f, c, buf2, 100) != 55)
  629. X    return (-1);
  630. X
  631. X  *b = Decode_board (buf1, buf2);
  632. X  (*b)->play_records = NULL;
  633. X
  634. X  if (Read_Ciphered_Line (f, c, buf1, 100) < 0) return (-1);
  635. X  while (strcmp(buf1, "--")) {
  636. X    if (Read_Ciphered_Line (f, c, buf2, 100) < 0) return (-1);
  637. X    if (Read_Ciphered_Line (f, c, buf3, 100) < 0) return (-1);
  638. X    if (!strcmp(buf2, "--") || !strcmp(buf3, "--")) return (-1);
  639. X
  640. X    p = Decode_play_record (buf1, buf2, buf3);
  641. X    if (p == NULL)
  642. X      return (-1);
  643. X
  644. X    p->next = (*b)->play_records;
  645. X    (*b)->play_records = p;
  646. X    if (Read_Ciphered_Line (f, c, buf1, 100) < 0) return (-1);
  647. X  }
  648. X  return (0);
  649. X}
  650. X
  651. Xvoid Write_Email_Board (f, c, b)
  652. X     FILE *f;
  653. X     Cipher *c;
  654. X     Board *b;
  655. X/* Writes the board b to the file f using the cipher descriptor c. */
  656. X{
  657. X  char buf1[100], buf2[100], buf3[100];
  658. X  Play_record *p;
  659. X
  660. X  Encode_board (b, buf1, buf2);
  661. X  Write_Ciphered_Line (f, c, buf1);
  662. X  Write_Ciphered_Line (f, c, buf2);
  663. X
  664. X  for (p = b->play_records; p != NULL; p = p->next) {
  665. X    Encode_play_record (p, buf1, buf2, buf3);
  666. X    Write_Ciphered_Line (f, c, buf1);
  667. X    Write_Ciphered_Line (f, c, buf2);
  668. X    Write_Ciphered_Line (f, c, buf3);
  669. X  }
  670. X  fprintf (f, "--\n");
  671. X}
  672. X
  673. Xstatic void Copy_play_record (p, q)
  674. X     Play_record *p;
  675. X     Play_record *q;
  676. X/* Copies the contents of the play record p to q, without destroying
  677. X   q's next field. */
  678. X{
  679. X  Play_record *r = q->next;
  680. X  int i;
  681. X
  682. X  for (i = 0; i < 4; i++)
  683. X    if (q->player_names[i] != NULL)
  684. X      free (q->player_names[i]);
  685. X
  686. X  bcopy (p, q, sizeof(Play_record));
  687. X  q->next = r;
  688. X  free (p);
  689. X}
  690. X
  691. Xvoid Merge_play_record (b, p)
  692. X     Board *b;
  693. X     Play_record *p;
  694. X/* Links p into the list of play records for the board b.  If b already
  695. X   has a record of play for the players listed in p, then the older record
  696. X   is deleted.
  697. X*/
  698. X{
  699. X  Play_record *q;
  700. X  int i, match;
  701. X
  702. X  for (q = b->play_records; q->next != NULL; q = q->next) {
  703. X    match = 1;
  704. X    for (i = 0; (i < 4) && match; i++)
  705. X      if (strcasecmp(p->player_names[i], q->player_names[i]))
  706. X    match = 0;
  707. X    if (match) {
  708. X      if (p->hand_completed)
  709. X    Copy_play_record (p, q);
  710. X      else if (p->bidding_completed && !q->hand_completed)
  711. X    Copy_play_record (p, q);
  712. X      else if (!q->bidding_completed)
  713. X    Copy_play_record (p, q);
  714. X      else
  715. X    Deallocate_play_record (p);
  716. X      return;
  717. X    }
  718. X  }
  719. X
  720. X}
  721. X
  722. Xstatic int Merge_board (list, b)
  723. X     Board *list;
  724. X     Board *b;
  725. X/* Searches the board list for a board matching b.  If one is found,
  726. X   then destructively merges the play records in b with those in the 
  727. X   matching record.  If no matching board is found, then does nothing.
  728. X   Returns 0 if successful, and 1 if no match is found.
  729. X*/
  730. X{
  731. X  Board *c;
  732. X  Play_record *p, *q;
  733. X
  734. X  c = Search_for_board (list, b);
  735. X  if (c == NULL)
  736. X    return (1);
  737. X
  738. X  p = b->play_records;
  739. X  while (p != NULL) {
  740. X    q = p->next;
  741. X    p->next = NULL;
  742. X    Merge_play_record (c, p);
  743. X    p = q;
  744. X  }
  745. X  b->play_records = NULL;
  746. X  Deallocate_board (b);
  747. X
  748. X  return (0);
  749. X}
  750. X
  751. Xint Load_Email_Duplicate_File (f)
  752. X     FILE *f;
  753. X/* Reads an entire email duplicate file, recording each of the hands 
  754. X   read from the file into the current list of boards. */
  755. X{
  756. X  Board *b, *tail;
  757. X  Cipher c;
  758. X  int status;
  759. X
  760. X  if (Read_Email_Header (f))
  761. X    return (1);
  762. X
  763. X  if (Read_Cipher_Descriptor(f, &c))
  764. X    return (-1);
  765. X
  766. X  tail = Unplayed_boards;
  767. X  if (tail != NULL)
  768. X    while (tail->next != NULL) tail = tail->next;
  769. X
  770. X  status = Read_Email_Board (f, &c, &b);
  771. X  while (status == 0) {
  772. X    if ((Unplayed_boards == NULL) || Merge_board (Unplayed_boards, b)) {
  773. X      if (tail == NULL) {
  774. X    Unplayed_boards = tail = b;
  775. X      } else {
  776. X    tail->next = b;
  777. X    tail = b;
  778. X      }
  779. X      b->next = NULL;
  780. X    }
  781. X    status = Read_Email_Board (f, &c, &b);
  782. X  }
  783. X
  784. X  if (status == 1)
  785. X    return (0);
  786. X  else
  787. X    return (1);
  788. X}
  789. X
  790. Xint Merge_Email_Duplicate_File (f, list)
  791. X     FILE *f;
  792. X     Board *list;
  793. X/* Reads an email duplicate file.  For each board found in the file,
  794. X   if the same board occurs among the list of boards, then updates
  795. X   the data associated with that board using the data read from the file.
  796. X   Discards boards which do not match those stored in memory.
  797. X   If successful, returns 0.  If the header could not be found, returns 1.
  798. X   If some other error occurs, returns -1.
  799. X*/
  800. X{
  801. X  Board *b;
  802. X  Cipher c;
  803. X  int status;
  804. X
  805. X  if (Read_Email_Header (f))
  806. X    return (1);
  807. X
  808. X  if (Read_Cipher_Descriptor(f, &c))
  809. X    return (-1);
  810. X
  811. X  status = Read_Email_Board (f, &c, &b);
  812. X  while (status == 0) {
  813. X    if (!Merge_board (list, b))
  814. X      Deallocate_board (b);
  815. X    status = Read_Email_Board (f, &c, &b);
  816. X  }
  817. X
  818. X  if (status == 1)
  819. X    return (0);
  820. X  else
  821. X    return (1);
  822. X}
  823. X
  824. Xvoid Write_Email_Duplicate_File (f)
  825. X     FILE *f;
  826. X/* Writes the list of played and unplayed boards to the file f. */
  827. X{
  828. X  Board *b;
  829. X  Cipher c;
  830. X
  831. X  Write_Email_Header (f);
  832. X  Create_Cipher_Descriptor (f, &c);
  833. X  Write_Cipher_Descriptor (f, &c);
  834. X
  835. X  for (b = Played_boards; b != NULL; b = b->next)
  836. X    Write_Email_Board (f, &c, b);
  837. X
  838. X  for (b = Unplayed_boards; b != NULL; b = b->next)
  839. X    Write_Email_Board (f, &c, b);
  840. X  
  841. X}
  842. X
  843. X
  844. X/* Routines for accessing and updating the current set of email 
  845. X   duplicate boards. */
  846. X
  847. X
  848. Xvoid Generate_local_source_name ()
  849. X{
  850. X  char buf[20];
  851. X  time_t current_time;
  852. X  struct tm *decoded_time;
  853. X
  854. X  time (¤t_time);
  855. X  decoded_time = localtime (¤t_time);
  856. X  sprintf (buf, "%s%0d", month_names[decoded_time->tm_mon],
  857. X       decoded_time->tm_mday);
  858. X  local_source = strdup(buf);
  859. X
  860. X}
  861. X
  862. Xstatic void shuffle_the_deck (cards)
  863. X    deal cards;
  864. X/* Using the algorithm suggested by Douglas Foxvog.  Thanks, Doug! */
  865. X{
  866. X    int i, t, c;
  867. X    deal shuffle;
  868. X    for (i = 0; i < 52; i++) 
  869. X        shuffle [i] = i;
  870. X    for (i = 0; i < 51; i++) {
  871. X        c = random (52 - i);
  872. X        t = shuffle[i+c]; 
  873. X        shuffle[i+c] = shuffle[i];
  874. X        shuffle[i] = t;
  875. X    };
  876. X    for (i = 0; i < 52; i++)
  877. X        cards[shuffle[i]] = (i % 4);
  878. X        
  879. X}
  880. X
  881. XBoard *Generate_Random_Match_Board (scoring, prevboard)
  882. X     int scoring;
  883. X     Board *prevboard;
  884. X/* Generates a random match board and appends it to the Board_list. */
  885. X{
  886. X  int r;
  887. X  Board *b;
  888. X
  889. X  if (local_source == NULL)
  890. X    Generate_local_source_name ();
  891. X
  892. X  b = Allocate_board ();
  893. X
  894. X  b->source = strdup (local_source);
  895. X  b->serial_no = ++local_seq_no;
  896. X
  897. X  if (prevboard == NULL)
  898. X    r = local_seq_no + ROTATION_LENGTH - 1;
  899. X  else {
  900. X    for (r = 0; r < ROTATION_LENGTH; r++)
  901. X      if ((prevboard->dealer == dealer_list[r]) &&
  902. X      (prevboard->vulnerable[SIDE_NS] == ns_vulnerability_list[r]) &&
  903. X      (prevboard->vulnerable[SIDE_EW] == ew_vulnerability_list[r]))
  904. X    break;
  905. X    r += 1;
  906. X  }
  907. X  r %= ROTATION_LENGTH;
  908. X
  909. X  b->dealer = dealer_list[r];
  910. X  b->vulnerable[SIDE_NS] = ns_vulnerability_list[r];
  911. X  b->vulnerable[SIDE_EW] = ew_vulnerability_list[r];
  912. X  b->scoring_mode = scoring;
  913. X  shuffle_the_deck (b->deal);
  914. X  
  915. X  return (b);
  916. X}
  917. X
  918. XBoard *Generate_Random_Rubber_Board (prevboard, prevplay)
  919. X     Board *prevboard;
  920. X     Play_record *prevplay;
  921. X/* Generates a random rubber board and returns a pointer to it,
  922. X   based upon the part score and result recorded in the previously
  923. X   played board b and play record p.  If b or p is NULL, then
  924. X   generates a board with neither side vulnerable and a 0 part score.
  925. X*/
  926. X{
  927. X  int r;
  928. X  Board *b;
  929. X
  930. X  if (local_source == NULL)
  931. X    Generate_local_source_name ();
  932. X
  933. X  b = Allocate_board ();
  934. X
  935. X  b->source = strdup (local_source);
  936. X  b->serial_no = local_seq_no + 1;
  937. X
  938. X  if ((prevboard == NULL) || (prevplay == NULL)) {
  939. X    r = local_seq_no++ % ROTATION_LENGTH;
  940. X    b->dealer = dealer_list [r];
  941. X    b->vulnerable[SIDE_NS] = ns_vulnerability_list[r];
  942. X    b->vulnerable[SIDE_EW] = ew_vulnerability_list[r];
  943. X  } else {
  944. X    b->dealer = player_next [prevboard->dealer];
  945. X    b->vulnerable[SIDE_NS] = prevboard->vulnerable[SIDE_NS];
  946. X    b->vulnerable[SIDE_EW] = prevboard->vulnerable[SIDE_EW];
  947. X    b->part_score[SIDE_NS] = prevboard->part_score[SIDE_NS] +
  948. X      prevplay->below_line[SIDE_NS];
  949. X    b->part_score[SIDE_EW] = prevboard->part_score[SIDE_EW] +
  950. X      prevplay->below_line[SIDE_EW];
  951. X    if (b->part_score[SIDE_NS] > 100) {
  952. X      if (prevboard->vulnerable[SIDE_NS])
  953. X    b->vulnerable[SIDE_NS] = b->vulnerable[SIDE_EW] = 0;
  954. X      else
  955. X    b->vulnerable[SIDE_NS] = 1;
  956. X      b->part_score[SIDE_NS] = b->part_score[SIDE_EW] = 0;
  957. X    } else if (b->part_score[SIDE_EW] > 100) {
  958. X      if (prevboard->vulnerable[SIDE_EW] > 100)
  959. X    b->vulnerable[SIDE_EW] = b->vulnerable[SIDE_NS] = 0;
  960. X      else
  961. X    b->vulnerable[SIDE_EW] = 1;
  962. X      b->part_score[SIDE_NS] = b->part_score[SIDE_EW] = 0;
  963. X    }
  964. X  }
  965. X
  966. X  b->scoring_mode = RUBBER_SCORING;
  967. X  shuffle_the_deck (b->deal);
  968. X  
  969. X  return (b);
  970. X}
  971. X
  972. X
  973. X
  974. Xvoid Clear_All_Boards ()
  975. X/* Clears the list of played and unplayed boards. */
  976. X{
  977. X  Erase_board_list (&Unplayed_boards);
  978. X  Erase_board_list (&Played_boards);
  979. X
  980. X  Unplayed_boards = NULL;
  981. X  Played_boards = NULL;
  982. X  Played_boards_tail = NULL;
  983. X}
  984. X
  985. Xint Board_is_Available ()
  986. X/* Returns true if there is a board available in the list of unplayed
  987. X   boards. */
  988. X{
  989. X  return (Unplayed_boards != NULL);
  990. X}
  991. X
  992. XBoard *Next_Unplayed_Board ()
  993. X/* If there is a board on the list of unplayed boards, then unlinks it and
  994. X   returns it.  Otherwise, returns NULL. */
  995. X{
  996. X  Board *b;
  997. X
  998. X  if (Unplayed_boards != NULL) {
  999. X    b = Unplayed_boards;
  1000. X    Unplayed_boards = b->next;
  1001. X    b->next = NULL;
  1002. X  } else
  1003. X    b = NULL;
  1004. X
  1005. X  return (b);
  1006. X}
  1007. X
  1008. Xvoid Record_Played_Board (b)
  1009. X     Board *b;
  1010. X/* Appends the board to the list of played boards. */
  1011. X{
  1012. X  if (Played_boards == NULL) {
  1013. X    Played_boards = Played_boards_tail = b;
  1014. X  } else {
  1015. X    Played_boards_tail->next = b;
  1016. X    Played_boards_tail = b;
  1017. X  }
  1018. X  Played_boards_tail->next = NULL;
  1019. X}
  1020. X
  1021. X/* Scoring routines: */
  1022. X
  1023. X
  1024. Xint Highcard_points (b, side)
  1025. X     Board *b;
  1026. X     int side;
  1027. X/* Returns the number of highcard points held by the partnership 'side'. */
  1028. X{
  1029. X  int partner = side + 2;
  1030. X  int i, hcp = 0;
  1031. X
  1032. X  for (i = 0; i < 52; i++)
  1033. X    if ((b->deal[i] == side) || (b->deal[i] == partner)) {
  1034. X      if (rank_of(i) > 8)
  1035. X    hcp += rank_of(i) - 8;
  1036. X    }
  1037. X  return (hcp);
  1038. X
  1039. X}
  1040. X
  1041. Xvoid Compute_total_score_by_partnership 
  1042. X  (list, a, b, d, mp, imp)
  1043. X     Board *list;
  1044. X     char *a;
  1045. X     char *b;
  1046. X     int *d;
  1047. X     float *mp;
  1048. X     float *imp;
  1049. X/* Computes the total scores for the partnership (a,b).  Returns in d the
  1050. X   total of the (duplicate) scores, in mp the total of the match point scores,
  1051. X   and in imp the total of the imp scores.
  1052. X*/
  1053. X{
  1054. X  int s;
  1055. X  Play_record *p;
  1056. X  Board *bd;
  1057. X
  1058. X  *d = 0;
  1059. X  *mp = *imp = 0.0;
  1060. X  for (bd = list; bd != NULL; bd = bd->next) {
  1061. X    if (!bd->mps_computed)
  1062. X      Compute_Matchpoints (bd);
  1063. X    if (!bd->imps_computed)
  1064. X      Compute_Intl_Matchpoints (bd);
  1065. X
  1066. X    p = Locate_play_record_by_partnership (bd, a, b, &s);
  1067. X    if (p != NULL) {
  1068. X      *d += p->below_line[s];
  1069. X      *mp += p->match_points[s];
  1070. X      *imp += p->imatch_points[s];
  1071. X    }
  1072. X  }
  1073. X}
  1074. X
  1075. Xvoid Compute_total_score_by_player
  1076. X  (list, n, d, mp, imp)
  1077. X     Board *list;
  1078. X     char *n;
  1079. X     int *d;
  1080. X     float *mp;
  1081. X     float *imp;
  1082. X/* Computes the total score for the player p.  Returns in d the total of
  1083. X   the (duplicate) scores, in mp the total of the match point scores, and
  1084. X   in mp the total of the imp scores. */
  1085. X{
  1086. X  int s, pos;
  1087. X  Board *b;
  1088. X  Play_record *p;
  1089. X
  1090. X  *d = 0;
  1091. X  *mp = *imp = 0.0;
  1092. X  for (b = list; b != NULL; b = b->next) {
  1093. X    if (!b->mps_computed)
  1094. X      Compute_Matchpoints (b);
  1095. X    if (!b->imps_computed)
  1096. X      Compute_Intl_Matchpoints (b);
  1097. X
  1098. X    p = Locate_play_record_by_player (b, n, &pos);
  1099. X    s = side_of(pos);
  1100. X    if (p != NULL) {
  1101. X      *d += p->below_line[s];
  1102. X      *mp += p->match_points[s];
  1103. X      *imp += p->imatch_points[s];
  1104. X    }
  1105. X  }
  1106. X}
  1107. X
  1108. X
  1109. Xstatic int NS_score (p)
  1110. X     Play_record *p;
  1111. X{
  1112. X  return (p->below_line[SIDE_NS] - p->below_line[SIDE_EW]);
  1113. X}
  1114. X
  1115. Xint score_compare (p1, p2)
  1116. X     Play_record **p1;
  1117. X     Play_record **p2;
  1118. X{
  1119. X  if (NS_score(*p1) < NS_score(*p2))
  1120. X    return (-1);
  1121. X  else if (NS_score(*p1) == NS_score(*p2))
  1122. X    return (0);
  1123. X  else
  1124. X    return (1);
  1125. X}
  1126. X
  1127. Xvoid Compute_Matchpoints (b)
  1128. X     Board *b;
  1129. X/* Computes the match point totals for the current board. */
  1130. X{
  1131. X  Play_record *Play_array[100], *p;
  1132. X  int i, j, n, t, score_compare();
  1133. X  float base;
  1134. X
  1135. X  b->mps_computed = 1;
  1136. X  if ((b->play_records == NULL) || (b->play_records->next == NULL))
  1137. X    return;
  1138. X
  1139. X  n = 0;
  1140. X  for (p = b->play_records; p != NULL; p = p->next) {
  1141. X    p->match_points[0] = p->match_points[1] = 0.0;
  1142. X    if (p->hand_completed)
  1143. X      Play_array[n++] = p;
  1144. X  }
  1145. X
  1146. X  qsort (Play_array, n, sizeof(Play_record *), score_compare);
  1147. X  
  1148. X  i = 0;
  1149. X  base = 0.5 / ((float) (n-1));
  1150. X  while (i < n) {
  1151. X    for (t = i; (t < n) && 
  1152. X     (NS_score(Play_array[i]) == NS_score(Play_array[t])); t++);
  1153. X    for (j = i; j < t; j++) {
  1154. X      Play_array[j]->match_points[0] = ((float) t + i - 1) * base;
  1155. X      Play_array[j]->match_points[1] = 
  1156. X    1.0 - Play_array[j]->match_points[0];
  1157. X    }
  1158. X    i = t;
  1159. X  }
  1160. X
  1161. X}
  1162. X
  1163. Xvoid Compute_Intl_Matchpoints (b)
  1164. X     Board *b;
  1165. X/* Computes the internation match point totals for the current board. */
  1166. X{
  1167. X  Play_record *p, *q;
  1168. X  int pdiff, qdiff;
  1169. X  int contractor, defender;
  1170. X  int no_tables = -1;
  1171. X
  1172. X  b->imps_computed = 1;
  1173. X  if (b->play_records == NULL)
  1174. X    return;
  1175. X  else if (b->play_records->next == NULL) {
  1176. X    p = b->play_records;
  1177. X    Compute_MIMP_points (b, p);
  1178. X    return;
  1179. X  }
  1180. X
  1181. X  for (p = b->play_records; p != NULL; p = p->next) {
  1182. X    p->imatch_points[0] = p->imatch_points[1] = 0.0;
  1183. X    contractor = side_of (p->declarer);
  1184. X    defender   = 1 - contractor;
  1185. X    if (!p->hand_completed)
  1186. X      continue;
  1187. X    no_tables += 1;
  1188. X    pdiff = p->below_line[contractor] - p->below_line[defender];
  1189. X    for (q = b->play_records; q != NULL; q = q->next) {
  1190. X      if (!q->hand_completed)
  1191. X    continue;
  1192. X      qdiff = q->below_line[contractor] - q->below_line[defender];
  1193. X      if (pdiff > qdiff)
  1194. X    p->imatch_points[contractor] += 
  1195. X      ((float) IMP_rating (pdiff - qdiff)) * 0.5;
  1196. X      else if (pdiff < qdiff)
  1197. X    p->imatch_points[contractor] -= 
  1198. X      ((float) IMP_rating (qdiff - pdiff)) * 0.5;
  1199. X    }
  1200. X    p->imatch_points[defender] = -p->imatch_points[contractor];
  1201. X  }
  1202. X
  1203. X  if (no_tables > 0)
  1204. X    for (p = b->play_records; p != NULL; p = p->next) {
  1205. X      p->imatch_points[0] = p->imatch_points[0] / ((float) no_tables);
  1206. X      p->imatch_points[1] = p->imatch_points[1] / ((float) no_tables);
  1207. X    }
  1208. X}
  1209. X
  1210. Xvoid Compute_contract (b, p)
  1211. X     Board *b;
  1212. X     Play_record *p;
  1213. X/* Computes the contract for the play record p based upon the bids present
  1214. X   in the bidding list. */
  1215. X{
  1216. X  int i, bidder, contractor;
  1217. X
  1218. X  p->contract = BID_PASS;
  1219. X  p->doubled  = 0;
  1220. X  p->declarer = PLAYER_NORTH;
  1221. X
  1222. X  if (p->no_bids == 0)
  1223. X    return;
  1224. X
  1225. X  i = p->no_bids - 1;
  1226. X  switch (i%4) {
  1227. X  case 0: bidder = b->dealer; break;
  1228. X  case 1: bidder = player_next[b->dealer]; break;
  1229. X  case 2: bidder = player_partner[b->dealer]; break;
  1230. X  case 3: bidder = player_prev[b->dealer]; break;
  1231. X  }
  1232. X
  1233. X  do {
  1234. X    if (p->bids[i] == BID_REDOUBLE)
  1235. X      p->doubled = 2;
  1236. X    else if (p->bids[i] == BID_DOUBLE) {
  1237. X      if (!p->doubled)
  1238. X    p->doubled = 1;
  1239. X    } else if (p->bids[i] != BID_PASS) {
  1240. X      p->contract = p->bids[i];
  1241. X      contractor  = side_of (bidder);
  1242. X      break;
  1243. X    }
  1244. X    bidder = player_prev[bidder];
  1245. X    i = i - 1;
  1246. X  } while (i >= 0);
  1247. X
  1248. X  if (p->contract != BID_PASS) {
  1249. X    bidder = b->dealer;
  1250. X    for (i = 0; i < p->no_bids; i++) {
  1251. X      if ((side_of(bidder) == contractor) && 
  1252. X      (trumpsuit_of(p->bids[i]) == trumpsuit_of(p->contract))) {
  1253. X    p->declarer = bidder;
  1254. X    break;
  1255. X      } else
  1256. X    bidder = player_next[bidder];
  1257. X    }
  1258. X  }
  1259. X}
  1260. X
  1261. X
  1262. X
  1263. Xvoid Compute_MIMP_points (b, p)
  1264. X     Board *b;
  1265. X     Play_record *p;
  1266. X/* Computes the number of MIMP points for the play record p, based upon
  1267. X   the scoring information found in the play record.  In addition,
  1268. X   we compute simulated match_point and imp values for the play record
  1269. X   which are based upon the number of MIMP's.
  1270. X*/
  1271. X{
  1272. X  int hcp, diff;
  1273. X  int contractor = side_of (p->declarer);
  1274. X  int level      = level_of (p->contract);
  1275. X  int trumpsuit  = trumpsuit_of (p->contract);
  1276. X
  1277. X  p->mimp_points[0] = p->mimp_points[1] = 0;
  1278. X  if (!p->hand_completed)
  1279. X    return;
  1280. X
  1281. X  hcp = Highcard_points (b, side_of(p->declarer));
  1282. X  if (p->result >= 0)
  1283. X    p->mimp_points[side_of(p->declarer)] = 
  1284. X      MIMP_score_made 
  1285. X    (b->vulnerable[contractor], level, trumpsuit, 
  1286. X     p->doubled, p->result, hcp);
  1287. X  else
  1288. X    p->mimp_points[side_of(p->declarer)] = 
  1289. X      MIMP_score_set 
  1290. X    (b->vulnerable[contractor], level, trumpsuit, 
  1291. X     p->doubled, p->result, hcp);
  1292. X
  1293. X  p->imatch_points[0] = ((float) p->mimp_points[0] * 0.5);
  1294. X  p->imatch_points[1] = ((float) p->mimp_points[1] * 0.5);
  1295. X  
  1296. X  p->match_points[0] = p->match_points[1] = 0.0;
  1297. X  diff = p->mimp_points[0] - p->mimp_points[1];
  1298. X  if (diff >= 1)
  1299. X    p->match_points[0] = 1.0;
  1300. X  else if (diff <= -1)
  1301. X    p->match_points[1] = 1.0;
  1302. X  else
  1303. X    p->match_points[0] = p->match_points[1] = 0.5;
  1304. X
  1305. X}
  1306. X
  1307. X
  1308. Xint Index_of_Last_Bid (b, p, player)
  1309. X     Board *b;
  1310. X     Play_record *p;
  1311. X     int player;
  1312. X/* Returns the index in the bid list p of the last bid made by the given
  1313. X   player, or -1 if the player has not made any bids.
  1314. X*/
  1315. X{
  1316. X  int index, bidder;
  1317. X
  1318. X  index = p->no_bids - 1;
  1319. X
  1320. X  switch (p->no_bids % 4) {
  1321. X  case 1: bidder = b->dealer; break;
  1322. X  case 2: bidder = player_next[b->dealer]; break;
  1323. X  case 3: bidder = player_partner[b->dealer]; break;
  1324. X  case 0: bidder = player_prev[b->dealer];
  1325. X  }
  1326. X
  1327. X  while ((index >= 0) && (bidder != player)) {
  1328. X    index -= 1;
  1329. X    bidder = player_prev[bidder];
  1330. X  }
  1331. X  
  1332. X  return (index);
  1333. X}
  1334. X
  1335. X
  1336. Xvoid Generate_valid_bids (p, player, minimum_bid, double_ok, redouble_ok)
  1337. X     Play_record *p;
  1338. X     int player;
  1339. X     int *minimum_bid;
  1340. X     int *double_ok;
  1341. X     int *redouble_ok;
  1342. X/* Determines the valid bids for the player, based on the information
  1343. X   contained in the play record p.  Assumes the declarer, contract
  1344. X   and doubled fields of p have been correctly computed from the bid
  1345. X   list.
  1346. X*/
  1347. X{
  1348. X  if (p->contract == BID_PASS)
  1349. X    *minimum_bid = 3;   /* The code for the 1C bid. */
  1350. X  else
  1351. X    *minimum_bid = p->contract + 1;
  1352. X
  1353. X  if (side_of(player) == side_of(p->declarer)) {
  1354. X    *double_ok = 0;
  1355. X    if (p->doubled == 1)
  1356. X      *redouble_ok = 1;
  1357. X    else
  1358. X      *redouble_ok = 0;
  1359. X  } else {
  1360. X    *redouble_ok = 0;
  1361. X    *double_ok = 0;
  1362. X    if (!p->doubled && (p->contract != BID_PASS))
  1363. X      *double_ok = 1;
  1364. X  }
  1365. X}
  1366. X
  1367. Xvoid Generate_holdings (b, plays, no_plays, player, h)
  1368. X     Board *b;
  1369. X     card_type *plays;
  1370. X     int no_plays;
  1371. X     int player;
  1372. X     card_type *h;
  1373. X/* Records in the hand h the cards held by the given player, based on the
  1374. X   deal contained in the board b and on the past no_plays recorded plays. 
  1375. X   The holdings of the player are recorded as a boolean string in h, so that
  1376. X     h[c] == true iff the player holds the card c.
  1377. X*/
  1378. X{
  1379. X  int i;
  1380. X
  1381. X  for (i = 0; i < 52; i++)
  1382. X    if (b->deal[i] == player)
  1383. X      h[i] = 1;
  1384. X    else
  1385. X      h[i] = 0;
  1386. X
  1387. X  for (i = 0; i < no_plays; i++)
  1388. X    h[plays[i]] = 0;
  1389. X}
  1390. X
  1391. Xvoid Generate_valid_leads (b, p, player, h)
  1392. X     Board *b;
  1393. X     Play_record *p;
  1394. X     int player;
  1395. X     card_type *h;
  1396. X/* Records in the hand h the set of cards which the player may lead,
  1397. X   based upon the plays which have already been recorded in p.
  1398. X   The valid plays are stored as a boolean string in h, so that
  1399. X     h[c] == true iff it is legal to play card c.
  1400. X*/
  1401. X{
  1402. X  Generate_holdings (b, p->play_list, p->no_plays, player, h);
  1403. X}
  1404. X
  1405. Xvoid Generate_valid_follows 
  1406. X  (b, p, player, lead, h)
  1407. X     Board *b;
  1408. X     Play_record *p;
  1409. X     int player;
  1410. X     int lead;
  1411. X     card_type *h;
  1412. X/* Records in the hand h the set of cards which the player may play to
  1413. X   follow the given lead, based upon the plays which have already been
  1414. X   recorded in p.
  1415. X
  1416. X   The valid plays are stored as a boolean string in h, so that
  1417. X     h[c] == true iff it is legal to play card c.
  1418. X*/
  1419. X{
  1420. X  int i;
  1421. X  int lead_suit  = suit_of (lead);
  1422. X  int has_lead_suit = 0;
  1423. X
  1424. X  Generate_holdings (b, p->play_list, p->no_plays, player, h);
  1425. X
  1426. X  for (i = 0; (i < 13) && !has_lead_suit; i++)
  1427. X    if (h[card_code(lead_suit, i)])
  1428. X      has_lead_suit = 1;
  1429. X
  1430. X  if (has_lead_suit)
  1431. X    for (i = 0; i < 52; i++)
  1432. X      if (suit_of(i) != lead_suit)
  1433. X    h[i] = 0;
  1434. X}
  1435. X
  1436. Xint Next_Player (p)
  1437. X     Play_record *p;
  1438. X/* Returns the index of the next person who should play, or -1 if the
  1439. X   hand has been completed. */
  1440. X{
  1441. X  if (p->hand_completed)
  1442. X    return (-1);
  1443. X  else if (p->next_player == player_partner[p->declarer])
  1444. X    return (p->declarer);
  1445. X  else
  1446. X    return (p->next_player);
  1447. X     
  1448. X}
  1449. X
  1450. Xstatic int outranks (c1, c2, t)
  1451. X    int c1, c2, t;
  1452. X/* Returns true if c1 outranks c2, according to the current trump suit t.
  1453. X * If c1 and c2 are of different suits, neither of which is the trump suit t,
  1454. X * then returns false.
  1455. X */
  1456. X{
  1457. X    if (suit_of (c1) == suit_of (c2))
  1458. X        return (rank_of(c1) > rank_of(c2));
  1459. X    else
  1460. X        return (suit_of (c1) == t);
  1461. X}
  1462. X
  1463. Xint Winning_card (trump_suit, leader, c_l, c_lho, c_p, c_rho)
  1464. X     int trump_suit;
  1465. X     int leader;
  1466. X     int c_l;
  1467. X     int c_lho;
  1468. X     int c_p;
  1469. X     int c_rho;
  1470. X/* Returns the index of the player who played the winning card from
  1471. X   the cards c_l, c_lho, c_p, c_rho, based on the given trump suit
  1472. X   and that c_l was the card lead.
  1473. X*/
  1474. X{
  1475. X  int w = leader;
  1476. X  int c = c_l;
  1477. X
  1478. X  if (outranks (c_lho, c, trump_suit)) {
  1479. X    c = c_lho;
  1480. X    w = player_next [leader];
  1481. X  }
  1482. X
  1483. X  if (outranks (c_p, c, trump_suit)) {
  1484. X    c = c_p;
  1485. X    w = player_partner [leader];
  1486. X  }
  1487. X
  1488. X  if (outranks (c_rho, c, trump_suit))
  1489. X    w = player_prev [leader];
  1490. X
  1491. X  return (w);
  1492. X}
  1493. X
  1494. END_OF_FILE
  1495. if test 36085 -ne `wc -c <'boards.c'`; then
  1496.     echo shar: \"'boards.c'\" unpacked with wrong size!
  1497. fi
  1498. # end of 'boards.c'
  1499. fi
  1500. if test -f 'network.h' -a "${1}" != "-c" ; then 
  1501.   echo shar: Will not clobber existing file \"'network.h'\"
  1502. else
  1503. echo shar: Extracting \"'network.h'\" \(15537 characters\)
  1504. sed "s/^X//" >'network.h' <<'END_OF_FILE'
  1505. X/* network.h
  1506. X *
  1507. X ! Copyright (C) 1990-1992 by Matthew Clegg.  All Rights Reserved
  1508. X ! 
  1509. X ! OKbridge is made available as a free service to the Internet.
  1510. X ! Accordingly, the following restrictions are placed on its use:
  1511. X ! 
  1512. X ! 1.  OKbridge may not be modified in any way without the explicit 
  1513. X !     permission of Matthew Clegg.  
  1514. X ! 
  1515. X ! 2.  OKbridge may not be used in any way for commercial advantage.
  1516. X !     It may not be placed on for-profit networks or on for-profit
  1517. X !     computer systems.  It may not be bundled as part of a package
  1518. X !     or service provided by a for-profit organization.
  1519. X ! 
  1520. X ! If you have questions about restrictions on the use of OKbridge,
  1521. X ! write to mclegg@cs.ucsd.edu.
  1522. X ! 
  1523. X ! DISCLAIMER:  The user of OKbridge accepts full responsibility for any
  1524. X ! damage which may be caused by OKbridge.
  1525. X *
  1526. X * The network module provides an interface between the network and
  1527. X * the bridge program which is mostly independent of whether or not
  1528. X * the local player is the server or a client.  In version 1.6, the
  1529. X * network module has much more intelligence -- i.e., this module
  1530. X * now parses all incoming messages and even processes some of them,
  1531. X * only passing up to the input module those messages which are relevant
  1532. X * to the play.
  1533. X *
  1534. X */  
  1535. X
  1536. X#ifndef TYPES_INCLUDED
  1537. X#include "types.h"
  1538. X#endif
  1539. X
  1540. X#ifndef PROTOCOL_INCLUDED
  1541. X#include "protocol.h"
  1542. X#endif
  1543. X
  1544. X#ifndef BOARDS_INCLUDED
  1545. X#include "boards.h"
  1546. X#endif
  1547. X#define NETWORK_INCLUDED
  1548. X
  1549. X/* The following definitions define the possible states of a connection. */
  1550. X#define CSTATE_CONNECTED  1  /* Connected but waiting for handshakes to
  1551. X                complete. */
  1552. X#define CSTATE_PLAYING    2  /* Playing or ready to play. */
  1553. X
  1554. X
  1555. X#define DEFAULT_PORT     1729 /* The default port to which we will try
  1556. X                 to connect. */
  1557. X
  1558. Xtypedef struct Message_struct {
  1559. X  struct Message_struct *next;
  1560. X  struct Connection_struct *source;
  1561. X    /* The connection from which the message was received. */
  1562. X  int    private;
  1563. X    /* TRUE if this message should not be forwarded to the other players. */
  1564. X  int    loopback;
  1565. X    /* TRUE if this message originated from the local player. */
  1566. X  struct player_command_struct p;
  1567. X} *Message;
  1568. X
  1569. Xtypedef struct Message_queue_struct {
  1570. X  Message head, tail;
  1571. X} *message_queue;
  1572. X
  1573. X/* If we are in server mode, then we maintain a Connection structure for
  1574. X   each client connection.  All of the Connection structures are maintained
  1575. X   on a global input list which is continuously monitored for incoming
  1576. X   messages.  In addition, each Connection structure will be on an
  1577. X   output list which is determined by the table and seat occupied by
  1578. X   the player.  All of the connection lists contain dummy header elements,
  1579. X   so that a connection may be deleted from a list without reference to
  1580. X   the head of the list.
  1581. X*/
  1582. X
  1583. X/* typedef struct Table_struct; */
  1584. X
  1585. Xtypedef struct Connection_struct {
  1586. X  int  channel;            /* The socket descriptor for communication */
  1587. X  int  local;              /* True if this connection represents the local
  1588. X                  player.  In this case, channel is meaningless */
  1589. X  int  state;              /* The state of the connection, as above. */
  1590. X  name_buffer player_name; /* The name of the player. */
  1591. X  message_buffer fullname; /* The full name of the player. */
  1592. X  message_buffer email;    /* The email address of the player. */
  1593. X  message_buffer registry; /* A unique registration name for the player. */
  1594. X  int  seat;               /* The seat assigned to the player. */
  1595. X  int  spectator;          /* True if this player is in spectator mode. */
  1596. X  struct Table_struct *table;  /* The table where this player is located */
  1597. X  struct Connection_struct *iprev, *inext;
  1598. X  struct Connection_struct *oprev, *onext;
  1599. X} *Connection;
  1600. X
  1601. Xtypedef struct Seat_struct {
  1602. X  char  player_name[10];
  1603. X  int   occupied;          /* A boolean flag indicating this seat is occupied*/
  1604. X  int   skipping;          /* A boolean flag indicating that this player has
  1605. X                  not yet acknowledge a skip request. */
  1606. X  Connection connection;   /* NULL if there is no one sitting here. */
  1607. X} *Seat;
  1608. X
  1609. Xtypedef struct Table_struct {
  1610. X  int table_no;                            /* A unique number identifying
  1611. X                          this table. */
  1612. X  struct Seat_struct Seats[PLAYER_TYPES];  /* The sitting players. */
  1613. X  Connection    Players;                   /* The list of players,
  1614. X                          including observers. */
  1615. X  message_queue protocol_queue;            /* Pending messages on the
  1616. X                          protocol queue. */
  1617. X  message_queue conversation_queue;        /* Pending messages on the 
  1618. X                          conversation queue. */
  1619. X  message_queue game_queue;                /* Pending messages on the
  1620. X                          game queue. */
  1621. X  int    game_mode;                        /* The current state of the game:
  1622. X                          STARTUP, BIDDING, PLAYING
  1623. X                          or SCORING. */
  1624. X  int  playing_mode;                      /* The current mode of play:
  1625. X                         CLUB, PRACTICE or FORMAL. */
  1626. X  int  above_line[2];                     /* Total above-the-line score 
  1627. X                         for this table. */
  1628. X  int  below_line[2];                     /* Total below-the-line score 
  1629. X                         for this table. */
  1630. X  Board  *board;                           /* The current board which is
  1631. X                          being played. */
  1632. X  Play_record *play_record;                /* The record of play for the
  1633. X                          current board. */
  1634. X  struct Table_struct *next, *prev;
  1635. X} *Table;
  1636. X
  1637. X#define OCCUPIED(t,s)    (((s) < 4) && t->Seats[s].occupied)
  1638. X#define VACANT(t,s)      !OCCUPIED(t,s)
  1639. X#define PLAYER_NAME(t,s) Local_table->Seats[s].player_name
  1640. X#define MODERATOR(t)     t->Players
  1641. X
  1642. X#define CLUB(t)          ((t)->playing_mode == CLUB_PLAYING_MODE)
  1643. X#define FORMAL(t)        ((t)->playing_mode == FORMAL_PLAYING_MODE)
  1644. X#define PRACTICE(t)      ((t)->playing_mode == PRACTICE_PLAYING_MODE)
  1645. X
  1646. X#ifdef _NETWORK_
  1647. X
  1648. X  Table Table_List = NULL;
  1649. X    /* If we are the server, then a list of the currently playing tables.
  1650. X       If we are a client, then a descriptor of the particular table
  1651. X       where we are sitting. */
  1652. X
  1653. X  Connection Connections = NULL;
  1654. X    /* Connections which have been established. */
  1655. X
  1656. X  Connection Local_Player_Connection = NULL;
  1657. X    /* A dummy connection representing the local player. */
  1658. X
  1659. X  int    server_mode = 0;
  1660. X    /* A boolean flag which is true if we are acting as the server. */
  1661. X  int    client_mode = 0;
  1662. X    /* A boolean flag which is true if we are a client. */
  1663. X
  1664. X  char  *server_name = NULL;
  1665. X    /* The server to which we will try to connect by default. */
  1666. X  int    network_port = DEFAULT_PORT;
  1667. X    /* The port number to be used for network communications. */
  1668. X
  1669. X  char Server_Start_time [40];
  1670. X    /* The time at which we entered server mode. */
  1671. X
  1672. X  /* The following information is maintained in order so that we
  1673. X     can quickly identify ourselves to the GPS server. */
  1674. X
  1675. X  char Host_IP [60];
  1676. X    /* The IP number of the local host, in ascii format. */
  1677. X  int  Host_IP_is_known = 0;
  1678. X    /* A boolean flag indicating that the host IP number (or name) is known. */
  1679. X  char Host_name [100];
  1680. X    /* The name of the local host. */
  1681. X  char User_name [20];
  1682. X    /* The login name of the local user. */
  1683. X  char User_fullname [60];
  1684. X    /* The full name of the local user, as taken from the password file. */
  1685. X  char *Registration = NULL;
  1686. X    /* A unique name assigned to the local user which identifies him to
  1687. X       the GPS. */
  1688. X  char *Timezone_name = NULL;
  1689. X    /* A string naming the time zone of the local player. */
  1690. X
  1691. X#else
  1692. X
  1693. X  extern Table Table_List;
  1694. X  extern Connection Connections;
  1695. X  extern Connection Local_Player_Connection;
  1696. X  extern int server_mode, client_mode, network_port;
  1697. X  extern char *server_name;
  1698. X  extern char Host_IP[], Host_name[], User_name[], User_fullname[],
  1699. X              Server_Start_time[];
  1700. X  extern int Host_IP_is_known;
  1701. X  extern char *Registration;
  1702. X  extern char *Timezone_name;
  1703. X
  1704. X#endif
  1705. X
  1706. X/* Procedures for manipulating command queues: */
  1707. X
  1708. Xextern int message_available ();
  1709. X/* extern int message_available (message_queue queue); */
  1710. X/* Returns true if the given queue is nonempty. */
  1711. X
  1712. Xextern Message dequeue_message ();
  1713. X/* extern Message dequeue_message (message_queue queue); */
  1714. X/* Deletes the first message from the given queue and returns a pointer
  1715. X   to that message. 
  1716. X*/
  1717. X
  1718. Xextern void enqueue_message ();
  1719. X/* extern void enqueue_message (message_queue queue, Message m); */
  1720. X/* Appends m to the list of messages stored in the given message queue. */
  1721. X
  1722. Xextern Message allocate_message ();
  1723. X/* extern Message allocate_message (void); */
  1724. X/* Allocates a message structure and returns a pointer to the structure.
  1725. X   Copies the message text mtest into the message structure. */
  1726. X
  1727. Xextern void deallocate_message ();
  1728. X/* extern void deallocate_message (Message m); */
  1729. X/* Returns the message structure m to the pool of free message structs. */
  1730. X
  1731. Xextern void clear_message_queue ();
  1732. X/* extern void clear_message_queue (message_queue queue); */
  1733. X/* Deletes all messages from the named queue. */
  1734. X
  1735. Xextern void clear_all_message_queues ();
  1736. X/* extern void clear_all_message_queues (Table t); */
  1737. X/* Clears all of the message queues for the table t. */
  1738. X
  1739. X
  1740. X
  1741. X/*  SEND ROUTINES
  1742. X *
  1743. X *  The following routines provide various options for sending messages
  1744. X *  to the other players.  
  1745. X *
  1746. X *  The client and also any routine at the conversation level or above 
  1747. X *  will use exclusively the send_message procedure.  However, server
  1748. X *  routines in the cs module may need to use some of these other
  1749. X *  send routines. 
  1750. X */
  1751. X
  1752. Xextern Message send_message ();
  1753. X/* void send_message (Table t, int msg_type, char *message); */
  1754. X/* If in server mode, sends a message to each of the clients at table t.
  1755. X   If in client mode, sends a message to the server.  Returns a pointer
  1756. X   to the message which is put onto the protocol queue.
  1757. X  
  1758. X   NOTE 1: This is the main send routine, and should be used by all
  1759. X   routines operating at the conversation level or higher.
  1760. X   NOTE 2: As a side effect, the message sent by this routine is
  1761. X   also queued onto the protocol queue of the table t.
  1762. X*/
  1763. X
  1764. X/* SEND Primitives.
  1765. X
  1766. X   NOTE:  The following routines should only be used if we are in
  1767. X   server mode.
  1768. X*/
  1769. X
  1770. Xextern int server_send_unformatted ();
  1771. X/* int server_send_unformatted (Connection c, char *message); */
  1772. X/* Transmits the message to the given player.  Returns 0 if successful or 1
  1773. X   if an error.  If an error occurs, then the connection is closed.
  1774. X
  1775. X   NOTE:  If the connection c is a local connection, then the message
  1776. X   is dropped.  To cause the message to be received at the local table,
  1777. X   the routine send_private_message must be used.   
  1778. X*/
  1779. X
  1780. Xextern int server_send ();
  1781. X/* int server_send (Connection c, int source, char *player_name, 
  1782. X     char *message); */
  1783. X/* Formats a message and sends it across the given connection.
  1784. X   Returns 0 if successful or 1 if an error.  If an error occurs,
  1785. X   then the connection is closed.  If the connection c is that
  1786. X   of the local player, then the message is dropped.  If this is
  1787. X   not desired, then send_private_message should be used.
  1788. X*/
  1789. X
  1790. Xextern void Relay_message ();
  1791. X/* void Relay_message (Table t, Connection c, int msg_type, char *message); */
  1792. X/* Relays the message from c to all of the other players at table t who
  1793. X   are allowed to receive the message.  Does NOT put the message onto
  1794. X   the local protocol queue.
  1795. X*/
  1796. X
  1797. Xextern Message loopback_message_unformatted ();
  1798. X/* void loopback_message_unformatted (Table t, Connection c, char *message); */
  1799. X/* Constructs a message structure using the the given message.
  1800. X   Assumes that the message is in the format which is used by the
  1801. X   client in transmitting messages.  Appends the message structure
  1802. X   to the protocol queue for the table t.  Returns a pointer to the
  1803. X   message which is enqueued.
  1804. X*/
  1805. X
  1806. Xextern Message loopback_message ();
  1807. X/* void loopback_message (Table t, Connection c, char *message); */
  1808. X/* Appends the message to the protocol queue of the table t. 
  1809. X   Returns a pointer to the message which is enqueued.
  1810. X*/ 
  1811. X
  1812. Xextern void server_broadcast_unformatted ();
  1813. X/* void server_broadcast_unformatted (Table t, int msg_type, char *message); */
  1814. X/* Broadcasts the message to all of the people sitting at table t who are
  1815. X   entitled to receive the message.  This includes putting the message
  1816. X   onto the local protocol queue if we are sitting at the table t.
  1817. X*/
  1818. X
  1819. Xextern void server_broadcast ();
  1820. X/* void server_broadcast (Table t, int source, msg_type, char *player_name, 
  1821. X     char *message); */
  1822. X/* Formats and broadcasts the message to all of the people sitting at table t
  1823. X   who are entitled to receive the message.  Puts the message onto the
  1824. X   local protocol queue if we are sitting at the table t.
  1825. X*/
  1826. X
  1827. Xextern void send_server_message ();
  1828. X/* void send_server_message (Table t, int msg_type, char *message); */
  1829. X/* Sends a message which originates from the 'SERVER'. */
  1830. X
  1831. Xextern void send_private_message ();
  1832. X/* void send_private_message (Connection c, char *message); */
  1833. X/* Only to be used in server mode.  Sends a message from the 'server'
  1834. X   to the connection c.  If the connection c is the local player,
  1835. X   then appends the message to the protocol queue of the table of
  1836. X   the local player.
  1837. X*/
  1838. X
  1839. X
  1840. X/* The following routines are for transmitting and receiving boards and
  1841. X   play records.  These routines are special in that boards and
  1842. X   play records are transmitted and received as in-line data, and so
  1843. X   are not handled by the normal parsing mechanisms.
  1844. X*/
  1845. X
  1846. Xextern void Transmit_board ();
  1847. X/* void Transmit_board (Table t, Board *b); */
  1848. X/* If we are the server, then transmits the board b to each of the players
  1849. X   at the table t.  If we are a client, then transmits the board b to
  1850. X   the server. */
  1851. X
  1852. Xextern void Transmit_play_record ();
  1853. X/* void Transmit_play_record (Table t, Play_record *p); */
  1854. X/* If we are the server, then transmits the play record p to each of the
  1855. X   players at the table t.  If we are a client, then transmits the play
  1856. X   record p to the server. */
  1857. X
  1858. Xextern void Relay_board ();
  1859. X/* void Relay_board (Table t, Connection c, Board *b); */
  1860. X/* Relays the in-line board data from the connection c to the other players
  1861. X   at the table t.
  1862. X*/
  1863. X
  1864. Xextern void Relay_play_record ();
  1865. X/* void Relay_play_record (Table t, Connection c, Play_record *p); */
  1866. X/* Relays the in-line play record from the connection c to the other players
  1867. X   at the table t.
  1868. X*/
  1869. X
  1870. X
  1871. X/* Top level routines for accessing the network: */ 
  1872. X
  1873. Xextern void Initialize_Network ();
  1874. X/* Initializes the network data structures. */
  1875. X
  1876. Xextern void Attempt_to_connect ();
  1877. X/* Attempts to connect to the server named above as server_name at
  1878. X   the port specified above as network_port.  
  1879. X*/
  1880. X
  1881. Xextern void Setup_server ();
  1882. X/* Sets up the local player as a server.  Attempts to use the specified
  1883. X   port, but if this does not work, then a new port will be chosen.
  1884. X*/
  1885. X
  1886. Xextern void Wait_for_network_event ();
  1887. X/* Waits for an input event to occur.  If a network event occurs, then
  1888. X   parses the message and places it onto the proper player queue.
  1889. X*/
  1890. X
  1891. Xextern void close_connection ();
  1892. X/* void close_connection (Connection c) */
  1893. X/* Closes the connection to c. */
  1894. X
  1895. Xextern void Close_all_connections ();
  1896. X/* Closes all current network connections. */
  1897. X
  1898. Xextern void Switch_Table ();
  1899. X/* void Switch_Table (Connection c, Table new_table); */
  1900. X/* Unlinks the connection c from the current table and links it into
  1901. X   the new table.
  1902. X*/
  1903. X
  1904. X/* The following two macros are for iterating through the set of all
  1905. X   connections and through the set of all players at a given table,
  1906. X   respectively.
  1907. X*/
  1908. X
  1909. X#define FOREACH_CONNECTION(x) for(x = Connections->inext; x != NULL; x = x->inext)
  1910. X#define FOREACH_PLAYER(x,t)   for(x = t->Players->onext; x != NULL; x = x->onext)
  1911. END_OF_FILE
  1912. if test 15537 -ne `wc -c <'network.h'`; then
  1913.     echo shar: \"'network.h'\" unpacked with wrong size!
  1914. fi
  1915. # end of 'network.h'
  1916. fi
  1917. echo shar: End of archive 5 \(of 14\).
  1918. cp /dev/null ark5isdone
  1919. MISSING=""
  1920. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  1921.     if test ! -f ark${I}isdone ; then
  1922.     MISSING="${MISSING} ${I}"
  1923.     fi
  1924. done
  1925. if test "${MISSING}" = "" ; then
  1926.     echo You have unpacked all 14 archives.
  1927.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1928. else
  1929.     echo You still need to unpack the following archives:
  1930.     echo "        " ${MISSING}
  1931. fi
  1932. ##  End of shell archive.
  1933. exit 0
  1934.