// Copyright 1993 by Jon Dart.  All Rights Reserved.

#include "stdafx.h"
#include "attacks.h"
#include "bearing.h"
#ifndef _WINDOWS
#include <iostream.h>
#endif

void 
Attacks::clear()
{
    for (int i = 0; i < 64; i++)
    {
	my_attacks[i][White].clear();
	my_attacks[i][Black].clear();
    }
}

Attacks::Attacks()
{
    clear();
}

void 
Attacks::compute_attacks(const Board & board, const ColorType side)
// initial computation of attack info
{
    for (int i = 0; i < 16; i++)
    {
	Square sq(board.PiecePos(side, i));
	if (!sq.IsInvalid())
	    add_attacks(board, sq, side);
    }
}

void 
Attacks::add_attacks(const Board & board,
		     const Square & sq, const ColorType side)
{
    static Square squares[Bearing::MaxBearSq];
    Piece source(board[sq]);
    int n = Bearing::Attack_or_Defend(board, sq, squares);
    for (int j = 0; j < n; j++)
    {
	Square sq2(squares[j]);
	add_attack(sq2, source, side);
    }
}

static const int BishopInverseDirection[4] = { 3, 2, 1, 0 };
static const int RookInverseDirection[4] = { 1, 0, 3, 2 };

void 
Attacks::add_discovered_attacks(const Board & board,
			      const Square & sq, const Square & dest_square)
{
    for (int i = 0; i < 4; i++)
    {
	const byte *data = RookSquares[sq] + (8*i);
	Square sq2;
	for (;;)
	{
	    if (*data == 255 || (sq2 = *data++) == dest_square)
		break;
	    Piece piece(board[sq2]);
	    if (!piece.IsEmpty())
	    {
		if (piece.Type() == Piece::Rook ||
		    piece.Type() == Piece::Queen)
		{
		    Square sq3;
		    const byte *data2 = 
		      RookSquares[sq] + (8*RookInverseDirection[i]);
		    for (;;)
		    {
			if ((sq3 = *data2++) == 255)
			   break;
			Piece piece3(board[sq3]);
			if (piece3.IsEmpty())
			{
			    add_attack(sq3, piece, piece.Color());
			    if (sq3 == dest_square)
				break;
			} 
			else
			{
			    add_attack(sq3, piece, piece.Color());
			    break;
			}
		    }
		}
		break;
	    }
	}
	data = BishopSquares[sq] + (8*i);
	sq2 = sq;
	for (;;)
	{
	    if (*data == 255 || (sq2 = *data++) == dest_square)
		break;
	    Piece piece(board[sq2]);
	    if (!piece.IsEmpty())
	    {
		if (piece.Type() == Piece::Queen ||
		    piece.Type() == Piece::Bishop)
		{
		    Square sq3;
		    const byte *data2 = 
		      BishopSquares[sq] + (8*BishopInverseDirection[i]);
		    for (;;)
		    {
			if ((sq3 = *data2++) == 255)
			   break;
			Piece piece3(board[sq3]);
			if (piece3.IsEmpty())
			{
			    add_attack(sq3, piece, piece.Color());
			    if (sq3 == dest_square)
				break;
			} 
			else
			{
			    add_attack(sq3, piece, piece.Color());
			    break;
			}
		    }
		}
		break;
	    }
	}
    }
}

void 
Attacks::remove_attacks(const Board & board,
			const Square & sq, const ColorType side)
{
    static Square squares[Bearing::MaxBearSq];
    Piece source(board[sq]);
    int n = Bearing::Attack_or_Defend(board, sq, squares);
    for (int j = 0; j < n; j++)
    {
	Square sq2(squares[j]);
	remove_attack(sq2, source, side);
    }
}

void 
Attacks::remove_discovered_attacks(const Board & board,
			     const Square & sq, const Square & start_square)
{
    for (int i = 0; i < 4; i++)
    {
	Square sq2(sq);
	const byte *data = RookSquares[sq] + (8*i);
	for (;;)
	{
	    if (*data == 255 || (sq2 = *data++) == start_square)
		break;
	    Piece piece(board[sq2]);
	    if (!piece.IsEmpty())
	    {
		if (piece.Type() == Piece::Rook ||
		    piece.Type() == Piece::Queen)
		{
		    const byte *data2 = 
		      RookSquares[sq] + (8*RookInverseDirection[i]);
		    Square sq3(sq);
		    for (;;)
		    {
			if ((sq3 = *data2++) == 255)
			   break;
			else if (sq3 == start_square)
			{
			    remove_attack(sq3, piece, piece.Color());
			    break;
			}
			Piece piece3(board[sq3]);
			if (piece3.IsEmpty())
			    remove_attack(sq3, piece, piece.Color());
			else
			{
			    remove_attack(sq3, piece, piece.Color());
			    break;
			}
		    }
		}
		break;
	    }
	}
	sq2 = sq;
	data = BishopSquares[sq] + (8*i);
	for (;;)
	{
	    if (*data == 255 || (sq2 = *data++) == start_square)
		break;
	    Piece piece(board[sq2]);
	    if (!piece.IsEmpty())
	    {
		if (piece.Type() == Piece::Queen ||
		    piece.Type() == Piece::Bishop)
		{
		    Square sq3;
		    const byte *data2 = 
		        BishopSquares[sq] + (8*BishopInverseDirection[i]);
		    for (;;)
		    {
			if ((sq3 = *data2++) == 255)
				break;
			else if (sq3 == start_square)
			{
			    remove_attack(sq3, piece, piece.Color());
			    break;
			}
			Piece piece3(board[sq3]);
			if (piece3.IsEmpty())
			    remove_attack(sq3, piece, piece.Color());
			else
			{
			    remove_attack(sq3, piece, piece.Color());
			    break;
			}
		    }
		}
		break;
	    }
	}
    }
}

#if !defined(_WINDOWS) && defined(DEBUG_ATTACKS)
void 
Attacks::dump_attacks()
{
    int i;
    int j;
    for (i = 0; i < 8; i++)
    {
	for (j = 0; j < 8; j++)
	{
	    Square sq(j + 1, i + 1, Black);
	    cout << " [" << my_attacks[sq][White] << "," << 
	            my_attacks[sq][Black] << "]";
	}
	cout << endl;
    }
}
#endif

#ifdef DEBUG_ATTACKS
int Attacks::operator == (const Attacks &a) const
{
    for (int i = 0; i < 64; ++i)
    {
        if (my_attacks[i][White] != a.my_attacks[i][White])
	    return FALSE;
        if (my_attacks[i][Black] != a.my_attacks[i][Black])
	    return FALSE;
    }
    return TRUE;
}
#endif
