#include <stdio.h>

#include "common.h"

#define WEIGHT  12
#define HASHSORTSCORE   INFINITY
#define KILLERSORTSCORE 1000
#define CASTLINGSCORE   500

void SortCaptures (short ply)
{
   leaf *p;
   int temp, f, t;

   for (p = TreePtr[ply]; p < TreePtr[ply+1]; p++)
   {
      f = Value[cboard[FROMSQ(p->move)]];
      t = Value[cboard[TOSQ(p->move)]];
      if (f < t)
         p->score = t - f;
      else
      {
         temp = SwapOff (p->move);
	 p->score = (temp < 0 ? -INFINITY : temp);
      }
   }
}


void SortMoves (short ply)
{
   leaf *p;
   short f, t, m, tovalue, side, xside;
   BitBoard enemyP;

   side = board.side;
   xside = 1^side;
   enemyP = board.b[xside][pawn];

   for (p = TreePtr[ply]; p < TreePtr[ply+1]; p++)
   {
      p->score = -INFINITY;
      f = FROMSQ (p->move);
      t = TOSQ (p->move);
      m = p->move & MOVEMASK;

      /* Hash table move (highest score) */
      if (m == Hashmv[ply])
         p->score += HASHSORTSCORE;
      else if (cboard[t] != 0 || p->move & PROMOTION)
      {
         tovalue = WEIGHT * (Value[cboard[t]] + Value[PROMOTEPIECE (p->move)]);
         p->score += tovalue - Value[cboard[f]];
      }
      /* Killers */
      else if (m == killer1[ply] || m == killer2[ply])
         p->score += KILLERSORTSCORE; 
      else if (ply > 2 && (m == killer1[ply-2] || m == killer2[ply-2]))
         p->score += KILLERSORTSCORE; 

      p->score += history[side][(p->move & 0x0FFF)] + taxicab[f][D5] - taxicab[t][E4];

      if ( cboard[f] == pawn ) {
        /* Look at pushing Passed pawns first */
        if ( (enemyP & PassedPawnMask[side][t]) == NULLBITBOARD )
           p->score +=50;
      } 

   }
}

void SortRoot (void)
{
   leaf *p;
   int f, t ;
   short side, xside;
   BitBoard enemyP;

   side = board.side;
   xside = 1^side;
   enemyP = board.b[xside][pawn];

   for (p = TreePtr[1]; p < TreePtr[2]; p++)
   {
      f = Value[cboard[FROMSQ(p->move)]];
      t = Value[cboard[TOSQ(p->move)]];
      if (cboard[TOSQ(p->move)] != 0 || (p->move & PROMOTION))
      {
         f = Value[cboard[FROMSQ(p->move)]];
         t = Value[cboard[TOSQ(p->move)]];
         if (f < t)
            p->score = -1000 + t - f;
         else
            p->score = -1000 + SwapOff (p->move);
      }
      else 
         p->score = -3000 + SwapOff (p->move);

      p->score += taxicab[FROMSQ(p->move)][D5] - taxicab[TOSQ(p->move)][E4];

      if ( f == pawn ) {
        /* Look at pushing Passed pawns first */
        if ( (enemyP & PassedPawnMask[side][TOSQ(p->move)]) == NULLBITBOARD )
           p->score +=50;
      } 

   }
}


void pick (leaf *head, short ply)
{
   int best;
   leaf *p, *pbest, tmp;

   best = head->score;
   pbest = head;
   for (p = head+1; p < TreePtr[ply+1]; p++) 
   {
      if (p->score > best)
      {
         pbest = p;
	 best = p->score;
      }
   }

   /*  Swap pbest with the head  */
   tmp = *head;
   *head = *pbest;
   *pbest = tmp; 
}


short PhasePick (leaf **p1, short ply)
{
   static leaf* p[MAXPLYDEPTH];
   leaf *p2;
   int mv;
   short side;

   side = board.side;
   switch (pickphase[ply])
   {
      case PICKHASH:
         TreePtr[ply+1] = TreePtr[ply];
         pickphase[ply] = PICKGEN1;
         if (Hashmv[ply] && IsLegalMove (Hashmv[ply]))
         {
            TreePtr[ply+1]->move = Hashmv[ply];
            *p1 = TreePtr[ply+1]++;
            return (true);
         }

      case PICKGEN1:
         pickphase[ply] = PICKCAPT;
         p[ply] = TreePtr[ply+1];
         GenCaptures (ply);
         for (p2 = p[ply]; p2 < TreePtr[ply+1]; p2++)
            p2->score = SwapOff(p2->move) * WEIGHT + 
				Value[cboard[TOSQ(p2->move)]];

      case PICKCAPT:
         while (p[ply] < TreePtr[ply+1])
         {
            pick (p[ply], ply);
            if ((p[ply]->move & MOVEMASK) == Hashmv[ply])
            {
	       p[ply]++;
	       continue;
            } 
            *p1 = p[ply]++;
            return (true);
         }

      case PICKKILL1:
         pickphase[ply] = PICKKILL2;
         if (killer1[ply] && killer1[ply] != Hashmv[ply] && 
				IsLegalMove (killer1[ply]))
         {
            TreePtr[ply+1]->move = killer1[ply];
            *p1 = TreePtr[ply+1];
            TreePtr[ply+1]++;
            return (true);
         }
         
      case PICKKILL2:
         pickphase[ply] = PICKGEN2;
         if (killer2[ply] && killer2[ply] != Hashmv[ply] && 
				IsLegalMove (killer2[ply]))
         {
            TreePtr[ply+1]->move = killer2[ply];
            *p1 = TreePtr[ply+1];
            TreePtr[ply+1]++;
            return (true);
         }

      case PICKGEN2:
         pickphase[ply] = PICKREST;
         p[ply] = TreePtr[ply+1];
         GenNonCaptures (ply);
         for (p2 = p[ply]; p2 < TreePtr[ply+1]; p2++)
	 {
            p2->score = history[side][(p2->move & 0x0FFF)] + 
		taxicab[FROMSQ(p2->move)][D5]  - taxicab[TOSQ(p2->move)][E4];
	    if (p2->move & CASTLING)
	       p2->score += CASTLINGSCORE;
         }
	 
      case PICKREST:
         while (p[ply] < TreePtr[ply+1])
         {
            pick (p[ply], ply);
            mv = p[ply]->move & MOVEMASK;
            if (mv == Hashmv[ply] || mv == killer1[ply] || 
		mv == killer2[ply])
	    {
	       p[ply]++;
               continue;
	    }
            *p1 = p[ply]++;
            return (true);
         }
   }
   return (false);
} 


short PhasePick1 (leaf **p1, short ply)
{
   static leaf* p[MAXPLYDEPTH];

   switch (pickphase[ply])
   {
      case PICKHASH:
         pickphase[ply] = PICKREST;
         p[ply] = TreePtr[ply];

      case PICKREST:
	 while (p[ply] < TreePtr[ply+1])
         {
            pick (p[ply], ply);
            *p1 = p[ply]++;
            return (true);
         }
   }
   return (false);
}
