// modified by Wei-Hwa to compile on unix, 2006

/*
 *  slide.c
 *
 *  core routines for jimslide
 *  copyright Jim Leonard 1999
 */
char VERSION_TXT[] = "jim'slide version 0.81";
char COPYRIGHT_TXT[] = "copyright Jim Leonard, 1999, 2000";

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <limits.h>


#include "btree64k.h"
#include "slide.h"

/* include our global variables here */
#include "sl_globals.c"
#include "show_win.c"

#define MOVE_RIGHT  0
#define MOVE_LEFT   1
#define MOVE_DOWN   2
#define MOVE_UP     3
int DIR[4];

unsigned char uncompressMask = 0;

#define MAX_LEVEL 64
int tempFileLevelList[MAX_LEVEL];


int main(int argc, char *argv[])
   {
   unsigned int totalBoards = 1;
   unsigned int boardsThisGen;
   char workFileName[128];
   int a;
   int checkpointInd = -1;
   PosListNode *curPln;
   PosListNode *nextPln;


   Generation gen0 = {NULL, NULL, 0, NULL, NULL};
   Generation winGen = {NULL, NULL, 0, NULL, NULL}; 


   printf("%s\n", VERSION_TXT);
   printf("%s\n\n", COPYRIGHT_TXT);
   time(&startTime);
   ReadParms(argc, argv);

   for (a = 0; a < bitsPerType; ++a)
      uncompressMask = uncompressMask * 2 + 1;

   BT_SetBTAttributes(compressedPuzSize, compressedPuzSize);

   if (directed)
      {
      maxDist = (xsize * xsize + ysize * ysize) * numPiece;
      distList = (int *) calloc(maxDist + 1, sizeof(int));
      if (distList == NULL)
         {
         printf("Unable to allocate memory for distance list\n");
         exit(0);
         }
      }

   if (!bigStorage)
      {
      if (numWorkFiles > MAX_WORK_FILES)
         {
         printf("numWorkFiles lowered to %d\n", MAX_WORK_FILES);
         numWorkFiles = MAX_WORK_FILES;
         }

      minWorkFile = 0;
      numCurWorkFiles = numWorkFiles;

      if (winOnly)
         {
         if (concurrent)
            {
            numCurWorkFiles = numWorkFiles / 6;
            numWorkFiles = numCurWorkFiles * 6;
            }
         else
            {
            numCurWorkFiles = numWorkFiles / 3;
            numWorkFiles = numCurWorkFiles * 3;
            }
         }

      if (numCurWorkFiles < 1)
         {
         printf("Must have at least 1 work file, 3 if winonly, and 6 if\n");
         printf("winonly and concurrent.\n");
         }

      for (a = 0; a < numWorkFiles; ++a)
         {
         sprintf(workFileName, WORK_FILE_NAME, a);
         if (NULL == (workFile[a] = fopen (workFileName, "w+b")))
            {
            printf("Can't create %s\n", workFileName);
            exit(0);
            }
         }
      }
   DoInits(&gen0, &winGen, 1, 2);

   if (bigStorage)
      {
      curMoveNum = 1;
      }
   else
      {
      nextGen = &gen0;
      curGen = NULL;
      prevGen = NULL;
      }

   ReadyNextGen();


   if (concurrent)
      {
      ++totalBoards;
/*      ++curMove; */

      if (bigStorage)
         {
         curMoveNum++;
         }
      else
         {
         fNextGen = nextGen;
         fCurGen = curGen;
         fPrevGen = prevGen;
         nextGen = &winGen;
         curGen = NULL;
         prevGen = NULL;

         ReadyNextGen();

         rNextGen = nextGen;
         rCurGen = curGen;
         rPrevGen = prevGen;
         nextGen = fNextGen;
         curGen = fCurGen;
         prevGen = fPrevGen;
         }
      processForward = 1;
      }

   if (argc > 2)
      {
      curMoveNum = atoi(argv[2]);
      curMove = curMoveNum - 1;
      if (concurrent)
         ++curMoveNum;
      }

   while (1)
      {
      /* if we are recovering from previous run we might not want to do */
      /* this set of processing */
      if ((!bigStorage) || (!concurrent) || (curMoveNum & 1))
         {
         if (0 == (boardsThisGen = ProcessGen()))
            break;
         totalBoards += boardsThisGen;
         fprintf(stderr,"On move %d, %d queued, %d boards %d seconds\n",
               ++curMove, boardsThisGen, totalBoards, time(NULL) - startTime);

         if (cutoffStep && (curMove > cutoffStep))
            {
            printf("Unable to find solution in %d steps\n", cutoffStep);
            exit(0);
            }


         if (winOnly && bigStorage)
            {
            if (concurrent)
               {
               if (curMoveNum - 4 > 0)
                  RemoveGeneration (curMoveNum - 4);
               }
            else
               {
               if (curMoveNum - 2 > 0)
                  RemoveGeneration (curMoveNum - 2);
               }
            }
         if (winOnly && !bigStorage)
            {
            minWorkFile += numCurWorkFiles;
            if (minWorkFile >= numWorkFiles)
               minWorkFile = 0;

            if (prevGen)
               {
               for (a = 0; a < numCurWorkFiles; ++a)
                  {
                  fclose(workFile[minWorkFile + a]);
                  sprintf(workFileName, WORK_FILE_NAME, minWorkFile + a);
                  if (NULL == (workFile[minWorkFile + a] = fopen (workFileName, "w+b")))
                     {
                     printf("Can't create %s\n", workFileName);
                     exit(0);
                     }
                  }

               curPln = prevGen->pln0;
               while (curPln)
                  {
                  nextPln = curPln->next;
                  free(curPln);
                  curPln = nextPln;
                  }

               if (prevGen != &gen0)
                  free(prevGen);
               }
            }

         ReadyNextGen();
         }

      if (concurrent)
         {
         if (!bigStorage)
            {
            fNextGen = nextGen;
            fCurGen = curGen;
            fPrevGen = prevGen;
            nextGen = rNextGen;
            curGen = rCurGen;
            prevGen = rPrevGen;
            }

         processForward = 0;
         if (0 == (boardsThisGen = ProcessGen()))
            break;

         processForward = 1;
         totalBoards += boardsThisGen;
         fprintf(stderr,"On move %d, %d queued, %d boards %d seconds\n",
               ++curMove, boardsThisGen, totalBoards, time(NULL) - startTime);


         if (winOnly && bigStorage)
            {
            if (concurrent)
               {
               if (curMoveNum - 4 > 0)
                  RemoveGeneration (curMoveNum - 4);
               }
            else
               {
               if (curMoveNum - 2 > 0)
                  RemoveGeneration (curMoveNum - 2);
               }
            }
         
         if (winOnly && !bigStorage)
            {
            minWorkFile += numCurWorkFiles;
            if (minWorkFile >= numWorkFiles)
               minWorkFile = 0;

            if (prevGen)
               {
               for (a = 0; a < numCurWorkFiles; ++a)
                  {
                  fclose(workFile[minWorkFile + a]);
                  sprintf(workFileName, WORK_FILE_NAME, minWorkFile + a);
                  if (NULL == (workFile[minWorkFile + a] = fopen (workFileName, "w+b")))
                     {
                     printf("Can't create %s\n", workFileName);
                     exit(0);
                     }
                  }

               curPln = prevGen->pln0;
               while (curPln)
                  {
                  nextPln = curPln->next;
                  free(curPln);
                  curPln = nextPln;
                  }

               if (prevGen != &gen0)
                  free(prevGen);
               }
            }

         if (cutoffStep && (curMove > cutoffStep))
            {
            printf("Unable to find solution in %d steps\n", cutoffStep);
            exit(0);
            }
         
         ReadyNextGen();

         if (!bigStorage)
            {
            rNextGen = nextGen;
            rCurGen = curGen;
            rPrevGen = prevGen;
            nextGen = fNextGen;
            curGen = fCurGen;
            prevGen = fPrevGen;
            }
         }
      }
   printf("unable to find a solution\n");
   printf("Finished in %d seconds\n", time(NULL) - startTime);

   return 1;
   }


void ReadyNextGen()
   {
   if (bigStorage)
      {
      ++curMoveNum;
      }
   else
      {
      InitGen(nextGen);
      prevGen = curGen;
      curGen = nextGen;
      nextGen = nextGen->next;
      }
   }


void InitGen(Generation *prevGen)
   {
   Generation *gen;

   if (NULL == (gen = (Generation *)malloc(sizeof(Generation))))
      {
      printf("Unable to allocate a new generation\n");
      exit(1);
      }
   
   prevGen->next = gen;
   gen->prev = prevGen;
   gen->next = NULL;
   gen->numBoards = 0;
   gen->pln0 = NULL;
   gen->lastPln = NULL;
   }


void DoInits(Generation *gen0, Generation *winGen, int move0, int winMove)
   {
   int a, b;

   /* init some memory chunks */
   /* make them an additional 512 bytes longer so we */
   /* can run in place compression                   */
   goodPosSL = SL_Malloc(maxEntriesPerSl + (512 / compressedPuzSize) + 1);
   getNextBoardSL = SL_Malloc(maxEntriesPerSl + (512 / compressedPuzSize) + 1);
   if (bigStorage)
      mergeListSL = SL_Malloc(maxEntriesPerSl + (512 / compressedPuzSize) + 1);
   newPosList = BT_Init(maxNewPos);

   InitBaseBoard();
   InitPieces();
   InitBoard(workBoard);
   PrintBoard(workBoard);

   /*
    *  It's at this point (and this point only) that I have my board
    *  as the user designed it without the pieces being mixed around
    *  so...  while I'm here I should call RenumberPieces() so that
    *  I can keep a snapshot of this for when I've found my solution.
    */
   RenumberPieces(workBoard);

   if (bigStorage)
      {
      InitLevelList();
      }
   else
      {
      prevGen = NULL;
      curGen = NULL;
      nextGen = gen0;
      }

   EnqueueBoard(workBoard);
   ProcessNewPosList();
   if (bigStorage)
      {
      DoFinalMerge(move0, 0, 0);
      }

   if (concurrent)
      {
      for (a = 0; a < numPiece; ++a)
         piece[a].startX = -1;

      for (a = 0; a < winList.numWinCond; ++a)
         {
         for (b = 0; b < numPiece; ++b)
            {
            if (piece[b].pieceType == winList.winCond[a].pieceType &&
                  piece[b].startX == -1)
               {
               piece[b].startX = winList.winCond[a].posX;
               piece[b].startY = winList.winCond[a].posY;
               break;
               }
            }
         if (b == numPiece) /* ie we didn't find a match for our win condition */
            /* we can't win anyway so DIE */
            {
            printf("Win conditions don't match pieces, impossible to solve\n");
            exit(0);
            }
         }
      InitBoard(workBoard);
      printf("Working from both ends to get to this position\n");
      PrintBoard(workBoard);

      if (!bigStorage)
         nextGen = winGen;

      EnqueueBoard(workBoard);
      ProcessNewPosList();
      if (bigStorage)
         DoFinalMerge(winMove, 0, 0);
      }
   }


