// Original code used 32 bit ints and INFTY was a hard-coded 100000
// Reducing to a 16 bit int doesn't seem to have harmed the program.

#ifdef TRUE
#undef TRUE
#undef FALSE
#endif

#define TRUE 1
#define FALSE 0

#define mob_wt 6
#define back_wt 4
#define cent_wt 4
#define adv1_wt 450
#define adv2_wt 50
#define cramp_wt 6

// TO DO: if we end up with more global booleans,
// remember we can pack 8 of them into a byte to save space,
// either explicitly or using a struct containing bitfields..
static int8_t a_win;
static int8_t search_limit;
static int8_t Cancel_Request;

#define CROWN 1800

static const int8_t BACK1p[5] = { 77, 75, 73, 71, 64 };
#define BACK1(index) BACK1p[(index)-1]

static const int8_t BACK2p[5] = { 0, 2, 4, 6, 13 };
#define BACK2(index) BACK2p[(index)-1]

static const int8_t CENTSQx[8] = { 51, 53, 42, 44, 33, 35, 24, 26 };
#define CENTSQ(index) CENTSQx[index]

static const int8_t MOVEx[8] = { 9, 18, 11, 22, -9, -18, -11, -22 };
#define MOVE(index) MOVEx[index]

#include "diags.h"

#define DECLARE(type,name,low,high) type name##p[(high)-(low)+1]; type *name = &name##p[-(low)]
#define ARRAY(index,type,name,low,high) name##p[CHECK(index,#name,low,high,__LINE__)]

#define MAX_RECURSIVE_DEPTH 12

// Minimax values, to depth of recursion (max plies). So must be 16 bit.
#ifdef OLDSTYLE
DECLARE (INTEGER, MIN, 1, MAX_RECURSIVE_DEPTH);
#define MIN(index) ARRAY(index, INTEGER, MIN, 1, MAX_RECURSIVE_DEPTH)
DECLARE (INTEGER, MAX, 1, MAX_RECURSIVE_DEPTH);
#define MAX(index) ARRAY(index, INTEGER, MAX, 1, MAX_RECURSIVE_DEPTH)
#else
// wasting 2*2 bytes here to simplify code. Elements 0 are not used.
INTEGER MINp[MAX_RECURSIVE_DEPTH+1];
#define MIN(index) MINp[index]
INTEGER MAXp[MAX_RECURSIVE_DEPTH+1];
#define MAX(index) MAXp[index]
#endif

DECLARE (char, REPLY, 1, 9);
#define REPLY(index) ARRAY(index, char, REPLY, 1, 9)

#define ME 1
#define YOU 2

// Initialisation data for COMP and OPP arrays...

typedef struct Player {
  int8_t  COLOUR;
  int8_t  PLAYERNO;
  int8_t  POS[12]; // 1:12 still, base address is tweaked
  INTEGER TYPE[12];
  int8_t  NUM;
  int8_t  NUMC;
} Player;

static const Player PLAYER1 = {
  'W',                          // -1 - colour
  ME,                           // 0 - player no (1 or 2)
#ifdef DEBUG_SET_POSITION
  // put any set position in here for testing...
  {62, 42, 55, 11, 0, 0, 0, 0, 0, 0, 0, 0},                                       // 1:12 - location of pieces (CPOS)
  {1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000},       // 13:24 - type (eg CROWN) (CTYPE)
  4,                            // 25 - count of pieces (CNUM)
#else
  {77, 75, 73, 71, 64, 66, 62, 60, 57, 55, 53, 51},                               // 1:12 - location of pieces (CPOS)
  {1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000},       // 13:24 - type (eg CROWN) (CTYPE)
  12,                           // 25 - count of pieces (CNUM)
#endif
  0                             // 26 - count of crowns (CNUMC)
};
// 1:12 maps to 0:11
#define PLAYER1_POS(P)   PLAYER1.POS[(P)-1]
#define PLAYER1_TYPE(P)  PLAYER1.TYPE[(P)-1]

