/* Pepito v1.59  -- file: initataq.c --
   Copyright (c) 2000-02 Carlos del Cacho

   This program 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.

   This program 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 this program; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Contact the author: guggenjaimito@yahoo.com
*/

#ifndef UNIQUE_SOURCE_FILE
#  include "datos.h"
#endif

/************************************************************************************
 *                                                                                  *
 *    Inicialización de las máscaras que se van a emplear a lo largo del programa   *
 *    para extraer bits, generar jugadas...                                         *
 *                                                                                  *
 *    - MASK : cada celda contiene un número de 64 bits con un solo bit a 1, cuya   *
 *      posición viene determinada por el índice del array (MSB->63  /  LSB->0).    *
 *                                                                                  *
 *    - COLUMNA: contiene 8 bits a 1 por número, los correspondientes a casillas    *
 *      en dicha columna.                                                           *
 *                                                                                  *
 *    - FILA: equivalente a COLUMNA.                                                *
 *                                                                                  *
 *    - ENTRE: si dos casillas están alineadas, esta tabla devuelve un mapa de bits *
 +      con las casillas que hay entre medias.                                      *
 *                                                                                  *
 ************************************************************************************/

void            InitMasks(entero64 mask[65], entero64 fil[8], entero64 col[8], entero64 entre[64][64],
                                          entero64 izq[8], entero64 der[8])
{
    int             i,
                    j,
                    k;
    entero64        mask_aux,
                    temp;

    for (i = 0; i < 64; i++)
        mask[i] = (entero64) 1 << i;
    mask[64] = 0;
    for (i = 0; i < 8; i++) {
        fil[i] = mask[0 + 8 * i] | mask[1 + 8 * i] | mask[2 + 8 * i] | mask[3 + 8 * i] | mask[4 + 8 * i] |
            mask[5 + 8 * i] | mask[6 + 8 * i] | mask[7 + 8 * i];
        col[i] = mask[0 + i] | mask[8 + i] | mask[16 + i] | mask[24 + i] | mask[32 + i] | mask[40 + i] |
            mask[48 + i] | mask[56 + i];
    }

    for (i = 0; i < 8; i++) {
        izq[i] = der[i] = 0;
        for (k = i - 1; k >= 0; k--)
            izq[i] |= col[k];
        for (k = i + 1; k < 8; k++)
            der[i] |= col[k];
    }

    for (k = 0; k < 64; k++)
        for (j = 0; j < 64; j++) {
            mask_aux = mask[k];
            i = k;
            temp = 0;
            switch (DIRECCION[i][j]) {
            case 1:
                while (i != j) {
                    mask_aux >>= 7;
                    temp |= mask_aux;
                    i -= 7;
                }
                temp ^= mask_aux;
                break;

            case 2:
                while (i != j) {
                    mask_aux <<= 1;
                    temp |= mask_aux;
                    i += 1;
                }
                temp ^= mask_aux;
                break;

            case 3:
                while (i != j) {
                    mask_aux <<= 9;
                    temp |= mask_aux;
                    i += 9;
                }
                temp ^= mask_aux;
                break;

            case 4:
                while (i != j) {
                    mask_aux <<= 8;
                    temp |= mask_aux;
                    i += 8;
                }
                temp ^= mask_aux;
                break;

            case 5:
                while (i != j) {
                    mask_aux <<= 7;
                    temp |= mask_aux;
                    i += 7;
                }
                temp ^= mask_aux;
                break;

            case 6:
                while (i != j) {
                    mask_aux >>= 1;
                    temp |= mask_aux;
                    i -= 1;
                }
                temp ^= mask_aux;
                break;

            case 7:
                while (i != j) {
                    mask_aux >>= 9;
                    temp |= mask_aux;
                    i -= 9;
                }
                temp ^= mask_aux;
                break;

            case 8:
                while (i != j) {
                    mask_aux >>= 8;
                    temp |= mask_aux;
                    i -= 8;
                }
                temp ^= mask_aux;
                break;
            }                   // switch

            entre[k][j] = temp;
        }                       // for
    return;

}

/************************************************************************************
 *                                                                                  *
 *    La siguiente función inicializa el array que marca la dirección del vector    *
 *    (casilla_orig, casilla_fin). Cada dirección viene marcada por:                *
 *                                                                                  *
 *        +-----+-----+-----+                                                       *
 *        |  7  |  8  |  1  |       donde x marca la casilla de origen.             *
 *        +-----+-----+-----+       cualquier otra dirección (p.ej. salto           *
 *        |  6  |  x  |  2  |       del caballo) se expresa por un 0.               *
 *        +-----+-----+-----+                                                       *
 *        |  5  |  4  |  3  |                                                       *
 *        +-----+-----+-----+                                                       *
 *                                                                                  *
 ************************************************************************************/

