#ifndef BUILD_mossa_gen
#define BUILD_mossa_gen

#include "RobboLito.h"

#define Add(L, x, y) { (L++)->move = (x) | (y);}
#define AddTo(T, w) \
  { while (T) \
      { to = BSF (T); c = POSITION->sq[to]; \
	Add (LIST, (sq << 6) | to, 0);	BitClear (to, T); } }

static uint32 CAPTURE_VALUE[16][16]; /* ignored, AddTo, ignores w // HACK */

#define PtoQ ( 0xd8 << 24 )
#define PtoN ( 0xc2 << 24 )

#define FLAG_CHECK 0x8000

#define MoveAdd(L, x, pi, to, check) \
  { (L++)->move = (x) | ( (SqSet[to] & (check) ) ? FLAG_CHECK : 0) | 0; }

#define MovesTo(T, pi, check) \
  { while (T) \
      { to = BSF (T); MoveAdd (LIST, (sq << 6) | to, pi, to, check); \
	BitClear (to, T); } }

#define UnderPromWhite() \
  { if ( (AttN[to] & bBitboardK) == 0) \
      MoveAdd ( LIST, FlagPromN | (sq << 6) | to, wEnumP, to, 0); \
    MoveAdd (LIST, FlagPromR | (sq << 6) | to, wEnumP, to, 0); \
    MoveAdd (LIST, FlagPromB | (sq << 6) | to, wEnumP, to, 0); }

#define UnderPromBlack() \
  { if ( (AttN[to] & wBitboardK) == 0) \
      MoveAdd (LIST, FlagPromN | (sq << 6) | to, bEnumP, to, 0); \
    MoveAdd (LIST, FlagPromR | (sq << 6) | to, bEnumP, to, 0); \
    MoveAdd (LIST, FlagPromB | (sq << 6) | to, bEnumP, to, 0); }

typeMoveList* EvasionMoves (typePOS* POSITION, typeMoveList* list, uint64 mask)
{
  if (POSITION->wtm)
    return WhiteEvasions (POSITION, list, mask);
  return BlackEvasions (POSITION, list, mask);
}

typeMoveList* OrdinaryMoves (typePOS* POSITION, typeMoveList* list)
{
  if (POSITION->wtm)
    return WhiteOrdinary (POSITION, list);
  return BlackOrdinary (POSITION, list);
}

typeMoveList* CaptureMoves (typePOS* POSITION, typeMoveList* list, uint64 mask)
{
  if (POSITION->wtm)
    return WhiteCaptures (POSITION, list, mask & bBitboardOcc);
  return BlackCaptures (POSITION, list, mask & wBitboardOcc);
}

#include "move_gen.c"
#include "white.h"
#else
#include "black.h"
#endif

