// EXchess source code, (c) Daniel C. Homan  1997-2011
// Released under the GNU public license, see file license.txt

/* Piece moves */

#include "define.h"
#include "chess.h"
#include "const.h"
#include "funct.h"
#include "extern.h"

/*------------------------- Semi-legal moves generator ---------------------*/

void position::allmoves(move_list *list, tree_search *ts)
{
  register int i;
  list->count = 0;

  for(i=1;i<=plist[wtm][PAWN][0];i++) 
    pawn_moves(list, plist[wtm][PAWN][i], ts);
  for(i=1;i<=plist[wtm][KNIGHT][0];i++) 
    knight_moves(list, plist[wtm][KNIGHT][i], ts);
  for(i=1;i<=plist[wtm][BISHOP][0];i++) 
    bishop_moves(list, plist[wtm][BISHOP][i], ts);
  for(i=1;i<=plist[wtm][ROOK][0];i++) 
    rook_moves(list, plist[wtm][ROOK][i], ts);
  for(i=1;i<=plist[wtm][QUEEN][0];i++) {
    bishop_moves(list, plist[wtm][QUEEN][i], ts);
    rook_moves(list, plist[wtm][QUEEN][i], ts);
  }
  for(i=1;i<=plist[wtm][KING][0];i++) 
    king_moves(list, plist[wtm][KING][i], ts);

}

/* Add move to move list */
// Function to add move to move list
// Move is scored for alpha-beta algorithm
void position::add_move(int fsq, int tsq, move_list *list, char type, tree_search *ts)
{
  int i = list->count;                 // move list index

  // add move to list
  list->mv[i].m.b.from = fsq;
  list->mv[i].m.b.to = tsq;
  list->mv[i].m.b.type = type;
  list->mv[i].m.b.promote = 0;

  if(check) {
   if(!check_table[tsq][plist[wtm][KING][1]]
      && !(knight_check_table[tsq][plist[wtm][KING][1]]
           && sq[tsq].type == KNIGHT)
      && !(type&EP)
      && sq[fsq].type != KING)
    return;
   position temp_pos = (*this);
   temp_pos.sq[tsq] = temp_pos.sq[fsq];
   temp_pos.sq[fsq] = empty;
   if(type&EP) {
    if(wtm) temp_pos.sq[tsq-8] = empty;
    else temp_pos.sq[tsq+8] = empty;
   }
   if(temp_pos.sq[tsq].type == KING) {
    if(temp_pos.attacks(tsq, (wtm^1), 1)) return;
   } else {
    if(temp_pos.attacks(plist[wtm][KING][1], (wtm^1), 1)) return;
   }
  }   

  // if it is a hash_move, score it first
  if(list->mv[i].m.t == ts->hmove.t) { 
    list->mv[i].score = 50000000;
  }
  // else if it is a capture...
  else if(type&CAPTURE) {
    if(value[sq[tsq].type] >= value[sq[fsq].type]) {
      list->mv[i].score = 10000000 + value[sq[tsq].type]
                               -(value[sq[fsq].type]/8);
    } else if(swap(tsq,(*this),wtm,fsq) >= 0) {
      list->mv[i].score = 10000000 + value[sq[tsq].type]
                               -(value[sq[fsq].type]/8);
     // looking for a revealed check if score isn't high enough
    } else if(slide_check_table[fsq][plist[wtm^1][KING][1]])  {
	position temp_pos = (*this);
	temp_pos.wtm ^= 1;
	temp_pos.sq[tsq] = temp_pos.sq[fsq];
	temp_pos.sq[fsq] = empty;
	if(temp_pos.simple_check(fsq)) list->mv[i].score = 10000000 + value[sq[tsq].type]
                               -(value[sq[fsq].type]/8);
	else list->mv[i].score = 0;
    } else list->mv[i].score = 0;
  }
  // if move has no score give a 'killer score' or a history score         
  else { 
    if(ts->killer1[wtm] == list->mv[i].m.t) 
     list->mv[i].score = 6000000;
    else if(ts->killer2[wtm] == list->mv[i].m.t) 
     list->mv[i].score = 4000000;
    else if(ts->killer3[wtm] == list->mv[i].m.t) 
     list->mv[i].score = 2000000;
    // give it a history score
    else list->mv[i].score = ts->history[fsq][tsq];
  }
  
  list->count++;                       // increment list count

  // is it a promotion move? if so, generate all types of promotions
  if((tsq > 55 || tsq < 8) && sq[fsq].type == PAWN)
   {
     list->mv[i].m.b.type |= PROMOTE; list->mv[i].m.b.promote = QUEEN;
     list->mv[i].score += 20000000;
     list->mv[list->count] = list->mv[i];
     list->mv[list->count].m.b.promote = ROOK;
     list->mv[list->count].score -= 9000050; list->count++;
     list->mv[list->count] = list->mv[i];
     list->mv[list->count].m.b.promote = BISHOP;
     list->mv[list->count].score -= 9000060; list->count++;
     list->mv[list->count] = list->mv[i];
     list->mv[list->count].m.b.promote = KNIGHT;
     list->mv[list->count].score -= 9000070; list->count++;
   }

}

