From: johnf@apollo.hp.com (John Francis)
Subject: Here is tennis.c  (Version 2.01)
Date: Mon, 31 Aug 1992 17:33:37 GMT
Organization: Hewlett-Packard Corporation, Chelmsford, MA

I've had several requests for this, so here it is again (a slightly
newer version than was previously posted).  Maybe I should just post
the latest version to this group before each grand slam tournament :-)

/*

        tennis.c V2.01  -- process results for 128-player tournaments.

        Copyright 1991, 1992 by John Francis (johnf@apollo.hp.com)

        Permission is hereby granted to use this program (or parts thereof)
        for private, non-commercial use, provided that due credit for ideas
        used in derivative works is acknowledged within any such works.

        usage:  tennis <input-file-list>

        input:  one or more input files in the format detailed below.

        output: updated versions of the input files (overwriting the originals),
                plus tennis.ps  --  a postscript file with the entire tournament
                matches laid out for printing on a single 8.5 x 11 sheet of paper.


Operation
---------

        The program operates on each input file in turn.  If no data format
        errors are detected while reading an input file the program rewrites
        an updated version of that input file, adding lines for any pairings
        which are now known from the results of earlier matches.(No error is
        reported if the updated input file can not be created).
        The program also creates a postscript output file containing two pages
        for each input file - one page for the men, and one for the women.
        The layout is designed for a standard US page (8.5 x 11 inches), though
        it should be fairly simple to adjust it to fit on European A4 paper.
        A high-resolution output device (300dpi or better) is essential, as the
        names of the players, and the scores, are printed in 5-point text.


Format of the input file
------------------------

        The input file should start out with a line giving the tournament name,
        preceded by an equal sign (=) in the first character position. The name
        should be at most 60 characters long.

        Subsequent lines should be formatted as follows:

        cols
         1      A single-character flag, either 'M' (mens) or 'W' (womens)
         2      The round - a single ASCII digit in the range one to seven
         3      The dash character (-)
        4-5     A two-digit match identifier number (with leading zeros)
         6      The colon character (:)
        7-31    The name of the 1st player
         32     ignored (should be blank)
       33-57    The name of the 2nd player
         58     ignored (should be blank)
         59     A question mark (?), space ( ), or asterisk (*)
                  (?)   The result of the match is unknown
                  ( )   The match is won by the 1st player
                  (*)   The match is won by the 2nd player
       60-80    Explanatory text (match score, retirement, . . .)


        Blank lines and lines starting with a semicolon (;) will be ignored.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PS  1

typedef struct
  {
  char player[2][26];
  char result[23];
  char status;
  } match_record;

static void check_player( int draw, int round, int match, int player, char *name );
static void check_player( int draw, int round, int match, int player, char *name )
  {
  static char *table = 0;
  static int   start_lo[2], start_hi[2];
  char         buffer[32], *cp;

  if ( !table && (table = (char *) malloc(500*26)) )
    {
    FILE *io = fopen( "players.dat", "r" );

    start_lo[0] = 0;
    start_hi[0] = 0;
    start_lo[1] = 0;
    start_hi[1] = 0;
    while ( io && fgets( buffer, 32, io ) )
     if ( (buffer[0] == 'M') || (buffer[0] == 'W') )
      {
      buffer[27] = 0;
      if ( buffer[0] == 'W' )
        {
        if ( !start_lo[1] ) start_lo[1] = start_hi[1] = start_hi[0];
        strcpy( &table[26*start_hi[1]], &buffer[2] );
        if ( ++start_hi[1] >= 500 ) break;
        }
      else
        {
        strcpy( &table[26*start_hi[0]], &buffer[2] );
        if ( ++start_hi[0] >= 500 ) break;
        }
      }
    if ( io ) fclose( io );
    }

  if ( table )
    {
    int    lo = start_lo[draw], hi = start_hi[draw], lh, cc = -1;

    strcpy( buffer, name );
    if ( cp = strchr( buffer, '(' ) )
     while ( *cp ) *cp++ = ' ';

    while ( (lo < hi) && (cc = strcmp( &table[26*(lh = (lo + hi) >> 1)], buffer )) )
     if ( cc < 0 ) lo = ++lh; else hi = lh;
    if ( cc ) fprintf( stderr,"  Unknown Player (%c%1d-%02d.%1d): <%s>\n",
                                 draw ? 'W' : 'M', round+1, match+1, player+1, buffer );
    }
  }

int main( int argc, char **argv )
  {
  match_record *table, *entry, *match[2][7];
  int           argn, length, errors, draw, round, index, record, count;
  FILE         *io, *ps;
  char          buffer[256], title[64], *winner;

  table = (match_record *) malloc(2*127*sizeof(match_record));
  for ( entry = table, draw = 0 ; draw < 2; draw++ )
   for ( round = 0 ; round < 7 ; round++ )
    {
    match[draw][round] = entry;
    entry += (64 >> round);
    }
#if PS
  ps = fopen( "tennis.ps", "w" );
  fprintf( ps, "%%!PS\n" );
#endif
  for ( argn = 0 ; ++argn < argc ; )
   if ( io = fopen( argv[argn], "r" ) )
    {
    for ( draw = 0 ; draw < 2 ; draw++ ) for ( round = 0 ; round < 7 ; round++ )
     for ( index = 0 ; (index << round) < 64 ; index++ )
      {
      entry = &match[draw][round][index];
      strcpy( entry->player[0], "                         " );
      strcpy( entry->player[1], "                         " );
      strcpy( entry->result   ,    "?                     " );
      entry->status = '?';
      }

    for ( errors = 0, record = 1 ; fgets( buffer, 256, io ) ; record++ )
      {
      length = strlen( buffer );
      if ( length && (buffer[length-1] == '\n') ) buffer[--length] = 0;
      if ( length && (buffer[length-1] == '\r') ) buffer[--length] = 0;
      switch( buffer[0] )
        {
      case  0 :
      case ';':                                     continue;
      case '=': strcpy( title, &buffer[1] );        continue;
      case 'M': draw = 0;                           break;
      case 'W': draw = 1;                           break;
      default:
        fprintf( stderr, "?Format of input data (file <%s>, record%4d) '%c'\n",
                         argv[argn], record, buffer[0] );
        errors++;
        continue;
        }
      if ( (sscanf( &buffer[1], "%1d-%2d:", &round, &index ) != 2 )
       || (round < 1) || (round > 7) || (index < 1) || (index > (128 >> round)) )
        {
        buffer[6] = 0;
        fprintf( stderr, "?Values of input data (file <%s>, record%4d)  %s\n",
                         argv[argn], record, buffer );
        errors++;
        continue;
	}
      entry = &match[draw][--round][--index];

      while ( length < 80 ) buffer[length++] = ' ';
      if ( round == 0 )
	{
	buffer[31] = 0;  strcpy( entry->player[0], &buffer[ 6] );
	buffer[57] = 0;  strcpy( entry->player[1], &buffer[32] );
	entry->status = '*';
#if 1
        check_player( draw, round, index, 0, entry->player[0] );
        check_player( draw, round, index, 1, entry->player[1] );
#endif
	}
      if ( buffer[58] != '?' )
	{
	buffer[80] = 0;   strcpy( entry->result   , &buffer[58] );
	entry->status = ' ';
	if ( round < 6 )
	  {
	  winner = entry->player[entry->result[0] != ' '];
	  entry = &match[draw][round+1][index >> 1];
	  strcpy( entry->player[index & 1], winner );
	  if ( entry->player[!(index & 1)][0] != ' ' ) entry->status = '*';
	  }
	}
      }
    fclose( io );
    if ( errors ) continue;

    if ( io = fopen( argv[argn], "w" ) )
      {
      fprintf( io, ";\n; Data for tennis program written by John Francis (johnf@apollo.hp.com)\n;\n" );
      fprintf( io, "=%s\n", title );
      count = -1;
      for ( draw = 0 ; draw < 2 ; draw++ )
       for ( round = 0 ; round < 7 ; round++ )
        {
        if ( count ) fprintf( io, "\n" );
        for ( count = 0, index = 0 ; (index << round) < 64 ; index++ )
          {
          entry = &match[draw][round][index];
          if ( entry->status == '?' ) continue;
          fprintf( io, "%c%1d-%02d:%s %s %s\n",
            draw ? 'W' : 'M', round+1, index+1, entry->player[0], entry->player[1], entry->result );
          count++;
          }
        }
      fclose( io );
      }
#if PS
    for ( draw = 0 ; draw < 2 ; draw++ )
      {
      int xbase = 100, ybase = 3120, stride;

      fprintf( ps, "initgraphics\n0.24 0.24 scale\n");
      fprintf( ps, "/Helvetica-Bold findfont 50 scalefont setfont\n");
      fprintf( ps, "%d 3150 moveto (%s %s Singles) show\n", 900 - 40*draw, title, draw ? "Womens" : "Mens" );
      fprintf( ps, "/Helvetica-Bold findfont 20 scalefont setfont\n");
      for ( index = 0 ; index < 64 ; index++ )
        {
        entry = &match[draw][0][index];
        fprintf( ps, "%4d %4d moveto (%s) show\n",xbase, ybase - 48*index     , entry->player[0] );
        fprintf( ps, "%4d %4d moveto (%s) show\n",xbase, ybase - 48*index - 20, entry->player[1] );
        }
      for ( stride = 24, round = 0 ; round < 7 ; round++, stride <<= 1 )
        {
        xbase +=  300;
        ybase  = 3120 - (stride - 24);
        for ( index = 0 ; index < (64 >> round) ; index++, ybase -= 2*stride )
          {
          fprintf( ps, "gsave newpath\n" );
          fprintf( ps, "%4d %4d moveto %4d %4d lineto\n", xbase - 30, ybase, xbase - 10, ybase );
          fprintf( ps, "%4d %4d moveto " , xbase - 50, ybase + (stride >> 1) );
          fprintf( ps, "%4d %4d lineto\n", xbase - 30, ybase + (stride >> 1) );
          fprintf( ps, "%4d %4d lineto " , xbase - 30, ybase - (stride >> 1) );
          fprintf( ps, "%4d %4d lineto\n", xbase - 50, ybase - (stride >> 1) );
          fprintf( ps, "stroke grestore\n" );
          entry = &match[draw][round][index];
          if ( entry->status == ' ' )
            {
            fprintf( ps, "%4d %4d moveto (%s) show\n", xbase, ybase, entry->player[entry->result[0] != ' '] );
            fprintf( ps, "%4d %4d moveto (%s) show\n", xbase + 20, ybase - 20, &entry->result[1] );
            }
          }
        }
      fprintf( ps, "showpage\n" );
      }
#endif
    }
#if PS
  fclose( ps );
#endif
  free(table);
  return 1;
  }
-- 
John Francis                                johnf@apollo.hp.com
The world can be divided into two classes :-
 those who divide people into two classes, and those who don't.
Newsgroups: rec.sport.tennis