static const Player PLAYER2 = {
  'B',                          // -1 - colour
  YOU,                          // 0 - player no (1 or 2)
#ifdef DEBUG_SET_POSITION
  {33, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},                                          // 1:12 - location of pieces (OPOS)
  {1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000},       // 13:24 - type (eg CROWN) (OTYPE)
  2,
#else
  {0, 2, 4, 6, 13, 11, 15, 17, 20, 22, 24, 26},                                   // 1:12 - location of pieces (OPOS)
  {1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000},       // 13:24 - type (eg CROWN) (OTYPE) 
  12,                           // 25 - count of pieces (ONUM)
#endif
  0                             // 26 - count of crowns (ONUMC)
};
#define PLAYER2_POS(P)   PLAYER2.POS[(P)-1]
#define PLAYER2_TYPE(P)  PLAYER2.TYPE[(P)-1]

// These two would be better as structs...
Player COMP;
//DECLARE (INTEGER, COMP, -1, 26);
//#define COMP(index) ARRAY(index, INTEGER, COMP, -1, 26)
#define COMP_COLOUR   COMP.COLOUR
#define COMP_PLAYERNO COMP.PLAYERNO
#define COMP_POS(P)   COMP.POS[CHECK(P,#P,1,12,__LINE__)-1]
#define COMP_TYPE(P)  COMP.TYPE[CHECK(P,#P,1,12,__LINE__)-1]
#define COMP_NUM      COMP.NUM
#define COMP_NUMC     COMP.NUMC

#define COMP__COLOUR   COMPp->COLOUR
#define COMP__PLAYERNO COMPp->PLAYERNO
#define COMP__POS(P)   COMPp->POS[CHECK(P,#P,1,12,__LINE__)-1]
#define COMP__TYPE(P)  COMPp->TYPE[CHECK(P,#P,1,12,__LINE__)-1]
#define COMP__NUM      COMPp->NUM
#define COMP__NUMC     COMPp->NUMC

Player OPP;
//DECLARE (INTEGER, OPP, -1, 26);
//#define OPP(index) ARRAY(index, INTEGER, OPP, -1, 26)

#define OPP_COLOUR   OPP.COLOUR
#define OPP_PLAYERNO OPP.PLAYERNO
#define OPP_POS(P)   OPP.POS[CHECK(P,#P,1,12,__LINE__)-1]
#define OPP_TYPE(P)  OPP.TYPE[CHECK(P,#P,1,12,__LINE__)-1]
#define OPP_NUM      OPP.NUM
#define OPP_NUMC     OPP.NUMC

#define OPP__COLOUR   OPPp->COLOUR
#define OPP__PLAYERNO OPPp->PLAYERNO
#define OPP__POS(P)   OPPp->POS[CHECK(P,#P,1,12,__LINE__)-1]
#define OPP__TYPE(P)  OPPp->TYPE[CHECK(P,#P,1,12,__LINE__)-1]
#define OPP__NUM      OPPp->NUM
#define OPP__NUMC     OPPp->NUMC

#ifdef OLDSTYLE
DECLARE (int8_t, PSTACK, 1, MAX_RECURSIVE_DEPTH);       // piece position take stack
#define PSTACK(index) ARRAY(index, int8_t, PSTACK, 1, MAX_RECURSIVE_DEPTH)
DECLARE (INTEGER, TSTACK, 1, MAX_RECURSIVE_DEPTH);      // piece type stack
#define TSTACK(index) ARRAY(index, INTEGER, TSTACK, 1, MAX_RECURSIVE_DEPTH)
DECLARE (int8_t, NSTACK, 1, MAX_RECURSIVE_DEPTH);       // piece number stack
#define NSTACK(index) ARRAY(index, int8_t, NSTACK, 1, MAX_RECURSIVE_DEPTH)
#else
// waste a byte to simplify code later... we can afford to be profligate with
// RAM now that we have reduced the footprint enough that everything fits,
// including 12 levels of recursion for the main evaluation code.
int8_t PSTACKp[MAX_RECURSIVE_DEPTH+1];
#define PSTACK(index) PSTACKp[index]
INTEGER TSTACKp[MAX_RECURSIVE_DEPTH+1];
#define TSTACK(index) TSTACKp[index]
int8_t NSTACKp[MAX_RECURSIVE_DEPTH+1];
#define NSTACK(index) NSTACKp[index]
#endif