int locList[LARGEST_BOARD_SIZE];
int *nextLLItem;

void ResetLocList()
   {
   nextLLItem = locList;
   }

int AddLocList(int loc)
   {
   int *curLLItem = locList;
   for (; curLLItem < nextLLItem; ++curLLItem)
      if (loc == *curLLItem)
         return 0;
   *(nextLLItem++) = loc;
   return 1;
   }


/*
 *  This is the guy that gets the real work done
 *  (he doesn't do most of it mind you, just sees to it
 *  that it gets done).
 *  returns number of new boards generated
 */
int ProcessGen()
   {
   unsigned int dcount; /* also used at the very end as a temp var */
   int a;
   int rejected = 0;
   unsigned char *winPos;

   if (!bigStorage && !curGen->numBoards)
      {
      printf("found no solution\n");
      return 0;
      }

   cutoffDist = 0;

   if (directed)
      {
      if (curGen->numBoards > directed)
         {
         for (
            dcount = 0; 
            (dcount < directed) && (cutoffDist < maxDist);
            dcount += distList[cutoffDist++]);
         }

      for (a = 0; a < 15; ++a)
         fprintf(stderr, "%d, ", distList[a]);

      /* clear distList */
      for (a = 0; a < maxDist; ++a)
         distList[a] = 0;

      fprintf(stderr, "%d", cutoffDist);
      }

   while(GetNextBoard(workBoard))
      {
      if (cutoffDist)
         if (Distance() > cutoffDist)
            {
            rejected++;
            continue;
            }

      ProcessBoard();
      }

   if (directed)
      fprintf(stderr, ", %d\n", rejected);

   ProcessNewPosList();
   if (bigStorage)
      {
      if (concurrent)
         DoFinalMerge(curMoveNum, 
               (curMoveNum - 2 > 0 ? curMoveNum - 2 : 0),
               (curMoveNum - 4 > 0 ? curMoveNum - 4 : 0));
      else
         DoFinalMerge(curMoveNum, 
               (curMoveNum - 1 > 0 ? curMoveNum - 1 : 0),
               (curMoveNum - 2 > 0 ? curMoveNum - 2 : 0));
      }

   /*
    *  It's here that we check for wins if bigstorage and concurrent
    */
   if (bigStorage && concurrent)
      if (NULL != (winPos = FindDuplicateEntryInFiles(
                        curMoveNum, -1, curMoveNum - 1, -1)))
         ConcurrentShowWin(winPos);

   if (bigStorage)
      {
      dcount = lastEntriesWritten;
      lastEntriesWritten = 0;
      return dcount;
      }
   else
      {
      return nextGen->numBoards;
      }
   }


/*
 *  So that the following don't need to be propagated down the stack
 *  frame as parameters, they are becoming globals
 */
int pieceNum;
PieceDef *pPtr;
int pStartLoc;

void ProcessBoard()
   {
   for (pieceNum = 0; pieceNum < numPiece; ++pieceNum)
      {
      pPtr = &piece[pieceNum];
      ResetLocList();
      AddLocList(piece[pieceNum].curLoc);
      pStartLoc = piece[pieceNum].curLoc;
      if (pPtr->numBloc == 1)
         TryPiece_1();
      else
         TryPiece();
      }
   }

void TryPiece_1()
   {
   /* do horizontal first */
   if (pPtr->moveX)
      {
      TryMove_1(1);

      TryMove_1(-1);
      }

   /* now do vertical */
   if (pPtr->moveY)
      {
      TryMove_1(xsize);

      TryMove_1(-xsize);
      }
   }

void TryMove_1(int offset)
   {
   /* because we're only moving 1 block we can take some liberties */
   /* that we couldn't normally take and some of the following vars */
   /* take on meanings slightly different from their counterparts */
   int newLoc = pPtr->curLoc + offset;
   int curLoc;
   unsigned char *newBoardLoc = workBoard + newLoc + *pPtr->xyoffset;
   unsigned char *curBoardLoc;


   /* see if we can move the piece */
   if (*newBoardLoc != SPACE_CHAR)
      return;

   if (!AddLocList(newLoc))
       return;

   curLoc = pPtr->curLoc;
   curBoardLoc = workBoard + curLoc + *pPtr->xyoffset;

   /* move the piece */
   *curBoardLoc = SPACE_CHAR;
   *newBoardLoc = pieceNum;
   
   pPtr->curLoc = newLoc;

   /* check if xstep or ystep is active on this piece and act on it as apppropriate */
   if (!pPtr->xstep || (!((newLoc % xsize - pStartLoc % xsize) % pPtr->xstep)))
      if (!pPtr->ystep || (!((newLoc / xsize - pStartLoc / xsize) % pPtr->ystep)))
         {
         /* copy the board to the move queue if applicable */
         if (EnqueueBoard(workBoard))
            {
            if (!concurrent)
               {
               /*
                *  If concurrent we check for wins in ProcessNewPosList()
                */
               if (CheckIfWin(workBoard))
                  ShowWin();
               }
            }
         }
   TryPiece_1();
   pPtr->curLoc = curLoc;

   /* move the piece back to be a good behaved routine */
   *newBoardLoc = SPACE_CHAR;
   *curBoardLoc = pieceNum;
   }


void TryPiece()
   {
   int a;
   unsigned char *curBoard = &workBoard[pPtr->curLoc];

   /* do horizontal first */
   if (pPtr->moveX)
      {
      for (a = 0; a < pPtr->moveBlock[MOVE_RIGHT]; ++a)
         if (*(curBoard + pPtr->moveTo[MOVE_RIGHT][a]) != SPACE_CHAR)
            break;
      if (a == pPtr->moveBlock[MOVE_RIGHT])
         TryMove(MOVE_RIGHT);

      for (a = 0; a < pPtr->moveBlock[MOVE_LEFT]; ++a)
         if (*(curBoard + pPtr->moveTo[MOVE_LEFT][a]) != SPACE_CHAR)
            break;
      if (a == pPtr->moveBlock[MOVE_LEFT])
         TryMove(MOVE_LEFT);
      }

   /* now do vertical */
   if (pPtr->moveY)
      {
      for (a = 0; a < pPtr->moveBlock[MOVE_DOWN]; ++a)
         if (*(curBoard + pPtr->moveTo[MOVE_DOWN][a]) != SPACE_CHAR)
            break;
      if (a == pPtr->moveBlock[MOVE_DOWN])
         TryMove(MOVE_DOWN);

      for (a = 0; a < pPtr->moveBlock[MOVE_UP]; ++a)
         if (*(curBoard + pPtr->moveTo[MOVE_UP][a]) != SPACE_CHAR)
            break;
      if (a == pPtr->moveBlock[MOVE_UP])
         TryMove(MOVE_UP);
      }
   }



void TryMove(int dir)
   {
   int curLoc = pPtr->curLoc;
   int newLoc = curLoc + DIR[dir];
   unsigned char *curBoardLoc = workBoard + curLoc;
   int a;

   if (!AddLocList(newLoc))
       return;

   /* move the piece */
   for (a = 0; a < pPtr->moveBlock[dir]; ++ a)
      {
      *(curBoardLoc + pPtr->moveTo[dir][a]) = pieceNum;
      *(curBoardLoc + pPtr->moveFrom[dir][a]) = SPACE_CHAR;
      }

   pPtr->curLoc = newLoc;

   /* check if xstep or ystep is active on this piece and act on it as apppropriate */
   if (!pPtr->xstep || (!((newLoc % xsize - pStartLoc % xsize) % pPtr->xstep)))
      if (!pPtr->ystep || (!((newLoc / xsize - pStartLoc / xsize) % pPtr->ystep)))
         {
         /* copy the board to the move queue if applicable */
         if (EnqueueBoard(workBoard))
            {
            if (!concurrent)
               {
               /*
                *  If concurrent we check for wins in ProcessNewPosList()
                */
               if (CheckIfWin(workBoard))
                  ShowWin();
               }
            }
         }
   TryPiece();
   pPtr->curLoc = curLoc;

   /* move the piece back to be a good behaved routine */
   for (a = 0; a < pPtr->moveBlock[dir]; ++ a)
      {
      *(curBoardLoc + pPtr->moveTo[dir][a]) = SPACE_CHAR;
      *(curBoardLoc + pPtr->moveFrom[dir][a]) = pieceNum;
      }
   }

/*
 *  EnqueueBoard now only compresses the board and checks for
 *  duplicates against the recently defined boards that are 
 *  sitting in memory.  Another process will then strip out
 *  duplicates from the previous generations (or earlier parts
 *  of this generation)
 */
int EnqueueBoard(unsigned char *board)
   {
   int status;
   unsigned char cString[256];

   CompressBoard(cString, board);
#if 0
   /* the backlink is no longer being stored */
   memcpy(&cString[compressedPuzSize], boardPtr, SIZE_BT_POINTER);
#endif

   /* add the compressed entry to the newPosList */
   status = BT_AddEntry(newPosList, cString, 0);
   if (status == -2) /* ie we ran out of space */
      {
      /* process the list and then attempt to add our new entry again */
      ProcessNewPosList();
      status = BT_AddEntry(newPosList, cString, 0);
      }

   if (status == 0)
      {
      printf("Error returned from BT_AddEntry\n");
      exit(0);
      }

   if (status == -1)
      return 0;
   return 1;
   }