typeMoveList* MyEvasion (typePOS* POSITION, typeMoveList* LIST, uint64 c2)
{
  uint64 U, T, att, mask;
  int sq, to, fr, c, king, pi;
  king = MyKingSq;
  att = MyKingCheck;
  sq = BSF (att);
  pi = POSITION->sq[sq];
  mask = (~OppAttacked) & (((pi == EnumOppP) ? AttK[king] : 0) |
			   Evade (king, sq)) & (~MyOccupied) & c2;
  BitClear (sq, att);
  if (att)
    {
      sq = BSF (att);
      pi = POSITION->sq[sq];
      mask = mask & (PIECE_IS_OPP_PAWN (pi) | Evade (king, sq));
      sq = king;
      AddTo (mask, CAPTURE_VALUE[EnumMyK][c]);
      LIST->move = 0;
      return LIST;
    }
  c2 &= InterPose (king, sq);
  sq = king;
  AddTo (mask, CAPTURE_VALUE[EnumMyK][c]);
  if (!c2)
    {
      LIST->move = 0;
      return LIST;
    }

  if (CAPTURE_RIGHT & (c2 & OppOccupied))
    {
      to = BSF (c2 & OppOccupied);
      c = POSITION->sq[to];
      if (EIGHTH_RANK (to))
	{
	  Add (LIST, FlagPromQ | FROM_LEFT (to) | to,
	       (0x20 << 24) + CAPTURE_VALUE[EnumMyP][c]);
	  Add (LIST, FlagPromN | FROM_LEFT (to) | to, 0);
	  Add (LIST, FlagPromR | FROM_LEFT (to) | to, 0);
	  Add (LIST, FlagPromB | FROM_LEFT (to) | to, 0);
	}
      else
	Add (LIST, FROM_LEFT (to) | to, CAPTURE_VALUE[EnumMyP][c]);
    }

  if (CAPTURE_LEFT & (c2 & OppOccupied))
    {
      to = BSF (c2 & OppOccupied);
      c = POSITION->sq[to];
      if (EIGHTH_RANK (to))
	{
	  Add (LIST, FlagPromQ | FROM_RIGHT (to) | to,
	       (0x20 << 24) + CAPTURE_VALUE[EnumMyP][c]);
	  Add (LIST, FlagPromN | FROM_RIGHT (to) | to, 0);
	  Add (LIST, FlagPromR | FROM_RIGHT (to) | to, 0);
	  Add (LIST, FlagPromB | FROM_RIGHT (to) | to, 0);
	}
      else
	Add (LIST, FROM_RIGHT (to) | to, CAPTURE_VALUE[EnumMyP][c]);
    }
  to = POSITION->DYN->ep;
  if (to)
    {
      if (CAPTURE_RIGHT & SqSet[to] && SqSet[BACKWARD (to)] & c2)
	Add (LIST, FlagEP | FROM_LEFT (to) | to,
	     CAPTURE_VALUE[EnumMyP][EnumOppP]);
      if (CAPTURE_LEFT & SqSet[to] && SqSet[BACKWARD (to)] & c2)
	Add (LIST, FlagEP | FROM_RIGHT (to) | to,
	     CAPTURE_VALUE[EnumMyP][EnumOppP]);
    }
  T = BitboardMyP & BACK_SHIFT ((c2 & OppOccupied) ^ c2);
  while (T)
    {
      fr = BSF (T);
      BitClear (fr, T);
      if (SEVENTH_RANK (fr))
	{
	  Add (LIST, FlagPromQ | (fr << 6) | FORWARD (fr),
	       CAPTURE_VALUE[EnumMyP][0]);
	  Add (LIST, FlagPromN | (fr << 6) | FORWARD (fr), 0);
	  Add (LIST, FlagPromR | (fr << 6) | FORWARD (fr), 0);
	  Add (LIST, FlagPromB | (fr << 6) | FORWARD (fr), 0);
	}
      else
	Add (LIST, (fr << 6) | FORWARD (fr), CAPTURE_VALUE[EnumMyP][0]);
    }

  T = BitboardMyP & BACK_SHIFT2 ((c2 & OppOccupied) ^ c2) &
      SECOND_RANK & BACK_SHIFT (~POSITION->OccupiedBW);
  while (T)
    {
      fr = BSF (T);
      BitClear (fr, T);
      Add (LIST, (fr << 6) | FORWARD2 (fr), CAPTURE_VALUE[EnumMyP][0]);
    }
  for (U = BitboardMyN; U; BitClear (sq, U))
    {
      sq = BSF (U);
      T = AttN[sq] & c2;
      AddTo (T, CAPTURE_VALUE[EnumMyN][c]);
    }
  for (U = BitboardMyB; U; BitClear (sq, U))
    {
      sq = BSF (U);
      T = AttB (sq) & c2;
      AddTo (T, CAPTURE_VALUE[EnumMyBL][c]);
    }
  for (U = BitboardMyR; U; BitClear (sq, U))
    {
      sq = BSF (U);
      T = AttR (sq) & c2;
      AddTo (T, CAPTURE_VALUE[EnumMyR][c]);
    }
  for (U = BitboardMyQ; U; BitClear (sq, U))
    {
      sq = BSF (U);
      T = AttQ (sq) & c2;
      AddTo (T, CAPTURE_VALUE[EnumMyQ][c]);
    }
  LIST->move = 0;
  return LIST;
}

typeMoveList* MyCapture (typePOS* POSITION, typeMoveList* LIST, uint64 mask)
{
  uint64 U, T, AttR, AttB;
  int sq, to, c;
  to = POSITION->DYN->ep;
  if (to)
    {
      if (CAPTURE_LEFT & SqSet[to])
	Add (LIST, FlagEP | FROM_RIGHT (to) | to, CaptureEP);
      if (CAPTURE_RIGHT & SqSet[to])
	Add (LIST, FlagEP | FROM_LEFT (to) | to, CaptureEP);
    }
  if ((mask & MyAttacked) == 0)
    goto NO_TARGET;

  T = CAPTURE_LEFT & (~BITBOARD_EIGHTH_RANK) & mask;
  while (T)
    {
      to = BSF (T);
      c = POSITION->sq[to];
      Add (LIST, FROM_RIGHT (to) | to, CAPTURE_VALUE[EnumMyP][c]);
      BitClear (to, T);
    }
  T = CAPTURE_RIGHT & (~BITBOARD_EIGHTH_RANK) & mask;
  while (T)
    {
      to = BSF (T);
      c = POSITION->sq[to];
      Add (LIST, FROM_LEFT (to) | to, CAPTURE_VALUE[EnumMyP][c]);
      BitClear (to, T);
    }

  for (U = BitboardMyN; U; BitClear (sq, U))
    {
      sq = BSF (U);
      T = AttN[sq] & mask;
      AddTo (T, CAPTURE_VALUE[EnumMyN][c]);
    }
  for (U = BitboardMyB; U; BitClear (sq, U))
    {
      sq = BSF (U);
      AttB = AttB (sq);
      T = AttB & mask;
      AddTo (T, CAPTURE_VALUE[EnumMyBL][c]);
    }
  for (U = BitboardMyR; U; BitClear (sq, U))
    {
      sq = BSF (U);
      AttR = AttR (sq);
      T = AttR & mask;
      AddTo (T, CAPTURE_VALUE[EnumMyR][c]);
    }
  for (U = BitboardMyQ; U; BitClear (sq, U))
    {
      sq = BSF (U);
      AttR = AttR (sq);
      AttB = AttB (sq);
      T = (AttB | AttR) & mask;
      AddTo (T, CAPTURE_VALUE[EnumMyQ][c]);
    }
  sq = BSF (BitboardMyK);
  T = AttK[sq] & mask & (~OppAttacked);
  AddTo (T, CAPTURE_VALUE[EnumMyK][c]);
NO_TARGET:
  for (U = BitboardMyP & BITBOARD_SEVENTH_RANK; U; BitClear (sq, U))
    {
      sq = BSF (U);
      to = FORWARD (sq);
      if (POSITION->sq[to] == 0)
	{
	  Add (LIST, FlagPromQ | (sq << 6) | to, PtoQ);
	  if (AttN[to] & BitboardOppK)
	    Add (LIST, FlagPromN | (sq << 6) | to, PtoN);
	}
      to = FORWARD_LEFT (sq);
      if (sq != WHITE_A7 && SqSet[to] & mask)
	{
	  c = POSITION->sq[to];
	  Add (LIST, FlagPromQ | (sq << 6) | to, PromQueenCap);
	  if (AttN[to] & BitboardOppK)
	    Add (LIST, FlagPromN | (sq << 6) | to, PromKnightCap);
	}
      to = FORWARD_RIGHT (sq);
      if (sq != WHITE_H7 && SqSet[to] & mask)
	{
	  c = POSITION->sq[to];
	  Add (LIST, FlagPromQ | (sq << 6) | to, PromQueenCap);
	  if (AttN[to] & BitboardOppK)
	    Add (LIST, FlagPromN | (sq << 6) | to, PromKnightCap);
	}
    }
  LIST->move = 0;
  return LIST;
}

