//*   P L A Y I N G   F U N C T I O N S

int8_t valid_pos (int8_t POS) {
int8_t I;
  // on the board?
  I = POS >> 1;
  if (POS < 0 || POS > 77 || I == 4 || I == 14 || I == 24 || I == 34) {
    return -1;
  }
  // square vacant?
  for (I = 1; I <= 12; I++) {
    if ((I <= COMP_NUM && POS == COMP_POS (I)) || (I <= OPP_NUM && POS == OPP_POS (I))) {
      return 1;
    }
  }
  return 0;
}

int8_t valid_move (int8_t M, int8_t P, Player *COMPp, Player *OPPp) {
int8_t CPOS, I, T;

  assert(1 <= P && P <= 12);
  if (CKTYPE(COMP__TYPE (P)) != CROWN) {
    if (COMP__PLAYERNO == 1) {   // player 1
      if ((M & 4) == 0) {
        return -1;              // backward move
      }
    } else {                    // else player 2
      if ((M & 4) != 0) {
        return -1;              // backward move
      }
    }
  }
  CPOS = COMP__POS (P);
  if (valid_pos (CPOS + MOVE (M))) {
    return -1;
  }
  if ((M & 1) == 0) {
    return 0;                   // ordinary move
  }
  if (OPP_NUM == 0) {
    return -1;
  }
  I = CPOS + MOVE (M - 1);      // else take-move
  for (T = 1; T <= OPP__NUM; T++) {
    if (I == OPP__POS (T)) {
      return T;                 // piece to take?
    }
  }
  return -1;
}


// THIS MAY BE THE BUG!  COMP_NUM etc define in terms of COMP, *not* COMPp

int8_t pending_move (Player *COMPp, Player *OPPp) {
int8_t P, M, PMCOMPNUM;         // might be able to reuse COMP_NUM ?

  PMCOMPNUM = COMP__NUM;
  if (!PMCOMPNUM) {
    return -1;                  // no pieces left!!
  }
  assert(1 <= PMCOMPNUM && PMCOMPNUM <= 12);
  for (P = 1; P <= PMCOMPNUM; P++) {
    for (M = 1; M <= 7; M += 2) {
      if (valid_move (M, P, COMPp, OPPp) > 0) {
        return P;               // return piece doing take
      }
    }
  }
  // ordinary moves
  for (P = 1; P <= PMCOMPNUM; P++) {
    for (M = 0; M <= 6; M += 2) {
      if (!valid_move (M, P, COMPp, OPPp)) {
        return 0;               // move ok
      }
    }
  }
  return -1;                    // no moves
}

static inline int8_t CROWNING (int8_t POS, int8_t PLAYER) {  // assumes valid pos
  return ((PLAYER == 1 && POS < 7) || (PLAYER == 2 && POS > 70));
}

static inline INTEGER MODI (INTEGER N) {
  return (N < 0) ? -N : N;
}

static inline int8_t MOD8 (int8_t N) {
  return (N < 0) ? -N : N;
}

INTEGER value_of_side (Player *COMPp, Player *OPPp) {
// bases have already been adjusted
INTEGER V1, V2, V3, V4, V5, V6, V7;
int8_t P, PP, M, MM, MV, ADV1, VM, PLAYER;
INTEGER *CTYPEp;
int8_t *CPOSp;

#define CPOS (*CPOSp)
#define CTYPE (*CTYPEp)

  PLAYER = COMP__PLAYERNO;

  // back control
  V2 = 0;
  if (!OPP__NUMC) {              // OPP has no crowns yet
    if (PLAYER == 1) {          // player 1
      for (P = 1; P <= 5; P++) {
        if (COMP__POS (P) == BACK1 (P))
          V2 += back_wt;
      }
    } else {                    // player 2
      for (P = 1; P <= 5; P++) {
        if (COMP__POS (P) == BACK2 (P))
          V2 += back_wt;
      }
    }
  }
  V1 = V3 = V4 = V5 = V6 = V7 = 0;
  for (P = 1; P <= COMP__NUM; P++) {
    CPOSp = &COMP__POS (P);
    CTYPEp = &COMP__TYPE (P);
    ADV1 = 0;

    // add up piece values
    V1 += CKTYPE(CTYPE);
    for (M = 0; M <= 7; M++) {
      VM = valid_move (M, P, COMPp, OPPp);
      MV = MOVE (M);
      // centre control
      if (CPOS == CENTSQ (M)) {
        V4 += cent_wt;
        if (CKTYPE(CTYPE) == CROWN)
          V4 += cent_wt + 1;
      }
      
      if (VM >= 0) {            // mobility
        V3 += mob_wt;
        if (VM > 0)
          V3 += mob_wt;
        if (CKTYPE(CTYPE) != CROWN) {
          // advancement 1
          if ((ADV1 == 0) && CROWNING (CPOS + MV, PLAYER)) {
            V5 += adv1_wt;
            ADV1 = 1;
          }
          // advancement 2
          if (VM == 0) {            // ignore jumps to crown
            CPOS += MV;
            for (MM = 0; MM <= 6; MM += 2) {
              if (CROWNING (CPOS + MOVE (MM), PLAYER)
                  && valid_move (MM, P, COMPp, OPPp) >= 0) {
                V6 += adv2_wt;
                break;
              }
            }
            CPOS -= MV;
          }
        }
        // cramp
        if ((VM == 0) && CKTYPE(CTYPE) == CROWN && OPP__NUM > 0) {
          CPOS += MV;
          for (PP = 1; PP <= OPP__NUM; PP++) {
            for (MM = 1; MM <= 7; MM += 2) {
              if (valid_move (MM, PP, OPPp, COMPp) >= 0) {
                V5 -= cramp_wt;
                break;
              }
            }
          }
          CPOS -= MV;
        }
      }
    }
  }
  return V1 + V2 + V3 + V4 + V5 + V6 + V7;
#undef FRAME
#undef CPOS
#undef CTYPE
}