int PNPL_totalEntries;

void ProcessNewPosListGen(Generation *gen)
   {
   PosListNode *curPln;
   int fetched = 0;
   unsigned char *endLNode;
   BT_Node *curBNode;
   unsigned char *curLNode;
   int cmpval;

   FILE *pauseFile;
   time_t pauseTime = 0;

   for (curPln = gen->pln0; curPln; curPln = curPln->next)
      {
      if (!curPln->pList)
         {
         GetPln(curPln, goodPosSL, 1);
         fetched = 1; /* mark this flag so later we */
                      /* know if we can drop curPln */
         }
      
      curLNode = curPln->pList->data;
      endLNode = &curPln->pList->data[curPln->pList->entries * bt_entrySize];
      curBNode = newPosList->nextNode;
      while(1)
         {
         if ((!curBNode) || (curLNode >= endLNode))
            break;
         
         cmpval = MEMCMP(curBNode->entry, curLNode, bt_entrySize);

         if (cmpval > 0)
            {
            curLNode += bt_entrySize;
            continue;
            }
         if (cmpval < 0)
            {
            curBNode = curBNode->gt_node;
            continue;
            }
         /*
          *  If we're here we found a match
          *  unlink curBNode (also keep in mind newPosList->nextNode)
          */
         
         --PNPL_totalEntries; /* also keep track of number of entries */
         if (curBNode->lt_node)
            {
            curBNode->lt_node->gt_node = curBNode->gt_node;
            }
         else
            {
            newPosList->nextNode = curBNode->gt_node;
            }

         if (curBNode->gt_node)
            {
            curBNode->gt_node->lt_node = curBNode->lt_node;
            }

         curBNode = curBNode->gt_node;
         }

      if (fetched)
         {
         DropPln(curPln, 0);
         fetched = 0;
         }
      }
   }

void ProcessNewPosList()
   {
   unsigned char *endNode = (unsigned char *)newPosList->nextNode;
   Generation *gen;
   PosListNode *curPln;
   int cmpval;
   unsigned char *curLNode;
   unsigned char *endLNode;
   BT_Node *curBNode;
   SList *plist = goodPosSL;
   int entries;
   int curMaxEntries;
   int a;
   int distance;
   Generation *checkGen;
   unsigned char baseEntry[256];
   PosFILE *outPosFile;
   FILE *pauseFile;
   time_t pauseTime = 0;


   PNPL_totalEntries = BT_NumEntries(newPosList);

   BT_CvtToLL(newPosList);

   if (!bigStorage)
      {
      if (checkFullTree)
         {
         fprintf(stderr, "*");
         for (checkGen = nextGen; checkGen; checkGen = checkGen->prev)
            ProcessNewPosListGen(checkGen);
         }
      else
         {
         if (prevGen)
            ProcessNewPosListGen(prevGen);         
   
         if (curGen)
            ProcessNewPosListGen(curGen);

         if (nextGen)
            ProcessNewPosListGen(nextGen);
         }

      /*
       *  if we're running concurrent, here is where we find wins
       *  this is mostly copied directly from ProcessNewPosListGen()
       */
      if (concurrent)
         {
         if (processForward)
            gen = rCurGen;
         else
            gen = fCurGen;
         if (gen)
            {
            for (curPln = gen->pln0; curPln; curPln = curPln->next)
               {
               GetPln(curPln, goodPosSL, 1);


               curLNode = curPln->pList->data;
               endLNode = &curPln->pList->data[curPln->pList->entries * bt_entrySize];
               curBNode = newPosList->nextNode;
               while(1)
                  {
                  if ((!curBNode) || (curLNode >= endLNode))
                     break;
         
                  cmpval = MEMCMP(curBNode->entry, curLNode, bt_entrySize);

                  if (cmpval > 0)
                     {
                     curLNode += bt_entrySize;
                     continue;
                     }
                  if (cmpval < 0)
                     {
                     curBNode = curBNode->gt_node;
                     continue;
                     }
                  /*
                   *  If we're here we found a win
                   */
                  ConcurrentShowWin(curBNode->entry);
                  exit(0);
                  }

               DropPln(curPln, 0);
               }
            }
         }
      }
   /*
    *  Find out how many entries we want to add to each list
    *  We'd like them to be evenly distributed
    */
   for (a = 1; (PNPL_totalEntries / a + 1) > maxEntriesPerSl; ++a);
   curMaxEntries = (PNPL_totalEntries / a) + 1;

   if (bigStorage && tempFileLevelList[0])
      {
      MergeTempFileWithLinkedList(0, 0, newPosList, 1, tempFileLevelList[1]++);
      tempFileLevelList[0] = 0;
      DoMerge(1);
      }
   else
      {
      if (bigStorage)
         outPosFile = OpenPosFile(0, tempFileLevelList[0]++, 1, 0);

      /*
       *  Now copy all entries that made the cut
       *  to sorted lists attached to nextGen
       */

      entries = 0;
      curLNode = plist->data;
      memset(baseEntry, 0, bt_entrySize);

      for (curBNode = newPosList->nextNode; curBNode; curBNode = curBNode->gt_node)
         {
         /* adding compression*/
         /* first find the first modified diffent byte from the baseEntry */
         for (a = 0; baseEntry[a] == curBNode->entry[a]; ++a);

         /* update the baseEntry */
         memcpy(&baseEntry[a], &curBNode->entry[a], bt_entrySize - a);

         /* write the (hopefully shorter) entry to the pile */
         *(curLNode++) = a;
         memcpy(curLNode, &baseEntry[a], bt_entrySize - a);
      
         /*
          *  If we're doing a directed search add the distances for each
          *  board copied to distList
          */
         if (directed)
            {
            distance = CDistance(baseEntry);
            if (distance < maxDist)
               ++distList[distance];
            }


         curLNode += (bt_entrySize - a);

         if (++entries == curMaxEntries)
            {
            plist->entries = entries;
            plist->size = curLNode - plist->data;
            if (bigStorage)
               lastEntriesWritten = WritePosFile(outPosFile, plist);
            else
               AddPln(nextGen, plist);

            entries = 0;
            curLNode = plist->data;
            memset(baseEntry, 0, bt_entrySize);
            }
         }

      if (entries)
         {
         plist->entries = entries;
         plist->size = curLNode - plist->data;
         if (bigStorage)
            {
            lastEntriesWritten = WritePosFile(outPosFile, plist);
            ClosePosFile(outPosFile);
            /* DoMerge(0); */
            }
         else
            {
            AddPln(nextGen, plist);
            }
         }
      }
   /* reset newPosList */
   BT_Reset(newPosList);
   ReorgGNBQueue();

   }


/*
 * just 0's the level list
 */
void InitLevelList()
   {
   int a;
   for (a = 0; a < MAX_LEVEL; ++a)
      tempFileLevelList[a] = 0;
   }

/*
 * handles some of the higher levels of creating the filename for
 * you
 */
void GetNewFileName(int level, int fileNum, char *fileName)
   {
   if (level >= MAX_LEVEL || level < 0)
      {
      printf("CreateTempFileName() - level %d greater than %d\n", level, MAX_LEVEL);
      fileName[0] = 0;
      return;
      }
   CreateTempFileName(level, tempFileLevelList[level], fileNum, fileName);
   ++tempFileLevelList[level];
   }

/*
 * mangles together a name for PosFile's
 * if entry == -1 makes a "final" name using level for the move num
 */
void CreateTempFileName(int level, int entry, int fileNum, char *fileName)
   {
   if (entry == -1)
      sprintf(fileName, "jsm%05d_%03d.tmp", level, fileNum);
   else
      sprintf(fileName, "js%02d%c%03d.tmp", level, entry + 'a', fileNum);
   }

/*
 * does the physical file opens for PosFile's
 */
void pf_open(PosFILE *pfile)
   {
   char name[256];

   CreateTempFileName(pfile->level, pfile->entry, pfile->seqNo, name);

   if (pfile->write)
      {
      if (NULL == (pfile->curFile = fopen(name, "wb")))
         {
         printf("pf_open - Can't create %s\n", name);
         exit(0);
         }
      }
   else
      {
      if (NULL == (pfile->curFile = fopen(name, "rb")))
         {
         printf("pf_open - Can't open %s\n", name);
         exit(0);
         }

      if (1 != fread(pfile->nextHeader, SIZE_SL_HEADER, 1, pfile->curFile))
         {
         printf("pf_open - Can't read header in %s\n", name);
         exit(0);
         }
      }
   }


/*
 *  delete a posfile in a posfile set
 */
void pf_remove(PosFILE *pfile)
   {
   char name[256];

   CreateTempFileName(pfile->level, pfile->entry, pfile->seqNo, name);
   if (0 != remove(name))
      {
      printf("pf_remove - Can't delete %s\n", name);
      printf("            continuing anyway\n");
      }
   }


/*
 * OpenPosFile()
 *   works in the same spirit as fopen, pass it necessary parameters
 *   and it creates a handle for you.  Bletches on errors instead of
 *   passing them back though.
 */
PosFILE * OpenPosFile(int level, int entry, int write, int remove)
   {
   PosFILE *tempPF;

   if (NULL == (tempPF = (PosFILE *)malloc(sizeof(PosFILE))))
      {
      printf("openPosFile - Can't malloc tempPF\n");
      exit(0);
      }
   memset (tempPF, 0, sizeof(PosFILE));
   tempPF->level = level;
   tempPF->entry = entry;
   tempPF->seqNo = 0;
   tempPF->write = write;
   tempPF->remove = remove;
   pf_open(tempPF);
   return tempPF;
   }

/*
 * ReadPosFile()
 *    reads in the next buffer of positions from inPF, optionally
 *    uncompressing the contents.
 *    returns
 *       1 if data fetched
 *       0 if reached end of data
 */