void            InitDirec(char d[64][64])
{
    int             ini,
                    fin;

    for (ini = 0; ini < 64; ini++)
        for (fin = 0; fin < 64; fin++) {
            if (fin == ini)
                d[ini][fin] = 0;
            else if (ini % 8 == fin % 8) {
                if (ini < fin)
                    d[ini][fin] = 4;
                else
                    d[ini][fin] = 8;
            } else if (ini / 8 == fin / 8) {
                if (ini < fin)
                    d[ini][fin] = 2;
                else
                    d[ini][fin] = 6;
            } else if (ini / 8 + ini % 8 == fin / 8 + fin % 8) {
                if (ini < fin)
                    d[ini][fin] = 5;
                else
                    d[ini][fin] = 1;
            } else if (ini / 8 - ini % 8 == fin / 8 - fin % 8) {
                if (ini < fin)
                    d[ini][fin] = 3;
                else
                    d[ini][fin] = 7;
            } else
                d[ini][fin] = 0;
        }
}

/************************************************************************************
 *                                                                                  *
 *    Las siguientes funciones inicializan las tablas que van a ser utilizadas para *
 *    calcular las casillas que ataca una determinada ficha en cualquier momento    *
 *    de la partida ( un 1 indica casilla atacada y un 0 no atacada):                                                                *
 *                                                                                  *
 *    - fichas no deslizantes: rey y caballo. Sencillamente se determinan las casi- *
 *    llas que atacan desde cualquier posición del tablero para su posterior con-   *
 *    sulta.                                                                        *
 *                                                                                  *
 *    - fichas deslizantes: indexadas por posición y estado de fila columna o dia-  *
 *      gonal (casillas ocupadas=1, vacías=0).                                      *
 *                                                                                  *
 *    Una vez calculada la información de TORRE_FILA se recicla para la de las co-  *
 *    lumnas y diagonales, así como para calcular los movimientos del rey. Quiere   *
 *    decir esto que debe ser llamada primero antes que las otras, con la excepción *
 *    del CABALLO que es independiente del resto. Da como resultado un código más   *
 *    compacto pero un poco más complejo de entender.                               *
 *                                                                                  *
 ************************************************************************************/

void            InitAtqTorreFil(register entero64 vect[64][256])
{
    register unsigned char postab,
                    estfil,
                    posfila,
                    aux;
    register int    j;

    for (postab = 0; postab < 64; postab++) {   // para cada casilla del
        // tablero
        posfila = 1 << (postab % 8);    // posición de la torre en la fila

        for (j = 0; j < 256; j++) {     // para cada estado posible dentro
            // //   de la fila:  0x00 ... 0xff.
            estfil = j;
            aux = posfila;

            vect[postab][estfil] = 0;

            // se recorre la fila desde la casilla de la torre en las dos
            // direcciones
            // posibles añadiendo cada casilla vacía al vector de atacadas
            // hasta que
            // se acabe la fila o nos estampemos con una ficha (que también
            // se añade).

            while (!((aux <<= 1) & estfil) && (aux != 0))
                vect[postab][estfil] |= aux;

            vect[postab][estfil] |= aux;
            aux = posfila;

            while (!((aux >>= 1) & estfil) && (aux != 0))
                vect[postab][estfil] |= aux;

            vect[postab][estfil] |= aux;

            // finalmente colocamos la información que estaba siendo
            // fabricada en una
            // fila "abstracta", por así decirlo en su posición definitiva
            // dentro del
            // tablero.

            vect[postab][estfil] <<= 8 * ((postab) / 8);
        }
    }
    return;
}

//----------------------------------------------------------------------

void            InitAtqTorreCol(register entero64 vect[64][256],
                                         register entero64 vectfil[64][256])
{
    register unsigned char postab;
    register int    i,
                    j;

    for (postab = 0; postab < 64; postab++) {
        for (j = 0; j < 256; j++) {
            vect[postab][j] = 0;
            for (i = 0; i < 8; i++)
                vect[postab][j] |= ((entero64) (vectfil[postab / 8][j] &
                                MASK[i] ? 1 : 0)) << (postab % 8 + (8 * i));
        }
    }
    return;
}

//------------------------------------------------------------------------