INTEGER value_of_pos (Player *COMPp, Player *OPPp) {
INTEGER VALUE;

  if (pending_move (COMPp, OPPp) >= 0) {
    VALUE = value_of_side (COMPp, OPPp) - value_of_side (OPPp, COMPp) - ply_number;
  } else {
    VALUE = -INFTY + ply_number;        // no mobility!!
  }
  return (COMP__PLAYERNO == ME) ? VALUE : -VALUE;
}

#ifdef OLDSTYLE
void make_move (int8_t MV, int8_t P, int8_t *Tp, Player *COMPp, Player *OPPp) {
#define T (*Tp)
INTEGER *CTYPEp, *OTYPEp;
int8_t *CPOSp, *OPOSp, *ONUMp, *ONUMCp;

#define CPOS (*CPOSp)
#define CTYPE (*CTYPEp)
#define OPOS (*OPOSp)
#define OTYPE (*OTYPEp)
#define ONUM (*ONUMp)
#define ONUMC (*ONUMCp)

  CPOSp = &COMP__POS (P);
  CTYPEp = &COMP__TYPE (P);
  CPOS = CPOS + MV;
  if (T) {                      // a take
    OPOSp = &OPP__POS (T);
    OTYPEp = &OPP__TYPE (T);
    ONUMp = &OPP__NUM;
    ONUMCp = &OPP__NUMC;
    SP += 1;
    PSTACK (SP) = OPOS;         // save position of taken piece
    TSTACK (SP) = CKTYPE(OTYPE);        // save piece type
    NSTACK (SP) = T;            // save piece number
    OPOS = OPP__POS (ONUM);      // remove piece from board
    ONUM -= 1;                  // reduce piece count for opp
    if (CKTYPE(OTYPE) == CROWN) ONUMC -= 1;
    OTYPE = CKTYPE(OPP__TYPE (ONUM + 1)); // (really OPP_TYPE(ONUM), but value before ONUM was decremented above) Could substitute ONUM--?
  }
  if (CKTYPE(CTYPE) != CROWN && CROWNING (CPOS, COMP__PLAYERNO)) {
    CTYPE = CKTYPE(CROWN);              // crown piece
    COMP__NUMC += 1;             // increase crown count
    T = 0;                      // no more takes
  }
#undef T
#ifdef PIZERO
  DEBUG_EVERYTHING(__LINE__);
#endif
}
#else
void make_move (int8_t MV, int8_t P, int8_t *Tp, Player *COMPp, Player *OPPp) {
#define T (*Tp)
  // This is fairly major surgery, considering that it was working before.
  // might need to revert.  geting a gcc register spill error
#ifdef PIZERO
  DEBUG_EVERYTHING(__LINE__);
#endif
  COMP__POS (P) += MV;
  if (T) {                      // a take
    SP += 1;
    PSTACK (SP) = OPP__POS (T);         // save position of taken piece
    TSTACK (SP) = CKTYPE(OPP__TYPE (T));        // save piece type
    NSTACK (SP) = T;            // save piece number
    OPP__POS (T) = OPP__POS (OPP__NUM);      // remove piece from board
    OPP__NUM -= 1;                  // reduce piece count for opp
    if (CKTYPE(OPP__TYPE (T)) == CROWN) OPP__NUMC -= 1;
    OPP__TYPE (T) = CKTYPE(OPP__TYPE (OPP__NUM + 1)); // (really OPP_TYPE(ONUM), but value before ONUM was decremented above) Could substitute ONUM--?
  }
  if (CKTYPE(COMP__TYPE (P)) != CROWN && CROWNING (COMP__POS (P), COMP__PLAYERNO)) {
    COMP__TYPE (P) = CKTYPE(CROWN);              // crown piece
    COMP__NUMC += 1;             // increase crown count
    T = 0;                      // no more takes
  }
#undef T
#ifdef PIZERO
  DEBUG_EVERYTHING(__LINE__);
#endif
}
#endif