int ReadPosFile(PosFILE *inPF, SList *inlist, int uncompress)
   {
   unsigned int ucSize; /* uncompressed size */
   unsigned int cSize;  /* compressed size */
   unsigned char *compressed;
   unsigned char *uncompressed;
   unsigned char *endCompressed;
   unsigned char curEntry[256];

   memcpy(inlist, inPF->nextHeader, SIZE_SL_HEADER);
   if (!inlist->entries)
      return 0;

   if (inlist->entries == UINT_MAX)
      {
      fclose(inPF->curFile);
      if (inPF->remove)
         pf_remove(inPF);
      ++inPF->seqNo;
      pf_open(inPF);
      memcpy(inlist, inPF->nextHeader, SIZE_SL_HEADER);
      }

   if (!uncompress)
      {
      if (1 != fread(inlist->data, inlist->size + SIZE_SL_HEADER, 1, inPF->curFile))
         {
         printf("ReadPosFile - fread failed\n");
         exit(0);
         }
      memcpy(inPF->nextHeader, inlist->data + inlist->size, SIZE_SL_HEADER);
      }
   else
      {
      /* read slist into space where he can be decompressed in place */
      ucSize = SL_UncompressedSizeSlist(inlist);
      cSize = SL_SizeSlist(inlist);
      compressed = inlist->data + ucSize - cSize + 256;
      if (1 != fread(compressed, cSize, 1, inPF->curFile))
         {
         printf("ReadPosFile - fread failed (compressed)\n");
         exit(0);
         }

      /* do some inits */
      memset(curEntry, 0, bt_entrySize);
      endCompressed = (unsigned char *)(inlist) + ucSize + 256;
      uncompressed = inlist->data;

      /* now that we know where the next header is, move it before */
      /* anyone does anything to it */
      memcpy(inPF->nextHeader, endCompressed, SIZE_SL_HEADER);
      
      while (compressed < endCompressed)
         {
         memcpy(&curEntry[*compressed], &compressed[1], bt_entrySize - *compressed);
         compressed += bt_entrySize - *compressed + 1;

         memcpy(uncompressed, curEntry, bt_entrySize);
         uncompressed += bt_entrySize;
         }
      }
   return 1;
   }

/*
 * the following is the size at which a new PosFile gets created
 * (checks only whether the value is exceeded already so files
 * can be up to MAX_BYTES_TO_POSFILE + smallmem + 2 * header info
 */
#define MAX_BYTES_TO_POSFILE 1000000000
/*
 * write an slist out to a PosFile. The slist is assumed to
 * already be compressed.
 * returns number of entries written so far to outPF
 */
unsigned int WritePosFile(PosFILE *outPF, SList *outlist)
   {
   SList nullSlist;

   if (outPF->bytesWritten > MAX_BYTES_TO_POSFILE)
      {
      nullSlist.entries = UINT_MAX;
      nullSlist.size = 0;
      if (1 != fwrite(&nullSlist, SIZE_SL_HEADER, 1, outPF->curFile))
         {
         printf("WritePosFile - Can't write EOF trailer\n");
         exit(0);
         }
      fclose (outPF->curFile);
      outPF->bytesWritten = 0;
      ++outPF->seqNo;
      pf_open(outPF);
      }

   if (1 != fwrite(outlist, SL_SizeSlist(outlist), 1, outPF->curFile))
      {
      printf("WritePosFile - Can't write buffer to PosFile\n");
      exit(0);
      }
   outPF->bytesWritten += SL_SizeSlist(outlist);
   outPF->totalEntriesWritten += outlist->entries;
   return outPF->totalEntriesWritten;
   }

/*
 * If performing writes, writes a trailer, 
 * Closes the last of a set of PosFiles,
 * and frees the memory for the handle.
 */
void ClosePosFile(PosFILE *pf)
   {
   SList nullSlist;

   if (pf->write)
      {
      nullSlist.entries = 0;
      nullSlist.size = 0;
      if (1 != fwrite(&nullSlist, SIZE_SL_HEADER, 1, pf->curFile))
         {
         printf("ClosePosFile - Can't write EOF trailer\n");
         exit(0);
         }
      }
   fclose (pf->curFile);
   if (pf->remove)
      pf_remove(pf);

   free(pf);
   }

void RenamePosFileSet(int oldLevel, int oldEntry, int newLevel, int newEntry)
   {
   /*
    * We are going to cheat and assume that I can successfully complete
    * the necessary renames and keep renaming until something fails
    * To help ensure this, I'm going to delete
    * out anything with new name before hand
    */
   char oldName[256];
   char newName[256];
   int seqNo = 0;

   do
      {
      CreateTempFileName(oldLevel, oldEntry, seqNo, oldName);
      CreateTempFileName(newLevel, newEntry, seqNo, newName);
      remove(newName);
      ++seqNo;
      } while (0 == rename(oldName, newName));
   }

void RemovePosFileSet(int level, int entry)
   {
   /*
    * I'm cheating and assuming that a failed deletion means no file
    * and thus I've come to the end of the fileset
    */
   char name[256];
   int seqNo = 0;

   do
      {
      CreateTempFileName(level, entry, seqNo, name);
      ++seqNo;
      } while (0 == remove(name));
   }

void RemoveGeneration(int gen)
   {
   RemovePosFileSet(gen, -1);
   }

/*
 * Do what it says, merge both infile sets, removing duplicates and
 * output them to the outfile set.
 * returns number of entries written to out
 */
unsigned int MergeTempFiles(int inLevel1, int inEntry1,
                    int inLevel2, int inEntry2,
                    int outLevel, int outEntry)
   {
   PosFILE *infile1;
   PosFILE *infile2;
   PosFILE *outfile;

   /* if this changes, bigStorage check in readparm.c will need adjusted */
   SList *inlist1 = (SList *)(newPosList->data);
   SList *inlist2 = (SList *)(((unsigned char *)(inlist1)) + 
           smallmem + 512 + SIZE_SL_HEADER);

   SList *outlist = goodPosSL;

   int morePos1 = 1;
   int morePos2 = 1;

   unsigned char *inPtr1;
   unsigned int inPosNo1 = 0;

   unsigned char *inPtr2;
   unsigned int inPosNo2 = 0;

   unsigned char *outPtr = outlist->data;
   int outPosNo = 0;

   int a;
   unsigned int totalEntries = 0;
   int cmpVal;
   unsigned char baseEntry[256];


   infile1 = OpenPosFile(inLevel1, inEntry1, 0, 1);
   infile2 = OpenPosFile(inLevel2, inEntry2, 0, 1);
   outfile = OpenPosFile(outLevel, outEntry, 1, 0);
   memset (baseEntry, 0, bt_entrySize);

   while (1)
      {
      if (!inPosNo1)
         {
         morePos1 = ReadPosFile(infile1, inlist1, 1);
         if (morePos1)
            {
            inPtr1 = inlist1->data;
            inPosNo1 = inlist1->entries;
            }
         else
            {
            break;
            }
         }

      if (!inPosNo2)
         {
         morePos2 = ReadPosFile(infile2, inlist2, 1);
         if (morePos2)
            {
            inPtr2 = inlist2->data;
            inPosNo2 = inlist2->entries;
            }
         else
            {
            break;
            }
         }

      cmpVal = memcmp(inPtr1, inPtr2, bt_entrySize);
      if (cmpVal <= 0)
         {
         for (a = 0; baseEntry[a] == inPtr1[a]; ++a);
         memcpy(&baseEntry[a], &inPtr1[a], bt_entrySize - a);
         inPtr1 += bt_entrySize;
         --inPosNo1;
         if (!cmpVal) /* ie both equal */
            {
            inPtr2 += bt_entrySize;
            --inPosNo2;
            }
         }
      else
         {
         for (a = 0; baseEntry[a] == inPtr2[a]; ++a);
         memcpy(&baseEntry[a], &inPtr2[a], bt_entrySize - a);
         inPtr2 += bt_entrySize;
         --inPosNo2;
         }
      *(outPtr++) = a;
      memcpy(outPtr, &baseEntry[a], bt_entrySize - a);
      outPtr += (bt_entrySize - a);
      if (++outPosNo >= maxEntriesPerSl)
         {
         outlist->size = outPtr - outlist->data;
         outlist->entries = outPosNo;
         totalEntries = WritePosFile(outfile, outlist);
         outPtr = outlist->data;
         outPosNo = 0;
         memset(baseEntry, 0, bt_entrySize);
         }
      }
   /* once here, there is data sitting on at most one inlist/file */
   while (morePos1)
      {
      if (!inPosNo1)
         {
         morePos1 = ReadPosFile(infile1, inlist1, 1);
         if (morePos1)
            {
            inPtr1 = inlist1->data;
            inPosNo1 = inlist1->entries;
            }
         else
            {
            break;
            }
         }
      for (a = 0; baseEntry[a] == inPtr1[a]; ++a);
      memcpy(&baseEntry[a], &inPtr1[a], bt_entrySize - a);
      inPtr1 += bt_entrySize;
      --inPosNo1;
      *(outPtr++) = a;
      memcpy(outPtr, &baseEntry[a], bt_entrySize - a);
      outPtr += (bt_entrySize - a);
      if (++outPosNo >= maxEntriesPerSl)
         {
         outlist->size = outPtr - outlist->data;
         outlist->entries = outPosNo;
         totalEntries = WritePosFile(outfile, outlist);
         outPtr = outlist->data;
         outPosNo = 0;
         memset(baseEntry, 0, bt_entrySize);
         }
      }

   while (morePos2)
      {
      if (!inPosNo2)
         {
         morePos2 = ReadPosFile(infile2, inlist2, 1);
         if (morePos2)
            {
            inPtr2 = inlist2->data;
            inPosNo2 = inlist2->entries;
            }
         else
            {
            break;
            }
         }
      for (a = 0; baseEntry[a] == inPtr2[a]; ++a);
      memcpy(&baseEntry[a], &inPtr2[a], bt_entrySize - a);
      inPtr2 += bt_entrySize;
      --inPosNo2;
      *(outPtr++) = a;
      memcpy(outPtr, &baseEntry[a], bt_entrySize - a);
      outPtr += (bt_entrySize - a);
      if (++outPosNo >= maxEntriesPerSl)
         {
         outlist->size = outPtr - outlist->data;
         outlist->entries = outPosNo;
         totalEntries = WritePosFile(outfile, outlist);
         outPtr = outlist->data;
         outPosNo = 0;
         memset(baseEntry, 0, bt_entrySize);
         }
      }

   outlist->size = outPtr - outlist->data;
   outlist->entries = outPosNo;
   totalEntries = WritePosFile(outfile, outlist);

   ClosePosFile(infile1);
   ClosePosFile(infile2);
   ClosePosFile(outfile);
   return totalEntries;
   }

