/*
 *  show_win.c
 *
 *  This is merely included in slide.c so that it can have
 *  easy access to globals etc.
 *  copyright Jim Leonard 1999
 */

void ResetPrevLoc();
void FindDif(int *movedPiece, int *movedUp, int *movedRight);

unsigned char *FindBoardInGen(Generation *gen)
   {
   PosListNode *curPln;
   int fetched = 0;
   unsigned char *endLNode;
   BT_Node *curBNode;
   unsigned char *curLNode;
   int cmpval;

   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
          */
         if (fetched)
            {
            DropPln(curPln, 0);
            fetched = 0;
            }
         return curBNode->entry;
         }

      if (fetched)
         {
         DropPln(curPln, 0);
         fetched = 0;
         }
      }
   return NULL;
   }

   

void ShowWin()
   {
   unsigned char cString[256];
   unsigned char *cSPtr;
   Generation *gen;
   int genNum;
   unsigned char *winSeq;
   unsigned char *curSeq;
   int moveNum;
   int movedUp;
   int movedRight;
   int movedPiece;

   printf("***FOUND WIN ***\n");

   if (winOnly)
      {
      PrintBoard(workBoard);
      printf("Finished in %d seconds\n", time(NULL) - startTime);
      exit(0);
      }
   /*
    * goofy hack so that we aren't looking for a win when using
    * calls such as ProcessBoard()
    */
   concurrent = 1;
   if (NULL == (winSeq = (unsigned char *) malloc((curMove + 1) * bt_entrySize)))
      {
      printf("unable to allocate memory to show win sequence\n");
      exit(0);
      }

   curSeq = winSeq;
   CompressBoard(cString, workBoard);
   memcpy(curSeq, cString, bt_entrySize);
   UncompressBoard(cString, workBoard);

   if (bigStorage)
      genNum = curMoveNum - 1;
   else
      gen = curGen;
   
   while(1)
      {
      if (bigStorage)
         {
         if (genNum <= 0)
            break;
         }
      else
         {
         if (!gen)
            break;
         }

      curSeq += bt_entrySize;
      BT_Reset(newPosList);
      ProcessBoard();
      BT_CvtToLL(newPosList);
      if (bigStorage)
         {
         if (NULL == (cSPtr = FindDuplicateInLinkedList(genNum, -1, newPosList)))
            {
            printf("Can't find board in gen (bigstorage)\n");
            exit(0);
            }
         }
      else
         {
         if (NULL == (cSPtr = FindBoardInGen(gen)))
            {
            printf("Can't find board in gen\n");
            exit(0);
            }
         }
      memcpy(curSeq, cSPtr, bt_entrySize);
      UncompressBoard(curSeq, workBoard);
      if (bigStorage)
         {
         --genNum;
         }
      else
         {
         gen = gen->prev;
         }
      }
   
   moveNum = 0;
   for ( ; curSeq >= winSeq; curSeq -= bt_entrySize)
      {
      UncompressBoard(curSeq, workBoard);
      RenumberPieces(workBoard);
      FindDif(&movedPiece, &movedUp, &movedRight);
      ResetPrevLoc();
      if (moveNum++)
         {
         printf("move %d: piece %c", moveNum - 1, PieceNum2Char(movedPiece));
         if (movedUp > 0)
            printf(" up %d", movedUp);
         if (movedUp < 0)
            printf(" down %d", -movedUp);
         if (movedRight > 0)
            printf(" right %d", movedRight);
         if (movedRight < 0)
            printf(" left %d", -movedRight);
         printf("\n");
         if (!noGraph)
            PrintBoard(workBoard);
         }
      else
         {
         printf("start position\n");
         PrintBoard(workBoard);
         }
      }

   printf("Finished in %d seconds\n", time(NULL) - startTime);
   exit(0);
   }


