//#define USE_SIDEBIT 1 // 4PL70 uses SIDEBIT here!!
/*
 * genmoves.c - C source for GNU CHESS
 *
 * Copyright (c) 1988,1989,1990 John Stanback
 * Copyright (c) 1992 Free Software Foundation
 *
 * This file is part of GNU CHESS.
 *
 * GNU Chess is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * GNU Chess is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNU Chess; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include "gnuchess.h"


short __aligned *TrP;

#define Link(from,to,flag,s) \
{\
   node->f = from; node->t = to;\
     node->reply = 0;\
       node->flags = flag;\
	 node->score = s;\
	   ++node;\
	     (*TrP)++;\
	     }

#ifndef KILLTO
inline void
LinkMove (ARGSZ int ply, ARGSZ int f,
	  ARGSZ int t,
	  ARGSZ int flag,
	  ARGSZ int xside)
#else
inline void
LinkMove (ARGSZ int ply, ARGSZ int f,
	  ARGSZ int t,
	  ARGSZ int flag)
#endif

/*
 * Add a move to the tree.  Assign a bonus to order the moves as follows: 1.
 * Principle variation 2. Capture of last moved piece 3. Other captures
 * (major pieces first) 4. Killer moves 5.
 */

{
  register short s = 0;
#if defined HISTORY
  register short z;
#endif
  register unsigned short mv;
  register struct leaf *node;

  node = &Tree[*TrP];
  mv = (f << 8) | t;
#ifdef KILLT
#ifdef USE_SIDEBIT
  s += killt[mv | sidebit];
#else
  s += killt[mv];
#endif
#endif
#ifdef HISTORY
  z = mv;
  if (xside == white) z |= 0x4000;
  s += history[z];
#endif
  if (color[t] != neutral)
    {
      /* TOsquare is the square the last piece moved moved to */
      s +=  value[board[t]] - board[f] + ((t == TOsquare) ? 500 : 0);
    }
  if (board[f] == pawn)
    if (row (t) == 0 || row (t) == 7)
      {
	flag |= promote;
	s += 800;
#if !defined OLDXBOARD  && !defined GNU3 && !defined CHESSTOOL
	Link (f, t, flag | queen, s - 20000);
	s -= 200;
	Link (f, t, flag | knight, s - 20000);
	s -= 50;
	Link (f, t, flag | rook, s - 20000);
	flag |= bishop;
	s -= 50;
#else
	flag |= queen;
#endif
      }
    else if (row (t) == 1 || row (t) == 6)
      {
	flag |= pwnthrt;
	s += 600;
      }
    else if ((row(t) == ((color[f] == white)?5:2)) && (ply > MINDEPTH) && (ply < Sdepth+3))
      {
	if ((mtl[white] - pmtl[white] + mtl[black] - pmtl[black]) < PTVALUE)
	  {
	    flag |= pwnthrt;
	    s += 400;
	  }
      }
  Link (f, t, flag, s - 20000);
}

inline
void
GenMoves (ARGSZ int ply, ARGSZ int sq, ARGSZ int side, ARGSZ int xside)

/*
 * Generate moves for a piece. The moves are taken from the precalulated
 * array nextpos/nextdir. If the board is free, next move is choosen from
 * nextpos else from nextdir.
 */

{
  register short u, piece;
  register unsigned char *ppos, *pdir;

  TrP = &TrPnt[ply + 1];
  piece = board[sq];
  ppos = nextpos[ptype[side][piece]][sq];
  pdir = nextdir[ptype[side][piece]][sq];
  if (piece == pawn)
    {
      u = ppos[sq];		/* follow no captures thread */
      if (color[u] == neutral)
	{
#ifndef KILLTO
	  LinkMove (ply, sq, u, 0, xside);
#else
	  LinkMove (ply, sq, u, 0);
#endif
	  u = ppos[u];
	  if (color[u] == neutral)
#ifndef KILLTO
	    LinkMove (ply, sq, u, 0, xside);
#else
	    LinkMove (ply, sq, u, 0);
#endif
	}
      u = pdir[sq];		/* follow captures thread */
      if (color[u] == xside && board[u] != king)
#ifndef KILLTO
	LinkMove (ply, sq, u, capture, xside);
#else
	LinkMove (ply, sq, u, capture);
#endif
      u = pdir[u];
      if (color[u] == xside && board[u] != king)
#ifndef KILLTO
	LinkMove (ply, sq, u, capture, xside);
#else
	LinkMove (ply, sq, u, capture);
#endif
    }
  else
    {
      u = ppos[sq];
      do
	{
	  if (color[u] == neutral)
	    {
#ifndef KILLTO
	      LinkMove (ply, sq, u, 0, xside);
#else
	      LinkMove (ply, sq, u, 0);
#endif
	      u = ppos[u];
	    }
	  else
	    {
	      if (color[u] == xside && board[u] != king)
#ifndef KILLTO
		LinkMove (ply, sq, u, capture, xside);
#else
		LinkMove (ply, sq, u, capture);
#endif
	      u = pdir[u];
	    }
      } while (u != sq);
    }
}