/*
 * write any position from in1 that isn't in in2 to out
 * largely just a clone of MergeTempFiles
 * returns number of entries written to out
 */
unsigned int DedupFile (int inLevel1, int inEntry1,
                int inLevel2, int inEntry2,
                int outLevel, int outEntry)
   {
   PosFILE *infile1;
   PosFILE *infile2;
   PosFILE *outfile;

   /* if this changes, bigStorage check in readparm.c will need adjusted */
   SList *inlist1 = (SList *)(newPosList->data);
   SList *inlist2 = (SList *)(((unsigned char *)(inlist1)) + 
           smallmem + 512 + SIZE_SL_HEADER);

   SList *outlist = goodPosSL;

   int morePos1 = 1;
   int morePos2 = 1;

   unsigned char *inPtr1;
   unsigned int inPosNo1 = 0;

   unsigned char *inPtr2;
   unsigned int inPosNo2 = 0;

   unsigned char *outPtr = outlist->data;
   int outPosNo = 0;

   int a;
   unsigned int totalEntries = 0;
   int cmpVal;
   int wroteSomething = 0;
   unsigned char baseEntry[256];


   infile1 = OpenPosFile(inLevel1, inEntry1, 0, 1);
   infile2 = OpenPosFile(inLevel2, inEntry2, 0, 0);
   outfile = OpenPosFile(outLevel, outEntry, 1, 0);
   memset (baseEntry, 0, bt_entrySize);

   while (1)
      {
      if (!inPosNo1)
         {
         morePos1 = ReadPosFile(infile1, inlist1, 1);
         if (morePos1)
            {
            inPtr1 = inlist1->data;
            inPosNo1 = inlist1->entries;
            }
         else
            {
            break;
            }
         }

      if (!inPosNo2)
         {
         morePos2 = ReadPosFile(infile2, inlist2, 1);
         if (morePos2)
            {
            inPtr2 = inlist2->data;
            inPosNo2 = inlist2->entries;
            }
         else
            {
            break;
            }
         }

      cmpVal = memcmp(inPtr1, inPtr2, bt_entrySize);

      if (cmpVal < 0)
         {
         for (a = 0; baseEntry[a] == inPtr1[a]; ++a);
         memcpy(&baseEntry[a], &inPtr1[a], bt_entrySize - a);
         inPtr1 += bt_entrySize;
         --inPosNo1;
         *(outPtr++) = a;
         memcpy(outPtr, &baseEntry[a], bt_entrySize - a);
         outPtr += (bt_entrySize - a);
         if (++outPosNo >= maxEntriesPerSl)
            {
            outlist->size = outPtr - outlist->data;
            outlist->entries = outPosNo;
            totalEntries = WritePosFile(outfile, outlist);
            outPtr = outlist->data;
            outPosNo = 0;
            memset(baseEntry, 0, bt_entrySize);
            wroteSomething = 1;
            }
         }
      else if (!cmpVal) /* ie both equal */
         {
         inPtr1 += bt_entrySize;
         --inPosNo1;
         inPtr2 += bt_entrySize;
         --inPosNo2;
         }
      else
         {
         inPtr2 += bt_entrySize;
         --inPosNo2;
         }
      }

   /* once here, there is data sitting on at most one inlist/file */
   /* if it's list1 then we want it */
   while (morePos1)
      {
      if (!inPosNo1)
         {
         morePos1 = ReadPosFile(infile1, inlist1, 1);
         if (morePos1)
            {
            inPtr1 = inlist1->data;
            inPosNo1 = inlist1->entries;
            }
         else
            {
            break;
            }
         }
      for (a = 0; baseEntry[a] == inPtr1[a]; ++a);
      memcpy(&baseEntry[a], &inPtr1[a], bt_entrySize - a);
      inPtr1 += bt_entrySize;
      --inPosNo1;
      *(outPtr++) = a;
      memcpy(outPtr, &baseEntry[a], bt_entrySize - a);
      outPtr += (bt_entrySize - a);
      if (++outPosNo >= maxEntriesPerSl)
         {
         outlist->size = outPtr - outlist->data;
         outlist->entries = outPosNo;
         totalEntries = WritePosFile(outfile, outlist);
         outPtr = outlist->data;
         outPosNo = 0;
         memset(baseEntry, 0, bt_entrySize);
         wroteSomething = 1;
         }
      }

   outlist->size = outPtr - outlist->data;
   outlist->entries = outPosNo;
   totalEntries = WritePosFile(outfile, outlist);

   ClosePosFile(infile1);
   ClosePosFile(infile2);
   ClosePosFile(outfile);
   /* in the very unlikely event that totalEntries is a multiple of 2^32 */
   /* we want to be able to continue on */
   if (!totalEntries && wroteSomething)
      return 1;
   return totalEntries;
   }


/*
 * Do what it says, merge infile set with a linked list removing
 * duplicates and output them to the outfile set.
 * returns number of entries written to out
 */
unsigned int MergeTempFileWithLinkedList(int inLevel1, int inEntry1,
                    BTree *inTree,
                    int outLevel, int outEntry)
   {
   PosFILE *infile1;
   PosFILE *outfile;

   /* if this changes, bigStorage check in readparm.c will need adjusted */
   SList *inlist1 = mergeListSL;

   SList *outlist = goodPosSL;

   int morePos1 = 1;
   int morePos2 = 1;

   unsigned char *inPtr1;
   unsigned int inPosNo1 = 0;

   BT_Node *inNode2 = inTree->nextNode;
   unsigned char *inPtr2 = inNode2->entry;

   unsigned char *outPtr = outlist->data;
   int outPosNo = 0;

   int a;
   unsigned int totalEntries = 0;
   int cmpVal;
   unsigned char baseEntry[256];


   infile1 = OpenPosFile(inLevel1, inEntry1, 0, 1);
   outfile = OpenPosFile(outLevel, outEntry, 1, 0);
   memset (baseEntry, 0, bt_entrySize);

   while (1)
      {
      if (!inPosNo1)
         {
         morePos1 = ReadPosFile(infile1, inlist1, 1);
         if (morePos1)
            {
            inPtr1 = inlist1->data;
            inPosNo1 = inlist1->entries;
            }
         else
            {
            break;
            }
         }

      if (!inNode2)
         {
         break;
         }

      cmpVal = memcmp(inPtr1, inPtr2, bt_entrySize);
      if (cmpVal <= 0)
         {
         for (a = 0; baseEntry[a] == inPtr1[a]; ++a);
         memcpy(&baseEntry[a], &inPtr1[a], bt_entrySize - a);
         inPtr1 += bt_entrySize;
         --inPosNo1;
         if (!cmpVal) /* ie both equal */
            {
            inNode2 = inNode2->gt_node;
            if (inNode2)
               inPtr2 = inNode2->entry;
            }
         }
      else
         {
         for (a = 0; baseEntry[a] == inPtr2[a]; ++a);
         memcpy(&baseEntry[a], &inPtr2[a], bt_entrySize - a);
         inNode2 = inNode2->gt_node;
         if (inNode2)
            inPtr2 = inNode2->entry;
         }
      *(outPtr++) = a;
      memcpy(outPtr, &baseEntry[a], bt_entrySize - a);
      outPtr += (bt_entrySize - a);
      if (++outPosNo >= maxEntriesPerSl)
         {
         outlist->size = outPtr - outlist->data;
         outlist->entries = outPosNo;
         totalEntries = WritePosFile(outfile, outlist);
         outPtr = outlist->data;
         outPosNo = 0;
         memset(baseEntry, 0, bt_entrySize);
         }
      }
   /* once here, there is data sitting on at most one inlist/file */
   while (morePos1)
      {
      if (!inPosNo1)
         {
         morePos1 = ReadPosFile(infile1, inlist1, 1);
         if (morePos1)
            {
            inPtr1 = inlist1->data;
            inPosNo1 = inlist1->entries;
            }
         else
            {
            break;
            }
         }
      for (a = 0; baseEntry[a] == inPtr1[a]; ++a);
      memcpy(&baseEntry[a], &inPtr1[a], bt_entrySize - a);
      inPtr1 += bt_entrySize;
      --inPosNo1;
      *(outPtr++) = a;
      memcpy(outPtr, &baseEntry[a], bt_entrySize - a);
      outPtr += (bt_entrySize - a);
      if (++outPosNo >= maxEntriesPerSl)
         {
         outlist->size = outPtr - outlist->data;
         outlist->entries = outPosNo;
         totalEntries = WritePosFile(outfile, outlist);
         outPtr = outlist->data;
         outPosNo = 0;
         memset(baseEntry, 0, bt_entrySize);
         }
      }

   while (inNode2)
      {
      for (a = 0; baseEntry[a] == inPtr2[a]; ++a);
      memcpy(&baseEntry[a], &inPtr2[a], bt_entrySize - a);
      inNode2 = inNode2->gt_node;
      if (inNode2)
         inPtr2 = inNode2->entry;
      *(outPtr++) = a;
      memcpy(outPtr, &baseEntry[a], bt_entrySize - a);
      outPtr += (bt_entrySize - a);
      if (++outPosNo >= maxEntriesPerSl)
         {
         outlist->size = outPtr - outlist->data;
         outlist->entries = outPosNo;
         totalEntries = WritePosFile(outfile, outlist);
         outPtr = outlist->data;
         outPosNo = 0;
         memset(baseEntry, 0, bt_entrySize);
         }
      }

   outlist->size = outPtr - outlist->data;
   outlist->entries = outPosNo;
   totalEntries = WritePosFile(outfile, outlist);

   ClosePosFile(infile1);
   ClosePosFile(outfile);
   return totalEntries;
   }