void            InitAtqAlfil315(register entero64 vect[64][256],
                                         register entero64 vectfil[64][256])
{
    register unsigned char postab,
                    inidiag;
    register int    i,
                    j;
    unsigned char   long_NO_SE[64] =
    {8, 7, 6, 5, 4, 3, 2, 1,    // array que indica la longitud
        7, 8, 7, 6, 5, 4, 3, 2, // de cada diagonal a 315º.
        6, 7, 8, 7, 6, 5, 4, 3, // (determina los bits válidos a
        5, 6, 7, 8, 7, 6, 5, 4, // la hora de indexar)
        4, 5, 6, 7, 8, 7, 6, 5,
        3, 4, 5, 6, 7, 8, 7, 6,
        2, 3, 4, 5, 6, 7, 8, 7,
    1, 2, 3, 4, 5, 6, 7, 8};

    for (postab = 0; postab < 64; postab++) {
        for (j = 0; j < 256; j++) {
            for (inidiag = postab; ((inidiag % 8) != 0) && ((inidiag / 8) != 0);
                 inidiag -= 9);

            vect[postab][j] = 0;

            for (i = 0; i < long_NO_SE[postab]; i++)
                vect[postab][j] |=
                    ((entero64) (vectfil[(postab - inidiag) / 9][j] &
                                 MASK[i] ? 1 : 0)) << (inidiag + i * 9);
        }
    }
    return;
}

//-----------------------------------------------------------------------

void            InitAtqAlfil45(register entero64 vect[64][256],
                                         register entero64 vectfil[64][256])
{
    register unsigned char postab,
                    inidiag;
    register int    i,
                    j;
    unsigned char   long_NE_SO[64] =
    {1, 2, 3, 4, 5, 6, 7, 8,    // array que indica la longitud
        2, 3, 4, 5, 6, 7, 8, 7, // de las diagonales a 45º.
        3, 4, 5, 6, 7, 8, 7, 6,
        4, 5, 6, 7, 8, 7, 6, 5,
        5, 6, 7, 8, 7, 6, 5, 4,
        6, 7, 8, 7, 6, 5, 4, 3,
        7, 8, 7, 6, 5, 4, 3, 2,
    8, 7, 6, 5, 4, 3, 2, 1};

    for (postab = 0; postab < 64; postab++) {
        for (j = 0; j < 256; j++) {
            for (inidiag = postab; ((inidiag % 8) != 7) && ((inidiag / 8) != 0);
                 inidiag -= 7);

            vect[postab][j] = 0;

            for (i = 0; i < long_NE_SO[postab]; i++)
                vect[postab][j] |=
                    ((entero64) (vectfil[(postab - inidiag) / 7][j] &
                                 MASK[i] ? 1 : 0)) << (inidiag + i * 7);
        }
    }
    return;
}

//-----------------------------------------------------------------------

void            InitAtqCaballo(register entero64 vect[64])
{
    int             caball[8] = {-17, -15, -6, 10, 17, 15, 6, -10};     // los ocho saltos del
    // caballo
    register int    i,
                    postab,
                    posataq;

    for (postab = 0; postab < 64; postab++) {   // para cada posición en el
        // tablero...
        vect[postab] = 0;
        for (i = 0; i < 8; i++) {       // para cada salto...
            posataq = postab + caball[i];

            if ((posataq >= 0) && (posataq < 64)) {     // se prueba y si cae
                // dentro
                // //   del tablero se
                // añade al
                if (Distancia(postab, posataq) < 3)     // vector de ataques.
                    vect[postab] |= MASK[posataq];
            }
        }
    }
    return;
}
//-----------------------------------------------------------------------

void            InitAtqRey(entero64 vect[64], entero64 v1[64][256], entero64 v2[64][256],
                                 entero64 v3[64][256], entero64 v4[64][256])
{
    int             i;

    // aquí usamos un pequeño truco: las tablas anteriores de torres y
    // alfiles
    // en una fila, columna o diagonal repleta de fichas reducen el área de
    // influen-
    // cia a las casillas adyacentes a la de la torre o alfil en cuestión, lo
    // que
    // combinado entre sí produce los movimientos del rey.

    for (i = 0; i < 64; i++)
        vect[i] = v1[i][255] | v2[i][255] | v3[i][255] | v4[i][255];
    return;
}

//-----------------------------------------------------------------------
void            InitAtqPeones(entero64 peonB[64], entero64 peonN[64])
{
    int             i;
    for (i = 0; i < 64; i++) {
        peonB[i] = ATAQUES_TORRE_FIL[i][255] >> 8;
        peonN[i] = ATAQUES_TORRE_FIL[i][255] << 8;
    }
}
//-----------------------------------------------------------------------
void            InitTaxiCab(char tabla[64][64])
{
    int             i,
                    j;
    for (i = 0; i < 64; i++)
        for (j = 0; j < 64; j++) {
            tabla[i][j] = Abs(MOD8(i) - MOD8(j)) + DIV8(Abs((i) - (j)));
            DISTANCIA[i][j] = Distancia(i, j);
        }
}
//-----------------------------------------------------------------------
void            InitValores()
{
    tab.pos.pos_piezas = (entero64 *) malloc(sizeof(entero64) * 13);
//  tab.pos.pos_piezas -= 1; /* This is a violation of the language standard.
// Therefore, we allocate an extra element instead.
}