void
MoveList (INTSIZE int side, INTSIZE int ply)

/*
 * Fill the array Tree[] with all available moves for side to play. Array
 * TrPnt[ply] contains the index into Tree[] of the first move at a ply.
 */

{
  register short i, xside, f;

  xside = side ^ 1;
  TrP = &TrPnt[ply + 1];
  *TrP = TrPnt[ply];
  if (!PV)
    Swag0 = killr0[ply];
   else Swag0 = PV;
  Swag1 = killr1[ply];
  Swag2 = killr2[ply];
  Swag3 = killr3[ply];
  if (ply > 2)
    Swag4 = killr1[ply - 2]; else Swag4 = 0;
#ifdef KILLT
#ifdef USE_SIDEBIT
  sidebit = ((side == white) ? 0 : 0x80);
  killt[SwagHt | sidebit] += 5000;
  killt[Swag0 | sidebit] += 2000;
  killt[Swag1 | sidebit] += 60;
  killt[Swag2 | sidebit] += 50;
  killt[Swag3 | sidebit] += 40;
  killt[Swag4 | sidebit] += 30;
#else
  killt[SwagHt] += 5000;
  killt[Swag0] += 2000;
  killt[Swag1] += 60;
  killt[Swag2] += 50;
  killt[Swag3] += 40;
  killt[Swag4] += 30;
#endif
#endif
#ifdef HISTORKILLT
#ifdef HISTORY
  i = (side == black)?0x4000:0;
  history[SwagHt | i] += 5000;
  history[Swag0 | i] += 2000;
  history[Swag1 | i] += 60;
  history[Swag2 | i] += 50;
  history[Swag3 | i] += 40;
  history[Swag4 | i] += 30;
#endif
#endif
  for (i = PieceCnt[side]; i >= 0; i--)
    GenMoves (ply, PieceList[side][i], side, xside);
  if (!castld[side])
    {
      f = PieceList[side][0];
      if (castle (side, f, f + 2, 0))
	{
#ifndef KILLTO
	  LinkMove (ply, f, f + 2, cstlmask, xside);
#else
	  LinkMove (ply, f, f + 2, cstlmask);
#endif
	}
      if (castle (side, f, f - 2, 0))
	{
#ifndef KILLTO
	  LinkMove (ply, f, f - 2, cstlmask, xside);
#else
	  LinkMove (ply, f, f - 2, cstlmask);
#endif
	}
    }
    if (epsquare > 0)
      {
	  register SHORT l;

	  f = epmove1[epsquare];
	  if (color[f] == side && board[f] == pawn)
	    {
		l = epsquare + ((epsquare > f) ? -8 : 8);
		board[l] = no_piece;
		color[l] = neutral;
		      LinkMove (ply, f, epsquare, capture | epmask, xside);
		board[l] = pawn;
		color[l] = xside;
	    }
	  f = epmove2[epsquare];
	  if (color[f] == side && board[f] == pawn)
	    {
		l = epsquare + ((epsquare > f) ? -8 : 8);
		board[l] = no_piece;
		color[l] = neutral;
		      LinkMove (ply, f, epsquare, capture | epmask, xside);
		board[l] = pawn;
		color[l] = xside;
	    }
      }
#ifdef KILLT
#ifdef USE_SIDEBIT
  killt[SwagHt | sidebit] -= 5000;
  killt[Swag0 | sidebit] -= 2000;
  killt[Swag1 | sidebit] -= 60;
  killt[Swag2 | sidebit] -= 50;
  killt[Swag3 | sidebit] -= 40;
  killt[Swag4 | sidebit] -= 30;
#else
  killt[SwagHt] -= 5000;
  killt[Swag0] -= 2000;
  killt[Swag1] -= 60;
  killt[Swag2] -= 50;
  killt[Swag3] -= 40;
  killt[Swag4] -= 30;
#endif
#endif
#ifdef HISTORKILLT
#ifdef HISTORY
 i = (side == black)?0x4000:0;
  history[SwagHt | i] -= 5000;
  history[Swag0 | i] -= 2000;
  history[Swag1 | i] -= 60;
  history[Swag2 | i] -= 50;
  history[Swag3 | i] -= 40;
  history[Swag4 | i] -= 30;
#endif
#endif
  SwagHt = 0;			/* SwagHt is only used once */
  GenCnt += (TrPnt[ply+1] - TrPnt[ply]);
}

void
CaptureList (INTSIZE int side, INTSIZE int ply)