/*
 *  Find the first duplicate in 2 position file sets
 */
unsigned char * FindDuplicateEntryInFiles(int inLevel1, int inEntry1,
                    int inLevel2, int inEntry2)
   {
   PosFILE *infile1;
   PosFILE *infile2;

   /* if this changes, bigStorage check in readparm.c will need adjusted */
   SList *inlist1 = (SList *)(newPosList->data);
   SList *inlist2 = (SList *)(((unsigned char *)(inlist1)) + 
           smallmem + 512 + SIZE_SL_HEADER);

   int morePos1 = 1;
   int morePos2 = 1;

   unsigned char *inPtr1;
   unsigned int inPosNo1 = 0;

   unsigned char *inPtr2;
   unsigned int inPosNo2 = 0;

   int cmpVal;


   infile1 = OpenPosFile(inLevel1, inEntry1, 0, 0);
   infile2 = OpenPosFile(inLevel2, inEntry2, 0, 0);

   while (1)
      {
      if (!inPosNo1)
         {
         morePos1 = ReadPosFile(infile1, inlist1, 1);
         if (morePos1)
            {
            inPtr1 = inlist1->data;
            inPosNo1 = inlist1->entries;
            }
         else
            {
            break;
            }
         }

      if (!inPosNo2)
         {
         morePos2 = ReadPosFile(infile2, inlist2, 1);
         if (morePos2)
            {
            inPtr2 = inlist2->data;
            inPosNo2 = inlist2->entries;
            }
         else
            {
            break;
            }
         }

      cmpVal = memcmp(inPtr1, inPtr2, bt_entrySize);
      if (!cmpVal)
         {
         ClosePosFile(infile1);
         ClosePosFile(infile2);
         return inPtr1;
         }

      if (cmpVal < 0)
         {
         inPtr1 += bt_entrySize;
         --inPosNo1;
         }
      else
         {
         inPtr2 += bt_entrySize;
         --inPosNo2;
         }
      }
   /* once here, there is data sitting on only one (at most) inlist/file */
   /* close things and return a NULL */
   ClosePosFile(infile1);
   ClosePosFile(infile2);
   return NULL;
   }


/*
 * Find first duplicate between a pos file set and a linked list
 */
unsigned char * FindDuplicateInLinkedList(int inLevel1, int inEntry1,
                    BTree *inTree)
   {
   PosFILE *infile1;

   /* if this changes, bigStorage check in readparm.c will need adjusted */
   SList *inlist1 = mergeListSL;


   int morePos1 = 1;
   int morePos2 = 1;

   unsigned char *inPtr1;
   unsigned int inPosNo1 = 0;

   BT_Node *inNode2 = inTree->nextNode;
   unsigned char *inPtr2 = inNode2->entry;

   int cmpVal;

   infile1 = OpenPosFile(inLevel1, inEntry1, 0, 0);

   while (1)
      {
      if (!inPosNo1)
         {
         morePos1 = ReadPosFile(infile1, inlist1, 1);
         if (morePos1)
            {
            inPtr1 = inlist1->data;
            inPosNo1 = inlist1->entries;
            }
         else
            {
            break;
            }
         }

      if (!inNode2)
         {
         break;
         }

      cmpVal = memcmp(inPtr1, inPtr2, bt_entrySize);
      if (!cmpVal)
         {
         ClosePosFile(infile1);
         return inPtr2;
         }

      if (cmpVal <= 0)
         {
         inPtr1 += bt_entrySize;
         --inPosNo1;
         }
      else
         {
         inNode2 = inNode2->gt_node;
         if (inNode2)
            inPtr2 = inNode2->entry;
         }
      }
   /* once here, there is data sitting on at most one inlist/file */
   /* in other words there can't be any duplicates at this point */

   ClosePosFile(infile1);
   return NULL;
   }



void DoMerge(int startLevel)
   {
   int level = startLevel;

   while (tempFileLevelList[level] == 2)
      {
      lastEntriesWritten = MergeTempFiles(level, 0, level, 1, level+1, tempFileLevelList[level+1]++);
      tempFileLevelList[level] = 0;
      if (++level == MAX_LEVEL)
         {
         printf("DoMerge - Maximum level reached (how did you do that?)\n");
         exit(0);
         }
      }
   }

void DoFinalMerge(int curGen, int prevGen, int prevPrevGen)
   {
   int curlevel;
   int lastlevel = -1;
   int lastentry = 0;

   for (curlevel = 0; curlevel < MAX_LEVEL; ++curlevel)
      {
      if (tempFileLevelList[curlevel])
         {
         if (lastlevel != -1)
            {
            lastEntriesWritten = MergeTempFiles(lastlevel, lastentry, curlevel, 0, curlevel, 1);
            lastentry = 1;
            }
         lastlevel = curlevel;
         }
      }
   if (!prevGen && !prevPrevGen)
      {
      RenamePosFileSet(lastlevel, lastentry, curGen, -1);
      InitLevelList();
      return;
      }
   if (prevPrevGen)
      {
      lastEntriesWritten = DedupFile(lastlevel, lastentry, prevPrevGen, -1, lastlevel, lastentry+1);
      ++lastentry;
      }

   lastEntriesWritten = DedupFile(lastlevel, lastentry, prevGen, -1, curGen, -1);
   InitLevelList();
   }


void AddPln(Generation *gen, SList *list)
   {
   PosListNode *pln;

   if (NULL == (pln = (PosListNode *)malloc(sizeof(PosListNode))))
      {
      printf("AddPln - can't malloc new pln0\n");
      exit(0);
      }

   /* update link info in nextGen */
   if (!gen->lastPln)
      {
      gen->pln0 = pln;
      gen->lastPln = pln;
      }
   else
      {
      gen->lastPln->next = pln;
      gen->lastPln = pln;
      }

   gen->numBoards += SL_NumEntries(list);

   /* now fill in the newly created pln */
   pln->next = NULL;
   pln->pList = list;
   pln->file = NULL;
   StorePln(pln, 0);
   }


#if 0
/*
 *  GetNextBoard() relies on curGen being set properly
 *  for first call.  From then on relies on internal static vars
 */
int GetNextBoard(unsigned char *board)
   {
   static unsigned char *curIndex = NULL;
   static PosListNode *curPln = NULL;
   static int boardsLeftInPln = 0;
   
   if (!(boardsLeftInPln--))
      {
      if (!curPln)
         {
         curPln = curGen->pln0;
         }
      else
         {
         DropPln(curPln, 0);
         curPln = curPln->next;
         }

      if (!curPln)
         {
         curIndex = NULL;
         /* curPln = NULL;*/ /* already set */
         boardsLeftInPln = 0;
         return 0;
         }

      GetPln(curPln, getNextBoardSL, 1);

      boardsLeftInPln = SL_NumEntries(curPln->pList) - 1;
      curIndex = curPln->pList->data;
      }
   else
      {
      curIndex += bt_entrySize;
      }
   UncompressBoard(curIndex, board);
   return 1;
   }


#endif
/*
 *  GetNextBoard() relies on curGen being set properly
 *  for first call.  From then on relies on internal static vars
 */

/*
 *  Because I'm an idiot I was pulling from a sorted list,
 *  making a minor adjustment (a single move) and then adding
 *  to a binary tree.  This is almost the worst possible scenario
 *  with a binary tree (a tree with 10,000 entries and a depth of
 *  a thousand is absolutely attrocious yet was what I was getting)
 *  This new version of GetNextBoard() will attempt to read the
 *  position list in an ideally out of order method in an attempt
 *  to make a more shapely tree.
 */
   PosListNode *gnb_curPln = NULL;
   PosFILE *gnb_infile = NULL;
   int gnb_boardsLeft = 0; /* number of boards left in the SL */

   unsigned char *gnb_baseEntry; /* pointer to the first entry (or zero'th) */
   int gnb_curInc;     /* current increment */
   int gnb_curEntry;   /* current entry number */
   int gnb_numEntries; /* number of entries in this pln */


char *GetNextIndex()
   {
   unsigned char *curIndex;

   if (gnb_curEntry >= gnb_numEntries)
      {
      gnb_curInc = gnb_curInc / 2;
      gnb_curEntry = (gnb_curInc / 2) - 1;
      if (gnb_curEntry < 0)
         {
         printf("GetNextBoard - gnb_curEntry = %d, bad programmer, bad\n", gnb_curEntry);
         exit(0);
         }
      }

   curIndex = gnb_baseEntry + (gnb_curEntry * bt_entrySize);
   gnb_curEntry += gnb_curInc;
   return curIndex;
   }

int GetNextBoard(unsigned char *board)
   {
   if (!(gnb_boardsLeft--))
      {
      if (bigStorage)
         {
         if (!gnb_infile)
            {
            gnb_infile = OpenPosFile(
                  curMoveNum - (concurrent ? 2 : 1),  /* move num to open */
                  -1,  /* signifies prev arg as a move num */
                  0,   /* for read */
                  0);  /* don't delete when read */
            }
         if (!ReadPosFile(gnb_infile, getNextBoardSL, 1))
            {
            ClosePosFile(gnb_infile);
            gnb_infile = NULL;
            gnb_boardsLeft = 0;
            return 0;
            }
         gnb_boardsLeft = SL_NumEntries(getNextBoardSL) - 1;
         gnb_baseEntry = getNextBoardSL->data;

         gnb_numEntries = SL_NumEntries(getNextBoardSL);
         }
      else
         {
         if (!gnb_curPln)
            {
            gnb_curPln = curGen->pln0;
            }
         else
            {
            DropPln(gnb_curPln, 0);
            gnb_curPln = gnb_curPln->next;
            }

         if (!gnb_curPln)
            {
            /* gnb_curIndex = NULL;*/ /* doesn't exist anymore */
            /* gnb_curPln = NULL;*/ /* already set */
            gnb_boardsLeft = 0;
            return 0;
            }

         GetPln(gnb_curPln, getNextBoardSL, 1);
         gnb_boardsLeft = SL_NumEntries(gnb_curPln->pList) - 1;
         gnb_baseEntry = gnb_curPln->pList->data;

         gnb_numEntries = SL_NumEntries(gnb_curPln->pList);
         }

      for (gnb_curInc = 2; gnb_curInc <= gnb_numEntries; gnb_curInc *= 2);
      gnb_curEntry = (gnb_curInc / 2) - 1;
      }


   UncompressBoard(GetNextIndex(), board);
   return 1;
   }