void ConcurrentShowWin(unsigned char *cPtr)
   {
   unsigned char *cSPtr;
   Generation *gen;
   Generation *fGen;
   Generation *rGen;
   int genNum;
   int fGenNum;
   int rGenNum;
   unsigned char *winSeq1;
   unsigned char *curSeq1;
   unsigned char *winSeq2;
   unsigned char *curSeq2;
   int moveNum;
   int movedUp;
   int movedRight;
   int movedPiece;

   printf("***FOUND WIN ***\n");
   if (winOnly)
      {
      PrintBoard(workBoard);
      printf("Finished in %d seconds\n", time(NULL) - startTime);
      exit(0);
      }

   if (NULL == (winSeq1 = (unsigned char *) malloc(curMove * bt_entrySize)))
      {
      printf("unable to allocate memory to show win sequence\n");
      exit(0);
      }
   if (NULL == (winSeq2 = (unsigned char *) malloc(curMove * bt_entrySize)))
      {
      printf("unable to allocate memory to show win sequence\n");
      exit(0);
      }


   if (bigStorage)
      {
      if (processForward)
         {
         fGenNum = curMoveNum - 2;
         rGenNum = curMoveNum - 3;
         }
      else
         {
         fGenNum = curMoveNum - 3;
         rGenNum = curMoveNum - 2;
         }
      genNum = fGenNum;
      }
   else
      {
      if (processForward)
         {
         fGen = curGen;
         rGen = rPrevGen;
         }
      else
         {
         fGen = fPrevGen;
         rGen = curGen;
         }
      gen = fGen;
      }

   curSeq1 = winSeq1;
   memcpy(curSeq1, cPtr, bt_entrySize);
   UncompressBoard(curSeq1, workBoard);

   while(1)
      {
      if (bigStorage)
         {
         if (genNum <= 0)
            break;
         }
      else
         {
         if (!gen)
            break;
         }

      curSeq1 += bt_entrySize;
      BT_Reset(newPosList);
      ProcessBoard(workBoard);
      BT_CvtToLL(newPosList);
      if (bigStorage)
         {
         if (NULL == (cSPtr = FindDuplicateInLinkedList(genNum, -1, newPosList)))
            {
            printf("Can't find board in gen (bigstorage)\n");
            exit(0);
            }
         }
      else
         {
         if (NULL == (cSPtr = FindBoardInGen(gen)))
            {
            printf("Can't find board in gen\n");
            exit(0);
            }
         }
      memcpy(curSeq1, cSPtr, bt_entrySize);
      UncompressBoard(curSeq1, workBoard);
      if (bigStorage)
         genNum -= 2;
      else
         gen = gen->prev;
      }
   
   curSeq2 = winSeq2;
   memcpy(curSeq2, winSeq1, bt_entrySize);
   UncompressBoard(curSeq2, workBoard);


   if (bigStorage)
      genNum = rGenNum;
   else
      gen = rGen;
   while (1)
      {
      if (bigStorage)
         {
         if (genNum <= 0)
            break;
         }
      else
         {
         if (!gen)
            break;
         }

      curSeq2 += bt_entrySize;
      BT_Reset(newPosList);
      ProcessBoard(workBoard);
      BT_CvtToLL(newPosList);
      if (bigStorage)
         {
         if (NULL == (cSPtr = FindDuplicateInLinkedList(genNum, -1, newPosList)))
            {
            printf("Can't find board in gen (bigstorage)\n");
            exit(0);
            }
         }
      else
         {
         if (NULL == (cSPtr = FindBoardInGen(gen)))
            {
            printf("Can't find board in gen\n");
            exit(0);
            }
         }
      memcpy(curSeq2, cSPtr, bt_entrySize);
      UncompressBoard(curSeq2, workBoard);
      if (bigStorage)
         genNum -= 2;
      else
         gen = gen->prev;
      }

   
   moveNum = 0;
   for ( ; curSeq1 >= winSeq1; curSeq1 -= bt_entrySize)
      {
      UncompressBoard(curSeq1, workBoard);
      RenumberPieces(workBoard);
      FindDif(&movedPiece, &movedUp, &movedRight);
      ResetPrevLoc();
      if (moveNum++)
         {
         printf("move %d: piece %c", moveNum - 1, PieceNum2Char(movedPiece));
         if (movedUp > 0)
            printf(" up %d", movedUp);
         if (movedUp < 0)
            printf(" down %d", -movedUp);
         if (movedRight > 0)
            printf(" right %d", movedRight);
         if (movedRight < 0)
            printf(" left %d", -movedRight);
         printf("\n");
         if (!noGraph)
            PrintBoard(workBoard);
         }
      else
         {
         printf("start position\n");
         PrintBoard(workBoard);
         }
      }

   for (curSeq1 = winSeq2 + bt_entrySize; curSeq1 <= curSeq2; curSeq1 += bt_entrySize)
      {
      UncompressBoard(curSeq1, workBoard);
      RenumberPieces(workBoard);
      FindDif(&movedPiece, &movedUp, &movedRight);
      ResetPrevLoc();
      if (moveNum++)
         {
         printf("move %d: piece %c", moveNum - 1, PieceNum2Char(movedPiece));
         if (movedUp > 0)
            printf(" up %d", movedUp);
         if (movedUp < 0)
            printf(" down %d", -movedUp);
         if (movedRight > 0)
            printf(" right %d", movedRight);
         if (movedRight < 0)
            printf(" left %d", -movedRight);
         printf("\n");
         if (!noGraph)
            PrintBoard(workBoard);
         }
      else
         {
         printf("start position\n");
         PrintBoard(workBoard);
         }
      }

   printf("Finished in %d seconds\n", time(NULL) - startTime);
   exit(0);
   }