/*------------------------------- Bishop Moves --------------------------*/
void position::bishop_moves(move_list *list, int sqr, tree_search *ts)
{
  int mm, nn, ii, tsq;

  mm = FILE(sqr); nn = RANK(sqr);

  ii = 1;
  while (mm + ii <= 7 && nn + ii <= 7)
  {
   tsq = SQR((mm+ii),(nn+ii));
   if (!sq[tsq].type)
   { add_move(sqr, tsq, list, 0, ts); }
   else if (sq[tsq].side != wtm)
   { add_move(sqr, tsq, list, 1, ts); break; }
   else break;
   ii++;
  }

  ii = 1;
  while (mm - ii >= 0 && nn + ii <= 7)
  {
   tsq = SQR((mm-ii),(nn+ii));
   if (!sq[tsq].type)
   { add_move(sqr, tsq, list, 0, ts); }
   else if (sq[tsq].side != wtm)
   { add_move(sqr, tsq, list, 1, ts); break; }
   else break;
   ii++;
  }

  ii = 1;
  while(mm + ii <= 7 && nn - ii >= 0)
  {
   tsq = SQR((mm+ii),(nn-ii));
   if (!sq[tsq].type)
   { add_move(sqr, tsq, list, 0, ts); }
   else if (sq[tsq].side != wtm)
   { add_move(sqr, tsq, list, 1, ts); break; }
   else break;
   ii++;
  }

  ii = 1;
  while (mm - ii >= 0 && nn - ii >= 0)
  {
   tsq = SQR((mm-ii),(nn-ii));
   if (!sq[tsq].type)
   { add_move(sqr, tsq, list, 0, ts); }
   else if (sq[tsq].side != wtm)
   { add_move(sqr, tsq, list, 1, ts); break; }
   else break;
   ii++;
  }

}

/*--------------------------- Rook Moves ---------------------------*/

void position::rook_moves(move_list *list, int sqr, tree_search *ts)
{
  int mm, nn, ii, tsq;

  mm = FILE(sqr); nn = RANK(sqr);

  ii = 1;
  while (mm + ii <= 7)
  {
   tsq = SQR((mm+ii),nn);
   if (!sq[tsq].type)
   { add_move(sqr, tsq, list, 0, ts); }
   else if (sq[tsq].side != wtm)
   { add_move(sqr, tsq, list, 1, ts); break; }
   else break;
   ii++;
  }

  ii = 1;
  while (mm - ii >= 0)
  {
   tsq = SQR((mm-ii),nn);
   if (!sq[tsq].type)
   { add_move(sqr, tsq, list, 0, ts); }
   else if (sq[tsq].side != wtm)
   { add_move(sqr, tsq, list, 1, ts); break; }
   else break;
   ii++;
  }

  ii = 1;
  while(nn - ii >= 0)
  {
   tsq = SQR(mm,(nn-ii));
   if (!sq[tsq].type)
   { add_move(sqr, tsq, list, 0, ts); }
   else if (sq[tsq].side != wtm)
   { add_move(sqr, tsq, list, 1, ts); break; }
   else break;
   ii++;
  }

  ii = 1;
  while (nn + ii <= 7)
  {
   tsq = SQR(mm,(nn+ii));
   if (!sq[tsq].type)
   { add_move(sqr, tsq, list, 0, ts); }
   else if (sq[tsq].side != wtm)
   { add_move(sqr, tsq, list, 1, ts); break; }
   else break;
   ii++;
  }

}