/*
 *  This copies everything left in the GNB queue to the
 *  (currently empty) newPosList and then copies them
 *  back sequentially so that they can be reordered again.
 */
/*
 *  I can get away with some of the things I do in here
 *  because nobody can possibly be using gnb_curPln other
 *  than gnb at this time.
 */

void ReorgGNBQueue()
   {
   int a;
   unsigned char *curLoc = newPosList->data;

   if (!gnb_boardsLeft)
      return;

/*   printf("in full reorg\n"); */

   if (BT_NumEntries(newPosList))
      {
      printf("ReorgGNBQueue() - Entries still in newPosList - bad programmer\n");
      exit(0);
      }

   for (a = 0; a < gnb_boardsLeft; ++a)
      {
      memcpy(curLoc, GetNextIndex(), bt_entrySize);
      curLoc += bt_entrySize;
      }

   /* this could really be anywhere but looks better here */
   if (!bigStorage)
      {
      DropPln(gnb_curPln, 0);  /* this could have already been done before */
                               /* but DropPln doesn't care */
      }

   memcpy(getNextBoardSL->data, newPosList->data, gnb_boardsLeft * bt_entrySize);

   gnb_baseEntry = getNextBoardSL->data;
   gnb_numEntries = gnb_boardsLeft;
   for (gnb_curInc = 2; gnb_curInc <= gnb_numEntries; gnb_curInc *= 2);
   gnb_curEntry = (gnb_curInc / 2) - 1;
   }


   
void StorePln(PosListNode *pln, int freePlist)
   {
   if (pln->file)
      {
      printf("pln has already been stored\n");
      exit(0);
      }
   if (fseek(workFile[writeNum % numCurWorkFiles + minWorkFile], 0, SEEK_END))
      {
      printf("StorePln - fseek failed\n");
      exit(0);
      }

   /*
    *  curMove is written in a place where noone will see it unless
    *  they are looking for it.
    */
   if (1 != fwrite(&curMove, sizeof(int), 1, workFile[writeNum % numCurWorkFiles + minWorkFile]))
      {
      printf("StorePln - unable to write moveNum\n");
      exit(0);
      }

   if (-1 == (pln->offset = ftell(workFile[writeNum % numCurWorkFiles + minWorkFile])))
      {
      printf("StorePln - ftell failed\n");
      exit(0);
      }

   pln->pListSize = SL_SizeSlist(pln->pList);
   pln->uncompressedSize = SL_UncompressedSizeSlist(pln->pList);
   if (1 != fwrite(pln->pList, pln->pListSize, 1, workFile[writeNum % numCurWorkFiles + minWorkFile]))
      {
      printf("StorePln - unable to write pln\n");
      exit(0);
      }
   pln->file = workFile[writeNum % numCurWorkFiles + minWorkFile];
   ++writeNum;
   if (freePlist)
      SL_Free(pln->pList);
   pln->pList = NULL;
   }

void GetPln(PosListNode *pln, SList *slptr, int decompress)
   {
   unsigned char *compressed;
   unsigned char *endCompressed;
   unsigned char *uncompressed;
   unsigned char curEntry[256];

   if (!pln->file)
      {
      printf("GetPln - pln has not been saved\n");
      exit(0);
      }
   if (fseek(pln->file, pln->offset, SEEK_SET))
      {
      printf("GetPln - fseek failed\n");
      exit(0);
      }

   pln->pList = slptr;
   
   if (!decompress)
      {
      if (1 != fread(pln->pList, pln->pListSize, 1, pln->file))
         {
         printf("GetPln - fread failed\n");
         exit(0);
         }
      }
   else
      {
      /* read slist into space where he can be decompressed in place */
      compressed = (unsigned char *)(pln->pList) + pln->uncompressedSize - pln->pListSize + 256;
      if (1 != fread(compressed, pln->pListSize, 1, pln->file))
         {
         printf("GetPln - fread failed (decompress)");
         exit(0);
         }

      /* move the sl header into place */
      memcpy(pln->pList, compressed, SIZE_SL_HEADER);
      uncompressed = pln->pList->data;
      compressed += SIZE_SL_HEADER;

      memset(curEntry, 0, bt_entrySize);
      endCompressed = (unsigned char *)(pln->pList) + pln->uncompressedSize + 256;
      while (compressed < endCompressed)
         {
         memcpy(&curEntry[*compressed], &compressed[1], bt_entrySize - *compressed);
         compressed += bt_entrySize - *compressed + 1;

         memcpy(uncompressed, curEntry, bt_entrySize);
         uncompressed += bt_entrySize;
         }
      }
   }

void DropPln(PosListNode *pln, int freeSlist)
   {
   if (freeSlist)
      SL_Free(pln->pList);
   pln->pList = NULL;
   }
   

void PrintBoard(unsigned char *board)
   {
   int x;
   int y;
   int pieceNum;

   for (y = 0; y < ysize; ++y)
      {
      for (x = 0; x < xsize; ++x)
         {
         pieceNum = board[x + y * xsize];
         switch(pieceNum)
            {
            case WALL_CHAR:
               printf("# ");
               break;
            case SPACE_CHAR:
               printf("  ");
               break;
            default:
               printf("%c ", PieceNum2Char(pieceNum));
            }
         }
      printf("\n");
      }
   printf("\n");
   }

char PieceNum2Char(int pn)
   {
   if (piece[pn].label)
      {
      return piece[pn].label;
      }

   if (useLetters)
      {
      if (pn < 26)
         return pn + 'A';
      else if (pn < 52)
         return pn - 26 + 'a';
      else if (pieceNum < 62)
         return pn - 52 + '0';
      else
         return '^';
      }

   /* default - use numbers */
   if (pn < 10)
      return pn + '0';
   if (pn < 36)
      return pn - 10 + 'A';
   if (pn < 62)
      return pn - 36 + 'a';
   else
      return '^';
   }
   

void InitBaseBoard()
   {
   int x;
   int y;
   int a;

   memset(baseBoard, SPACE_CHAR, LARGEST_BOARD_SIZE);

   for (y = 0; y < ysize; ++y)
      {
      baseBoard[y * xsize] = WALL_CHAR;
      baseBoard[(y + 1) * xsize - 1] = WALL_CHAR;
      }
   for (x = 0; x < xsize; ++x)
      {
      baseBoard[x] = WALL_CHAR;
      baseBoard[x + xsize * (ysize - 1)] = WALL_CHAR;
      }
   for (a = 0; a < wallList.numWall; ++a)
      {
      baseBoard[wallList.wallX[a] + 1 + xsize * (wallList.wallY[a] + 1)]
               = WALL_CHAR;
      }
   }


void InitBoard(unsigned char *board)
   {
   int a, b;
   int startOffset;

	memcpy(board, baseBoard, totSize);
	for (a = 0; a < numPiece; ++a)
		{
		startOffset = piece[a].startX + piece[a].startY * xsize + xsize + 1;
      piece[a].curLoc = startOffset;
		for (b = 0; b < piece[a].numBloc; ++b)
			board[startOffset + piece[a].xyoffset[b]] = a;
		}
	}


void InitPieces()
	{
	int a, b, c;
   int match;
   int dir;
   int countTo, countFrom;

   DIR[MOVE_RIGHT] = 1;
   DIR[MOVE_LEFT] = -1;
   DIR[MOVE_DOWN] = xsize;
   DIR[MOVE_UP] = -xsize;

	for (a = 0; a < numPiece; ++a)
      {
		for (b = 0; b < piece[a].numBloc; ++b)
			piece[a].xyoffset[b] = piece[a].xbloc[b] + piece[a].ybloc[b] * xsize;

      for (dir = 0; dir < 4; ++dir)
         {
         countTo = 0;
         countFrom = 0;
         for (b = 0; b < piece[a].numBloc; ++b)
            {
            match = 0;
            for (c = 0; c < piece[a].numBloc; ++c)
               {
               if (piece[a].xyoffset[b] + DIR[dir] == piece[a].xyoffset[c])
                  {
                  match = 1;
                  break;
                  }
               }
            if (!match)
               piece[a].moveTo[dir][countTo++] = piece[a].xyoffset[b] + DIR[dir];

            match = 0;
            for (c = 0; c < piece[a].numBloc; ++c)
               {
               if (piece[a].xyoffset[b] == piece[a].xyoffset[c] + DIR[dir])
                  {
                  match = 1;
                  break;
                  }
               }
            if (!match)
               piece[a].moveFrom[dir][countFrom++] = piece[a].xyoffset[b];
            }
         if (countTo != countFrom)
            {
            printf("InitPieces - Sanity check FAILED\n");
            exit(1);
            }
         piece[a].moveBlock[dir] = countTo;
         }
      }
	}