int prevLoc[MAX_PIECE];


/*
 * Renumber the pieces so that if a piece is still in the
 * same position the last time this function was called it
 * will still have the same label.
 */
void RenumberPieces(char *board)
   {
   static int firstTime = 1;
   int a, b, c;

   if (firstTime)
      {
      for (a = 0; a < numPiece; ++a)
         prevLoc[a] = piece[a].curLoc;

      firstTime = 0;
      return;
      }

   for (a = 0; a < numPiece; ++a)
      {
      for (b = 0; b < numPiece; ++b)
         {
         if (a == b)
            continue;

         if ((piece[a].pieceType == piece[b].pieceType) &&
             (piece[b].curLoc == prevLoc[a]))
            {
            /* if we're here then piece 'b' was in slot 'a' last move */
            /* first swap curLoc */
            piece[b].curLoc = piece[a].curLoc;
            piece[a].curLoc = prevLoc[a];

            /* then swap the pieces on *board */
            for (c = 0; c < piece[a].numBloc; ++c)
               {
               board[piece[a].curLoc + piece[a].xyoffset[c]] = a;
               board[piece[b].curLoc + piece[b].xyoffset[c]] = b;
               }
            /* we've already swapped this piece, we had */
            /* better not be able to find it later so...*/
               break; 
               }
         }
      }
   }


void ResetPrevLoc()
   {
   int a;

   for (a = 0; a < numPiece; ++a)
      prevLoc[a] = piece[a].curLoc;
   }


void FindDif(int *movedPiece, int *movedUp, int *movedRight)
   {
   int a;

   for (a = 0; a < numPiece; ++a)
      {
      if (piece[a].curLoc != prevLoc[a])
         {
         *movedPiece = a;
         *movedUp = prevLoc[a] / xsize - piece[a].curLoc / xsize;
         *movedRight = piece[a].curLoc % xsize - prevLoc[a] % xsize;
         return;
         }
      }
   }


#if 0

void ConcurrentShowWin(unsigned char *cPtr)
   {
   unsigned char *cString;
   unsigned char tempBoard[LARGEST_BOARD_SIZE];
   unsigned char *ptr;
   Generation *fGen;
   Generation *rGen;
   Generation *gen;
   unsigned char fPtr[SIZE_BT_POINTER];
   unsigned char rPtr[SIZE_BT_POINTER];
   unsigned char *winSeq;
   int numGen;
   int a;

   printf("***FOUND WIN ***\n");

   if (NULL == (winSeq = (unsigned char *) calloc(curMove * SIZE_BT_POINTER, sizeof(unsigned char))))
      {
      printf("unable to allocate memory to show win sequence\n");
      exit(0);
      }

   if (processForward)
      {
      fGen = curGen;
      memcpy (fPtr, boardPtr, SIZE_BT_POINTER);
      rGen = rCurGen;
      memcpy (rPtr, cPtr, SIZE_BT_POINTER);
      }
   else
      {
      fGen = fCurGen;
      memcpy (fPtr, cPtr, SIZE_BT_POINTER);
      rGen = curGen;
      memcpy (rPtr, boardPtr, SIZE_BT_POINTER);
      }

   /* first let's figure out how many generations we have before fGen */
   numGen = 0;
   for (gen = fGen->prev; gen; gen = gen->prev)
      ++numGen;

   ptr = fPtr;
   gen = fGen;
   for (a = numGen; a >= 0; --a)
      {
      memcpy(&winSeq[a * SIZE_BT_POINTER], ptr, SIZE_BT_POINTER);
      cString = FIND_ENTRY(gen->pList, ptr);
      ptr = &cString[compressedPuzSize];
      if (gen->prev)
         gen = gen->prev;
      else
         break;
      }

   if (a != 0)
      {
      printf("ConcurrentShowWin - a = %d, should equal 0 here", a);
      exit(0);
      }

   for (a = 0; a <= numGen; ++a)
      {
      cString = FIND_ENTRY(gen->pList, &winSeq[a * SIZE_BT_POINTER]);
      UncompressBoard(cString, tempBoard);
      printf("move %d\n", a);
      PrintBoard(tempBoard);
      gen = gen->next;
      }

   gen = rGen;

   while (gen)
      {
      cString = FIND_ENTRY(gen->pList, rPtr);
      UncompressBoard(cString, tempBoard);
      memcpy(rPtr, &cString[compressedPuzSize], SIZE_BT_POINTER);
      printf("move %d\n", a++);
      PrintBoard(tempBoard);
      gen = gen->prev;
      }

   printf("Finished in %d seconds\n", time(NULL) - startTime);
   exit(0);
   }

#endif