typeMoveList* MyOrdinary (typePOS* POSITION, typeMoveList* LIST)
{
  uint64 empty = ~POSITION->OccupiedBW, U, T, ROOK, BISHOP, PAWN;
  int to, sq, opks = OppKingSq;

  if (CastleOO && ((POSITION->OccupiedBW | OppAttacked) & WHITE_F1G1) == 0)
    MoveAdd (LIST, FlagOO | (WHITE_E1 << 6) | WHITE_G1, EnumMyK, WHITE_G1, 0);
  if (CastleOOO && (POSITION->OccupiedBW & WHITE_B1C1D1) == 0
      && (OppAttacked & WHITE_C1D1) == 0)
    MoveAdd (LIST, FlagOO | (WHITE_E1 << 6) | WHITE_C1, EnumMyK, WHITE_C1, 0);

  PAWN = MyAttackedPawns[opks];
  if (BitboardMyQ | BitboardMyR)
    ROOK = AttR (opks);
  if (BitboardMyQ | BitboardMyB)
    BISHOP = AttB (opks);
  for (U = FORWARD_SHIFT (BitboardMyP & SECOND_SIXTH_RANKS) & empty;
       U; BitClear (sq, U))
    {
      to = BSF (U);
      if (ON_THIRD_RANK (to) && POSITION->sq[FORWARD (to)] == 0)
	MoveAdd (LIST, (BACKWARD (to) << 6) | FORWARD (to),
		 EnumMyP, FORWARD (to), PAWN);
      MoveAdd (LIST, (BACKWARD (to) << 6) | to, EnumMyP, to, PAWN);
    }

  for (U = BitboardMyQ; U; BitClear (sq, U))
    {
      sq = BSF (U);
      T = AttQ (sq) & empty;
      MovesTo (T, EnumMyQ, ROOK | BISHOP);
    }
  for (U = BitboardMyR; U; BitClear (sq, U))
    {
      sq = BSF (U);
      T = AttR (sq) & empty;
      MovesTo (T, EnumMyR, ROOK);
    }
  for (U = BitboardMyB; U; BitClear (sq, U))
    {
      sq = BSF (U);
      T = AttB (sq) & empty;
      MovesTo (T, ((SqSet[sq] & DARK) ? EnumMyBD : EnumMyBL), BISHOP);
    }
  sq = BSF (BitboardMyK);
  T = AttK[sq] & empty & (~OppAttacked);
  MovesTo (T, EnumMyK, 0);
  for (U = BitboardMyN; U; BitClear (sq, U))
    {
      sq = BSF (U);
      T = AttN[sq] & empty;
      MovesTo (T, EnumMyN, AttN[opks]);
    }
  for (U = BitboardMyP & BITBOARD_SEVENTH_RANK; U; BitClear (sq, U))
    {
      sq = BSF (U);
      to = FORWARD (sq);
      if (POSITION->sq[to] == 0)
	UnderProm ();
      to = FORWARD_LEFT (sq);
      if (sq != WHITE_A7 && SqSet[to] & OppOccupied)
	UnderProm ();
      to = FORWARD_RIGHT (sq);
      if (sq != WHITE_H7 && SqSet[to] & OppOccupied)
	UnderProm ();
    }
  LIST->move = 0;
  return LIST;
}