void CompressBoard(unsigned char *compressed, unsigned char *board)
	{
	unsigned char *curLoc;
	unsigned char placed[256];
	unsigned char uncompressed[256];
	unsigned char *curByte = uncompressed;
   unsigned char *curUncompressed = uncompressed;
	unsigned char *curCompressed = compressed;
   int curBit;

	memset(placed, 0, numPiece);

#if 1
/*   memset(compressed, 0, compressedPuzSize); 
*/   *compressed = 0;

	for (curLoc = &board[startLoc]; curLoc < &board[endLoc]; ++curLoc)
		{
		if (*curLoc == WALL_CHAR)
			continue;
		else if (*curLoc == SPACE_CHAR)
			{
			*(curByte++) = 0;
			}
		else
			{
			if (!placed[*curLoc])
				{
				placed[*curLoc] = 1;
				*(curByte++) = piece[*curLoc].pieceType;
				}
			}
		}

   curBit = 0;
	for (; curUncompressed < curByte; ++curUncompressed)
		{
      *curCompressed |= (*curUncompressed << curBit);
      curBit += bitsPerType;
      if (curBit > 7)
         {
         ++curCompressed;
         curBit -= 8;
         if (curBit)
            *curCompressed = (*curUncompressed >> (bitsPerType - curBit));
         else
            *curCompressed = 0;
         }
      }

#else

   *curCompressed = 0;
   curBit = 0;

   for (curLoc = &board[startLoc]; curLoc < &board[endLoc]; ++curLoc)
		{
		if (*curLoc == WALL_CHAR)
			continue;
		else if (*curLoc == SPACE_CHAR)
			{
         curBit += bitsPerType;
         if (curBit > 7)
            {
            *(++curCompressed) = 0;
            curBit -= 8;
            }
			}
		else
			{
			if (!placed[*curLoc])
				{
				placed[*curLoc] = 1;
            *curCompressed |= (unsigned char)(piece[*curLoc].pieceType << curBit);
            curBit += bitsPerType;
            if (curBit > 7)
               {
               ++curCompressed;
               curBit -= 8;
               if (curBit)
                  *curCompressed = (unsigned char)((piece[*curLoc].pieceType) >> (bitsPerType - curBit));
               else
                  *curCompressed = 0;
               }
				}
			}
		}
#endif
   }


void UncompressBoard(unsigned char *compressed, unsigned char *board)
	{
	unsigned char *curLoc;
	unsigned char placed[256];
	unsigned char unCompressed[256];
	int curByte = 0;
	int a, b;
#if 0
   int curCompressed = 0;
	int ucmask;
	int cmask;
#else
   int curBit;
   unsigned char *curCompressed;
   unsigned char *curUncompressed;
#endif

#if 0
	memset(unCompressed, 0, numPiece + numSpace);
	cmask = 1;
	for (a = 0; a < numPiece + numSpace; ++a)
		{
		ucmask = 1;
		for (b = 0; b < bitsPerType; ++b)
			{
			if (compressed[curCompressed] & cmask)
				unCompressed[a] |= ucmask;
			cmask <<= 1;
			ucmask <<= 1;
			if (cmask > 255)
				{
				cmask = 1;
				++curCompressed;
				}
			}
		}
#else
   curBit = 0;
   curCompressed = compressed;
   for (curUncompressed = unCompressed;
         curUncompressed < &unCompressed[numPiece + numSpace];
         ++curUncompressed)
      {
      *curUncompressed = *curCompressed >> curBit;
      curBit += bitsPerType;
      if (curBit > 7)
         {
         curBit -= 8;
         ++curCompressed;
         if (curBit)
            *curUncompressed |= *curCompressed << (bitsPerType - curBit);
         }
      *curUncompressed &= uncompressMask;
      }
#endif



	memcpy(board, baseBoard, totSize);
	memset(placed, 0, numPiece);

	for (curLoc = &board[startLoc]; curLoc < &board[endLoc]; ++curLoc)
		{
		if (*curLoc != SPACE_CHAR)  /* ie this space has already been placed */
			continue;

		if (!unCompressed[curByte]) /* ie this space should be open */
			{
			++curByte;
			continue;
			}

		for (a = 0; a < numPiece; ++a)
			{
			if (!placed[a] && piece[a].pieceType == unCompressed[curByte])
				{
            piece[a].curLoc = curLoc - board;
				for (b = 0; b < piece[a].numBloc; ++b)
					curLoc[piece[a].xyoffset[b]] = a;
				placed[a] = 1;
            ++curByte;
				break;
				}
			}

		if (a == numPiece) /* ie we couldn't place this piece for some reason */
			{
			fprintf(stderr, "Can't place piece of type %d\n", unCompressed[curByte]);
			exit(0);
			}
		}
	}


int CheckIfWin(unsigned char *board)
   {
   WinCond *curCond = &winList.winCond[0];
   WinCond *compCond = &winList.winCond[winList.numWinCond];
   int a;

   for ( ; curCond < compCond; ++curCond)
      {
      if (!curCond->pieceType)
         if (board[curCond->posXY] != SPACE_CHAR)
            return 0;
         else
            continue;
      for (a = 0; a < numPiece; ++a)
         {
         if (piece[a].pieceType == curCond->pieceType)
            if (piece[a].curLoc == curCond->posXY)
               break;
         }
      if (a < numPiece)
         continue;
      return 0;
      }
   return 1;
   }

int Distance()
   {
   WinCond *curCond = &winList.winCond[0];
   WinCond *compCond = &winList.winCond[winList.numWinCond];
   int a;
   int distance = 0;
   int pDistance;
   int xDist, tempDist;
   int xPos, yPos;

   for (; curCond < compCond; ++ curCond)
      {
      if (!curCond->pieceType) /* ie space */
         continue;

      pDistance = 10000000; /* absurdly high distance */
      for (a = 0; a < numPiece; ++a)
         {
         if (piece[a].pieceType == curCond->pieceType)
            {
            xPos = piece[a].curLoc % xsize - 1;
            if (!piece[a].moveX)
               if (xPos != curCond->posX)
                  continue;
            xDist = curCond->posX - xPos;
#if 0
            if (xDist < 0)
               xDist = -xDist;
#else
            xDist = xDist * xDist * piece[a].numBloc;
#endif
/* fprintf(stderr,"%d\n", piece[a].numBloc); */

            yPos = piece[a].curLoc / xsize - 1;
            if (!piece[a].moveY)
               if (yPos != curCond->posY)
                  continue;
            tempDist = curCond->posY - yPos;
#if 0
            if (tempDist < 0)
               tempDist = -tempDist;
#else
            tempDist = tempDist * tempDist* piece[a].numBloc;
#endif
            tempDist += xDist;
            if (tempDist < pDistance)
               pDistance = tempDist;
            }
         }
      distance += pDistance;
      }
   if (distance > 100000)
      printf("distance %d\n", distance);
   return distance;
   }

/*
 * This is a concatenation of uncompressboard and distance
 * except that the structure 'piece' is not modified
 * (and the board is local)
 */

int CDistance(unsigned char *compressed)
	{
	unsigned char *curLoc;
	unsigned char placed[256];
	unsigned char unCompressed[256];
   unsigned char pieceCurLoc[256];
	int curByte = 0;
	int a, b;
#if 0
	int curCompressed = 0;
	int ucmask;
	int cmask;
#else
   int curBit;
   unsigned char *curCompressed;
   unsigned char *curUncompressed;
#endif
   unsigned char board[LARGEST_BOARD_SIZE];

   WinCond *curCond = &winList.winCond[0];
   WinCond *compCond = &winList.winCond[winList.numWinCond];
   int distance = 0;
   int pDistance;
   int xPos, yPos;
   int xDist, tempDist;


#if 0
	memset(unCompressed, 0, numPiece + numSpace);

	cmask = 1;
	for (a = 0; a < numPiece + numSpace; ++a)
		{
		ucmask = 1;
		for (b = 0; b < bitsPerType; ++b)
			{
			if (compressed[curCompressed] & cmask)
				unCompressed[a] |= ucmask;
			cmask <<= 1;
			ucmask <<= 1;
			if (cmask > 255)
				{
				cmask = 1;
				++curCompressed;
				}
			}
		}
#else
   curBit = 0;
   curCompressed = compressed;
   for (curUncompressed = unCompressed;
         curUncompressed < &unCompressed[numPiece + numSpace];
         ++curUncompressed)
      {
      *curUncompressed = *curCompressed >> curBit;
      curBit += bitsPerType;
      if (curBit > 7)
         {
         curBit -= 8;
         ++curCompressed;
         if (curBit)
            *curUncompressed |= *curCompressed << (bitsPerType - curBit);
         }
      *curUncompressed &= uncompressMask;
      }
#endif

	memcpy(board, baseBoard, totSize);
	memset(placed, 0, numPiece);

	for (curLoc = &board[startLoc]; curLoc < &board[endLoc]; ++curLoc)
		{
		if (*curLoc != SPACE_CHAR)  /* ie this space has already been placed */
			continue;

		if (!unCompressed[curByte]) /* ie this space should be open */
			{
			++curByte;
			continue;
			}

		for (a = 0; a < numPiece; ++a)
			{
			if (!placed[a] && piece[a].pieceType == unCompressed[curByte])
				{
            pieceCurLoc[a] = curLoc - board;
				for (b = 0; b < piece[a].numBloc; ++b)
					curLoc[piece[a].xyoffset[b]] = a;
				placed[a] = 1;
            ++curByte;
				break;
				}
			}

		if (a == numPiece) /* ie we couldn't place this piece for some reason */
			{
			fprintf(stderr, "Can't place piece of type %d\n", unCompressed[curByte]);
			exit(0);
			}
		}

   for (; curCond < compCond; ++ curCond)
      {
      if (!curCond->pieceType) /* ie space */
         continue;

      pDistance = 10000000; /* absurdly high distance */
      for (a = 0; a < numPiece; ++a)
         {
         if (piece[a].pieceType == curCond->pieceType)
            {
            xPos = pieceCurLoc[a] % xsize - 1;
            if (!piece[a].moveX)
               if (xPos != curCond->posX)
                  continue;
            xDist = curCond->posX - xPos;
#if 0
            if (xDist < 0)
               xDist = -xDist;
#else
            xDist = xDist * xDist * piece[a].numBloc;
#endif
/* fprintf(stderr, "%d\n", piece[a].numBloc); */
            yPos = pieceCurLoc[a] / xsize - 1;
            if (!piece[a].moveY)
               if (yPos != curCond->posY)
                  continue;
            tempDist = curCond->posY - yPos;
#if 0
            if (tempDist < 0)
               tempDist = -tempDist;
#else
            tempDist = tempDist * tempDist * piece[a].numBloc;
#endif

            tempDist += xDist;
            if (tempDist < pDistance)
               pDistance = tempDist;
            }
         }
      if (pDistance > 100000)
         printf("couldn't match piece type %d\n", curCond->pieceType);
      distance += pDistance;
      }
   return distance;
	}