/*--------------------------- Knight Moves ----------------------------*/
void position::knight_moves(move_list *list, int sqr, tree_search *ts)
{
  int tsq;

  if(FILE(sqr) < 6 && RANK(sqr) < 7) {
   tsq = sqr + 10;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(FILE(sqr) < 6 && RANK(sqr)) {
   tsq = sqr - 6;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(FILE(sqr) > 1 && RANK(sqr) < 7) {
   tsq = sqr + 6;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(FILE(sqr) > 1 && RANK(sqr)) {
   tsq = sqr - 10;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(FILE(sqr) < 7 && RANK(sqr) < 6) {
   tsq = sqr + 17;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(FILE(sqr) && RANK(sqr) < 6) {
   tsq = sqr + 15;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(FILE(sqr) < 7 && RANK(sqr) > 1) {
   tsq = sqr - 15;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(FILE(sqr) && RANK(sqr) > 1) {
   tsq = sqr - 17;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }

}

/*--------------------------- King Moves ----------------------------*/
void position::king_moves(move_list *list, int sqr, tree_search *ts)
{
  int tsq;

  if(FILE(sqr) && RANK(sqr) < 7) {
   tsq = sqr + 7;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(RANK(sqr) < 7) {
   tsq = sqr + 8;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(FILE(sqr) < 7 && RANK(sqr) < 7) {
   tsq = sqr + 9;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(FILE(sqr)) {
   tsq = sqr - 1;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(FILE(sqr) < 7) {
   tsq = sqr + 1;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(FILE(sqr) < 7 && RANK(sqr)) {
   tsq = sqr - 7;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(RANK(sqr)) {
   tsq = sqr - 8;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }
  if(FILE(sqr) && RANK(sqr)) {
   tsq = sqr - 9;
   if(sq[tsq].side != wtm) {
     if(sq[tsq].type) add_move(sqr, tsq, list, 1, ts);
     else add_move(sqr, tsq, list, 0, ts);
    }
  }

  // genrating castling moves ...
  if(wtm) {
     if (castle&1) add_move(4, 6, list, 2, ts);
     if (castle&2) add_move(4, 2, list, 2, ts);
  } else {
     if (castle&4) add_move(60, 62, list, 2, ts);
     if (castle&8) add_move(60, 58, list, 2, ts);
  }
}

/*------------------------ Pawn Moves ------------------------------*/
void position::pawn_moves(move_list *list, int sqr, tree_search *ts)
{

  if(wtm) {                        // if it is white's pawn
   if(!sq[sqr+8].type) {
     add_move(sqr, sqr+8, list, 16, ts);
     if(RANK(sqr) == 1) {
       if(!sq[sqr+16].type) { add_move(sqr, sqr+16, list, 8|16, ts); }
      }
   }
   if(FILE(sqr)) {
    if (sq[sqr+7].type && sq[sqr+7].side != wtm)
      { add_move(sqr, sqr+7, list, (1|PAWN_PUSH), ts); }
    else if((sqr+7) == ep && ep)
      { add_move(sqr, sqr+7, list, (4|1|PAWN_PUSH), ts); }
   }
   if(FILE(sqr) < 7) {
    if (sq[sqr+9].type && sq[sqr+9].side != wtm)
      { add_move(sqr, sqr+9, list, (1|PAWN_PUSH), ts); }
    else if((sqr+9) == ep && ep)
      { add_move(sqr, sqr+9, list, (4|1|PAWN_PUSH), ts); }
   }
  } else {                           // or if it is black's pawn
   if(!sq[sqr-8].type) {
     add_move(sqr, sqr-8, list, 16, ts);
     if(RANK(sqr) == 6) {
       if(!sq[sqr-16].type) { add_move(sqr, sqr-16, list, 8|16, ts); }
      }
   }
   if(FILE(sqr)) {
    if (sq[sqr-9].type && sq[sqr-9].side != wtm)
      { add_move(sqr, sqr-9, list, (1|PAWN_PUSH), ts); }
    else if((sqr-9) == ep && ep)
      { add_move(sqr, sqr-9, list, (4|1|PAWN_PUSH), ts); }
   }
   if(FILE(sqr) < 7) {
    if (sq[sqr-7].type && sq[sqr-7].side != wtm)
      { add_move(sqr, sqr-7, list, (1|PAWN_PUSH), ts); }
    else if((sqr-7) == ep && ep)
      { add_move(sqr, sqr-7, list, (4|1|PAWN_PUSH), ts); }
   }
  }
}
























