/* MP_CALC.C   basic calulations for MTCHPLAY */

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include "defines.h"

/* macro for calculating adjustment on hole h (x = hcp[a]-hcp[b]-order[h]) */
#define correction(x)  (x)<0 ? 0 : (x)<18 ? 1 : (x)<36 ? 2 : 3

extern int NP[], order[], ndx[], outcome[MAXSZ][MAXSZ];
extern short indx[MAXFL][MAXSZ];
extern PLAYER player[MAXFL][MAXSZ];

/* function prototypes */
void
  calc_all(void),
  calc_outcome(int),
  calc_results(int),
  set_gnp(int);         /* set .gross, .net, .points for flight */
int
  callaway(char *);

/* ---------------------------------------------------------------------- */
void
calc_all(void)
{
   int i;

   for (i=0; i<MAXFL; i++) {
     if (!NP[i]) continue;
     calc_results(i);
   }
}

/* ---------------------------------------------------------------------- */
void
set_gnp(int flight)    /* set gross, net, points for all players in flight */
{
  int i,h,g,points,val;
  extern int par[18];

  for (i=0; i<NP[flight]; i++) {
    /* skip players with gross already entered */
    if (player[flight][i].gross != 0)
      continue;
    /* set gross, net, points to 0 if no scores */
    if (player[flight][i].scores[0] == 0) {
      player[flight][i].gross = 0;
      player[flight][i].net = 0;
      player[flight][i].points = 0;
      continue;
    }
    g = points = 0;
    for (h=0; h<18; h++) {
      g += player[flight][i].scores[ndx[h]]-48;
      val = 2 + par[h] - (player[flight][i].scores[ndx[h]]-48);
      if (val < -1) val = -1;
      if (val > 4) val = 4;
      points += val;
    }
    points += player[flight][i].hcp;
    if (points > 40) points = 40;
    player[flight][i].gross = g;
    player[flight][i].net = g - player[flight][i].hcp;
    player[flight][i].points = points;
  }
}

/* ---------------------------------------------------------------------- */
void
calc_outcome(int flight)     /* like calc_results() but fills outcome[][] */
{
  int i,j,a,b,k,h,w,x,y;
  int diff;
  int sa[18],sb[18];         /* gross scores for player[a], player[b] */
  int i0;

  for (i=NP[flight]-1; i>0; i--) {
    if (player[flight][i].scores[0] == 0)  /* ignore players w/o scores */
       continue;
    for (j=i-1; j>=0; j--) {
      if (player[flight][j].scores[0] == 0)
        continue;
      if (player[flight][i].hcp > player[flight][j].hcp)
        a=i, b=j;
      else
        a=j, b=i;
      /* extract scores from formatted storage strings */
      for (h=0; h<18; h++) sa[h] = player[flight][a].scores[ndx[h]]-48;
      for (h=0; h<18; h++) sb[h] = player[flight][b].scores[ndx[h]]-48;
      k = player[flight][a].hcp - player[flight][b].hcp;
                                   /* k is non-negative, by choice of a,b */
      i0 = 17;               /* i0 = number of last hole that counts here */
      w = 0;                      /* w counts net wins (+ for a, - for b) */
      for (h=0; h<18; h++) {
        diff = correction(k-order[h]);  /* diff = 0,1,2,3 = advantage to a */
        x = sa[h] - diff;               /* x = a's net score relative to b */
        y = sb[h];                    /* since b has higher hcp, no change */
        w += (y-x>0 ? 1 : y==x ? 0 : -1);
        if (h<17 && abs(w)>17-h) {
          i0 = h;
          break;
        }
      }
      if (w==19-i0) w += 10;  /* to distinguish 'w and w-1' from 'w and w-2'; */
      if (-w==19-i0) w -= 10; /* e.g., |w|=3 -> 3&1 while |w|=13 -> 3&2 */
      outcome[a][b] = w;
      outcome[b][a] = -w;
    }
  }
}


/* ---------------------------------------------------------------------- */
void
calc_results(int flight)
{
  int i,j,a,b,k,h,w,x,y;
  int diff,old_np;
  int sa[18],sb[18];  /* gross scores, player[flight][a], player[flight][b] */
  int w1;
  for (i=0; i<NP[flight]; i++)
    player[flight][i].won=player[flight][i].tied=player[flight][i].lost=0;
  for (i=NP[flight]-1; i>0; i--) {
    if (player[flight][i].scores[0] == 0)  /* ignore players w/o scores */
       continue;
    for (j=i-1; j>=0; j--) {
      if (player[flight][j].scores[0] == 0)
        continue;
      if (player[flight][i].hcp > player[flight][j].hcp)
        a=i, b=j;
      else
        a=j, b=i;
      /* extract scores from formatted storage strings */
      for (h=0; h<18; h++) sa[h] = player[flight][a].scores[ndx[h]]-48;
      for (h=0; h<18; h++) sb[h] = player[flight][b].scores[ndx[h]]-48;

      k = player[flight][a].hcp - player[flight][b].hcp;
                                   /* k is non-negative, by choice of a,b */
      w = 0;                       /* w counts net wins (+ for a, - for b) */
      for (h=0; h<18; h++) {
        diff = correction(k-order[h]);  /* diff = 0,1,2,3 = advantage to a */
        x = sa[h] - diff;               /* x = a's net score relative to b */
        y = sb[h];                    /* since b has higher hcp, no change */
        w += (y-x>0 ? 1 : y==x ? 0 : -1);
        if (h<17 && abs(w)>17-h) break;
      }
      if (w == 0) {                               /* a and b tied */
        player[flight][a].tied++; player[flight][b].tied++;
      }
      else if (w > 0) {                            /* a defeated b */
        player[flight][a].won++;
        player[flight][b].lost++;
      }
      else if (w < 0) {                            /* b defeated a */
        player[flight][b].won++;
        player[flight][a].lost++;
      }
    }
  }
  asort(flight);
}

callaway(char *scores)
{
  int i,j,temp,num,h=0,g=0;
  int w[11];
  int score[18];

  /* extract scores from formatted string 'scores' into array score[] */
  /* ndx[i] = location of score on hole i in string 'scores' */
  for (i=0; i<18; i++) score[i] = scores[ndx[i]]-48;
  /* set g = gross score, 18 holes */
  for (i=0; i<18; i++) g += score[i];

  if (g < 73)
    return 0;
  if (g > 130)
    return 40;

  /* sort first 16 scores in descending order */
  for (i=0; i<15; i++)
    for (j=i+1; j<16; j++)
      if (score[i] < score[j]) {
        temp = score[i];
        score[i] = score[j];
        score[j] = temp;
      }

  /* establish array w[] =  */
  /* worst,worst,next_worst,next_worst, ... sixth_worst,sixth_worst */
  for (i=0; i<6; i++) w[2*i] = w[2*i+1] = score[i];

  /* determine number of worst holes to use */
  num = (g-1)/5 - 14;

  /* calculate handicap */
  for (i=0; i<= num; i++)
    h += w[i];               /* h = 2*hcp, before adjustment */
  h = (h+1)/2;               /* (half strokes count as strokes */
  /* add adjustment */
  if (g % 5 == 0)
    h += 2;
  else
    h += (g % 5 - 3);
  return h;
}