static int8_t SP;               // stack pointer
INTEGER VALUEB, NODES;          // MUST be 16-bits
int8_t P, M, PIECE, DIF, MODIF, MORE, best_piece, best_move, best_take, JMAN, POS, OLDPOS, NEWPOS, LASTPOS, COMPOS, ply_number, expected_move;
//char A, B, C;
static int8_t First_player_was;

#ifdef PIZERO
void DEBUG_EVERYTHING(int line) {
  int8_t P, I, J, POS;
  int8_t BOARDp[80];
#define BOARD(index) BOARDp[(index)+1]
  if (!logfile) return;
  fprintf(logfile, "-- %d -- %ld\n", line, SP);
  for (I = 0; I <= 79; I++) BOARDp[I] = ' ';
  // BOARD is not really needed, can move to board locations with
  // cursor addressing on linux or vector graphics on Vectrex
  for (I = 0; I <= 7; I++) {
    for (J = 0; J <= 6; J += 2) {
      BOARD (10 * I + J + (I & 1)) = '#';
    }
  }
  for (I = 1; I <= 12; I++) {
    if (I <= COMP_NUM) {
      POS = COMP_POS(I);
      BOARD (POS) = (CKTYPE(COMP_TYPE(I)) == CROWN) ? 'X' : 'x';
    }
    if (I <= OPP_NUM) {
      POS = OPP_POS(I);
      BOARD (POS) = (CKTYPE(OPP_TYPE(I)) == CROWN) ? 'O' : 'o';
    }
  }
  fprintf(logfile, "\n  A B C D E F G H");
  for (I = 70; I >= 0; I -= 10) {
    fputc('\n', logfile);
    fputc((char) (I / 10 + '1'), logfile);
    for (J = 0; J <= 7; J++) {
      fputc(' ', logfile);
      fputc((char) BOARD (J + I), logfile);
    }
    fputc(' ', logfile);
    fputc((char) (I / 10 + '1'), logfile);
  }
  fprintf(logfile, "\n  A B C D E F G H\n\n");
			      
  fprintf(logfile, "COMP NUM  %d  NUMC %d\n", COMP_NUM, COMP_NUMC);
  fprintf(logfile, "COMP POS ");
  for (P = 0; P <= 11; P++) {
    fprintf(logfile, "%d ", COMP.POS[P]);
  }
  fprintf(logfile, "\n");
  fprintf(logfile, "COMP TYPE ");
  for (P = 0; P <= 11; P++) {
    fprintf(logfile, "%d ", COMP.TYPE[P]);
  }
  fprintf(logfile, "\n");

  fprintf(logfile, "OPP NUM  %d  NUMC %d\n", OPP_NUM, OPP_NUMC);
  fprintf(logfile, "OPP POS ");
  for (P = 0; P <= 11; P++) {
    fprintf(logfile, "%d ", OPP.POS[P]);
  }
  fprintf(logfile, "\n");
  fprintf(logfile, "OPP TYPE ");
  for (P = 0; P <= 11; P++) {
    fprintf(logfile, "%d ", OPP.TYPE[P]);
  }
  fprintf(logfile, "\n");
  fflush(logfile);
}
#endif

#ifndef PIZERO
#include <vectrex.h>
#include "controller.h"
#endif

#define FULLBRIGHT 127
#define BACKGROUND_INTENSITY 30 /* 70 */
// Vectrex brightness must be set so that board grid is faint, matching what you see in Vide
#define WHITE_INTENSITY 90
#define BLACK_INTENSITY 50
#define DIM 40
#define MAXDIM (127-40)
static int8_t Dim;

static int8_t Flash; // increments every frame with wrap-around

#define BIG_SCALE 0x7F
#define SMALL_SCALE 0x1F

#define MEDIUM_SCALE 0x5A
#ifdef PIZERO
#define TINY_SCALE 0x4
#define TINY_SCALE_CROWNED 0x2
#else
#define TINY_SCALE 0x1
#define TINY_SCALE_CROWNED 0x2
#endif

static inline void set_scale (unsigned int s) {
#ifdef PIZERO
  current_scale = s;
#else
  VIA_t1_cnt_lo = s;
#endif
}