/*
 * Fill the array Tree[] with all available cature and promote moves for side
 * to play. Array TrPnt[ply] contains the index into Tree[] of the first move
 * at a ply.
 */

{
  register short u, sq, xside;
  register struct leaf *node;
  register unsigned char *ppos, *pdir;
  short i, piece, *PL, r7;

  xside = side ^ 1;
  TrP = &TrPnt[ply + 1];
  *TrP = TrPnt[ply];
  node = &Tree[*TrP];
  r7 = rank7[side];
  PL = PieceList[side];
#ifdef KILLT // 4PL70 USES sidebit here!!
#ifdef USE_SIDEBIT
  sidebit = ((side == white) ? 0 : 0x80);
  killt[SwagHt | sidebit] += 5000;
  killt[Swag0 | sidebit] += 2000;
  killt[Swag1 | sidebit] += 60;
  killt[Swag2 | sidebit] += 50;
  killt[Swag3 | sidebit] += 40;
  killt[Swag4 | sidebit] += 30;
#else
  killt[SwagHt] += 5000;
  killt[Swag0] += 2000;
  killt[Swag1] += 60;
  killt[Swag2] += 50;
  killt[Swag3] += 40;
  killt[Swag4] += 30;
#endif
#endif

    for (i = 0; i <= PieceCnt[side]; i++)
      {
	  SHORT r = row(PieceList[xside][0]);
	  SHORT c = column(PieceList[xside][0]);
	  sq = PL[i];
	  piece = board[sq];
	  if (sweep[piece])
	    {
		ppos = nextpos[piece][sq];
		pdir = nextdir[piece][sq];
		u = ppos[sq];
		do
		  {
		      if (color[u] == neutral) {
			    if (piece == rook | piece == queen) {
				if(r == row(sq) || c == column(sq)) Link (sq, u, 0, -999);}
				else if(abs(r - row(sq)) == abs(c - column(sq)))Link (sq, u, 0, -999);
			u = ppos[u];}
		      else
			{
			    if (color[u] == xside) Link (sq, u, capture, value[board[u]] + svalue[u] - piece);
			    u = pdir[u];
			}
		  }
		while (u != sq);
	    }
	  else
	    {
		pdir = nextdir[ptype[side][piece]][sq];
		if (piece == pawn && row (sq) == r7)
		  {
		      u = pdir[sq];
		      if (color[u] == xside){
			  Link (sq, u, capture | promote | queen, valueQ);
#if !defined OLDXBOARD  && !defined GNU3 && !defined CHESSTOOL
			    Link (sq, u, capture | promote | knight, valueN);
			    Link (sq, u, capture | promote | rook, valueR);
			    Link (sq, u, capture | promote | bishop, valueB);
#endif
		      }
		      u = pdir[u];
		      if (color[u] == xside)
			{
			    Link (sq, u, capture | promote | queen, valueQ);
#if !defined OLDXBOARD  && !defined GNU3 && !defined CHESSTOOL
			    Link (sq, u, capture | promote | knight, valueN);
			    Link (sq, u, capture | promote | rook, valueR);
			    Link (sq, u, capture | promote | bishop, valueB);
#endif
			}
		      ppos = nextpos[ptype[side][piece]][sq];
		      u = ppos[sq];	/* also generate non capture promote */
		      if (color[u] == neutral)
			{
			    Link (sq, u, promote | queen, valueQ);
#if !defined OLDXBOARD  && !defined GNU3 && !defined CHESSTOOL
			    Link (sq, u, promote | knight, valueN);
			    Link (sq, u, promote | rook, valueR);
			    Link (sq, u, promote | bishop, valueB);
#endif
			}
		  }
		else
		  {
		      u = pdir[sq];
		      do
			{
			    if (color[u] == xside)
				Link (sq, u, capture, value[board[u]] + svalue[u] - piece);
			    u = pdir[u];
			}
		      while (u != sq);
		  }
	    }
      }
#ifdef KILLT
#ifdef USE_SIDEBIT // 4PL70 uses SIDEBIT here!!
  sidebit = ((side == white) ? 0 : 0x80);
  killt[SwagHt | sidebit] -= 5000;
  killt[Swag0 | sidebit] -= 2000;
  killt[Swag1 | sidebit] -= 60;
  killt[Swag2 | sidebit] -= 50;
  killt[Swag3 | sidebit] -= 40;
  killt[Swag4 | sidebit] -= 30;
#else
  killt[SwagHt] -= 5000;
  killt[Swag0] -= 2000;
  killt[Swag1] -= 60;
  killt[Swag2] -= 50;
  killt[Swag3] -= 40;
  killt[Swag4] -= 30;
#endif
#endif
  SwagHt = 0;			/* SwagHt is only used once */
}