void Display_board (int8_t ignore);

// This is the expensive recursion.  Minimise local variables as much as possible.
INTEGER try_possible_moves (int8_t PLY, INTEGER DEPTH, Player *COMPp, Player *OPPp) {
static INTEGER VALUE;           // ONLY VARIABLES THAT DON'T NEED TO SURVIVE RECURSION!!!
INTEGER OLDTYPE;
int8_t M, MM, MMM, MMF, TAKES, OLDPOS, APT, P, T, TT;
INTEGER *MAXPLYp, *MINPLYp;

#define MAXPLY (*MAXPLYp)
#define MINPLY (*MINPLYp)

#define PURSUIT(PLY,M) (PLY == 1 ? 1 : (~M) & 1)

  NODES += 1;
  APT = pending_move (COMPp, OPPp);
  if ((DEPTH >= search_limit && APT <= 0) || PLY > MAX_RECURSIVE_DEPTH) {
    ply_number = PLY - 1;
    return value_of_pos (COMPp, OPPp);
  }
  MINPLYp = &MIN (PLY);
  MINPLY = INFTY;
  MAXPLYp = &MAX (PLY);
  MAXPLY = -INFTY;
  if (APT >= 0) {               // COMP able to move
    if (APT > 0) {              // take priority
      P = APT;
      APT = 2;
      MMM = 1;
      MMF = 7;
      if (PLY == 1)
        search_limit = 2;
    } else {
      P = 1;
      APT = 2;
      MMM = 0;
      MMF = 6;
    }
    for (P = P; P <= COMP__NUM; P++) {
      OLDPOS = COMP__POS (P);    // STACK THESE TO PRESERVE ACROSS RECURSION
      OLDTYPE = CKTYPE(COMP__TYPE (P));
      for (M = MMM; M <= MMF; M += APT) {
        TAKES = 0;
        T = valid_move (M, P, COMPp, OPPp);
        if (T >= 0) {           // valid move
          MM = M;
          TT = T;
	  do {
	    //another_take:
            if (TT > 0) TAKES += 1;
            // Hack! to flash "THINKING" on screen. Somewhat erratic.
            Wait_Recal (); Flash++; Reset0Ref (); Intensity_7F (); Print_Str_d (0, -120, "      THINKING...\x80");
#ifdef PIZERO
            Dim=DIM;Display_board(0);Dim=0;
#endif
            make_move (MOVE (MM), P, &TT, COMPp, OPPp);   // try this move
            if (TT > 0) {         // another take
              for (MM = 1; MM <= 7; MM += 2) {
                TT = valid_move (MM, P, COMPp, OPPp);
                if (TT > 0) break; // goto another_take;
              }
            }
	  } while (TT > 0);
          VALUE = try_possible_moves (PLY + 1, DEPTH + PURSUIT (PLY, M), OPPp, COMPp);
          COMP__POS (P) = OLDPOS;
          COMP__TYPE (P) = CKTYPE(OLDTYPE);
          OPP__NUM += TAKES;
          while (TAKES > 0) {
            TT = NSTACK (SP);
            OPP__POS (TT) = PSTACK (SP);
            OPP__TYPE (TT) = CKTYPE(TSTACK (SP));
            TAKES -= 1;
            SP -= 1;
          }
          if (COMP__PLAYERNO == ME) {
            if (VALUE > MAXPLY) {
              MAXPLY = VALUE;
              if (PLY == 1) {
                best_move = M;
                best_take = T;
                best_piece = P;
              }
            }
            if (PLY != 1 && MAXPLY >= MIN (PLY - 1)) {
              return MAXPLY;
            }
          } else {
            if (VALUE < MINPLY)
              MINPLY = VALUE;
            if (MINPLY <= MAX (PLY - 1)) {
              return MINPLY;
            }
          }
        } // if (T>=0)
      } // for M
    } // for P
  } // if APT >= 0
  return (COMP__PLAYERNO == ME) ? MAXPLY : MINPLY;
}