/* Pepito v1.59  -- file: fen.c --
   Copyright (c) 2000-2 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"
#  include <string.h>
#endif

#define ERROR              0
#define BIEN               1
#define EOLN               2

int             LeeTablero(char *, posicion *);
int             LeeTurno(char *cad, posicion * ptrpos);
int             LeeEnroque(char *cad, posicion * ptrpos);
int             LeeAlPaso(char *cad);
int             LeeMejorJug(nodo_jug ** ptrjug, char **resto_linea);
int             LeePV(nodo_jug ** ptrjug, char **resto_linea);


//----------------------------------------------------
void            FreeMoveList(nodo_jug *pl)
{
    nodo_jug *pkill;

    while (pl)
    {
        pkill = pl;
        pl = pl->sig;
        free(pkill);
    }
}
//----------------------------------------------------
int             TestEPD(FILE ** ppfich)
{
    int             i = 0,
                    j,
                    total,
                    resuelto,
                    pinta;
    char            linea[512];
    epd_info        pos_info;
    nodo_jug       *paux;
    FILE           *fich_test;
    entero32        juga;
    int             desde,
                    hacia,
                    mtiempo;
    entero32        mytime;

    if ((fich_test = fopen("fallos.epd", "w")) == NULL) {
        Print("error fopen");
        exit(1);
    }
    Print("Tiempo por problema (segs) ? ");
    ReadString(entrada);
    mtiempo = atoi(entrada);
    pinta = (int) (mtiempo > 10);
    xb_info.post = 1;
    total = 0;
    Enroque = 0;
    xb_info.my_clock = 0;
    mytime = mtiempo;
    mytime *= 100;

    Print("CONTROL_IN %d\n", CONTROL_INC);
    Print("\n");

    while (LeeLinea(ppfich, linea, 512) && !FullInput()) {
        if (LeeEPD(linea, &pos_info)) {
            resuelto = 0;
            if (pinta)
                PintaTablero();
            if (!VerificaTab(Turno)) {
                Print("Error al inicializar posición.\n");
                exit(1);
            }
            tab.book_retry = 0;

            for (j = 0; j < 4096; j++)
            {
               tab.history[j][0] = 0;
               tab.history[j][1] = 0;
            }
            memset(tab.trans_tab_p, 0, PAWN_HASH_SIZE * sizeof(entrada_hash_p));

            for (j = 0; j < MAX_PROF; j++) {
                memset(tab.killer[j], 0, 2 * sizeof(killer_type));
            }

            memset(tab.trans_tab, 0, HASH_SIZE * sizeof(entrada_hash));
            memset(tab.eval_cache, 0, CACHE_SIZE * sizeof(ecache));

            PreProcesa();
            GeneraValidas(0);
            Itera(&juga, 1, mytime, NULL);

            while (pos_info.bm != NULL) {
                paux = pos_info.bm;
                pos_info.bm = pos_info.bm->sig;

                if ((paux->jug & 0xfff) == (pv[0][0].jug & 0xfff))
                    resuelto = 1;
                else {
                    desde = paux->jug & 0x3f;
                    hacia = (paux->jug >> 6) & 0x3f;
                    Print("La jugada correcta era: %c%d-%c%d\n", 'a' + (desde & 7), 8 - (desde >> 3),
                          'a' + (hacia & 7), 8 - (hacia >> 3));
                }
                free(paux);
            }

            FreeMoveList(pos_info.pv);

            if (resuelto)
                total++;
            else {
                fprintf(fich_test, "%s\n", linea);
            }
            Print("Voy por el problema %d. Resueltos:%4d\n", i + 1, total);
            i++;

        }
    }

    fprintf(fich_test, "\nTOTAL %d/%d.\n", total, i);

    fclose(*ppfich);
    fclose(fich_test);
    xb_info.force = 1;
    Print("\n");

    return BIEN;
}

//-----------------------------------------------------------
int             LeeEPD(char *linea, epd_info *info)
{
    char            palabra[500],
                   *pos_cad;
    posicion       *posptr = &tab.pos;

    posptr->pos_status = 0;
    pos_cad = linea;

    if (!ExtraeArg(&pos_cad, palabra) || !LeeTablero(palabra, posptr) ||
        !ExtraeArg(&pos_cad, palabra) || !LeeTurno(palabra, posptr)   ||
        !ExtraeArg(&pos_cad, palabra) || !LeeEnroque(palabra, posptr) ||
        !ExtraeArg(&pos_cad, palabra) || !LeeAlPaso(palabra))
        return 0;

    InitPos(0);

    if (info)
    {
        info->bm = NULL;
        info->pv = NULL;

        while (ExtraeArg(&pos_cad, palabra)) {

           if (!strcmp("bm",  palabra))
               LeeMejorJug(&info->bm, &pos_cad);
           else if (!strcmp("ce",  palabra))
           {
               if (ExtraeArg(&pos_cad,palabra))
                 sscanf(palabra, "%d", &info->ce);
           }
           else if (!strcmp("acd", palabra))
           {
               if (ExtraeArg(&pos_cad,palabra))
                 sscanf(palabra, "%d", &info->acd);
           }
           else if (!strcmp("pv", palabra))
               LeePV(&info->pv, &pos_cad);
        }
    }

    return 1;
}

//--------------------------------------------------------
int             LeeTablero(char *pos_cad, posicion * posptr)
{
    int             fil,
                    col,
                    aux;

    for (fil = 0; fil < 64; fil++)
        posptr->tab[fil] = VACIA;


    for (fil = 0; fil < 8; fil++, pos_cad++) {
        col = 0;
        for (; *pos_cad != '/' && *pos_cad != '\0'; pos_cad++) {
            if (*pos_cad - '0' < 9 && *pos_cad - '0' > 0) {
                if (col + *pos_cad - '0' > 8)
                    return ERROR;
                for (aux = *pos_cad - '0'; aux; aux--)  // añadimos el número
                                                        // que se indique
                    posptr->tab[8 * fil + col++] = VACIA;       // de casillas vacías.
            } else {
                switch (*pos_cad) {
                case 'Q':
                    posptr->tab[8 * fil + col++] = DAMA_B;
                    break;
                case 'q':
                    posptr->tab[8 * fil + col++] = DAMA_N;
                    break;
                case 'R':
                    posptr->tab[8 * fil + col++] = TORRE_B;
                    break;
                case 'r':
                    posptr->tab[8 * fil + col++] = TORRE_N;
                    break;
                case 'B':
                    posptr->tab[8 * fil + col++] = ALFIL_B;
                    break;
                case 'b':
                    posptr->tab[8 * fil + col++] = ALFIL_N;
                    break;
                case 'N':
                    posptr->tab[8 * fil + col++] = CABALLO_B;
                    break;
                case 'n':
                    posptr->tab[8 * fil + col++] = CABALLO_N;
                    break;
                case 'P':
                    posptr->tab[8 * fil + col++] = PEON_B;
                    break;
                case 'p':
                    posptr->tab[8 * fil + col++] = PEON_N;
                    break;
                case 'K':
                    posptr->tab[8 * fil + col++] = REY_B;
                    break;
                case 'k':
                    posptr->tab[8 * fil + col++] = REY_N;
                    break;
                default:
                    return ERROR;
                    break;
                }               // switch
            }

            if (col > 8)
                return ERROR;
        }

        while (col < 8)         // si se ha acabado de especificar la fila y
                                // no se han
            posptr->tab[8 * fil + col++] = VACIA;       // llenado las 8
                                                        // casillas, el resto
                                                        // están vacías.
    }
    return BIEN;
}

//-----------------------------------------------------------
int             LeeTurno(char *cad, posicion * ptrpos)
{
    if (!strcmp(cad, "w")) {
        ptrpos->turno = 1;
        return BIEN;
    } else if (!strcmp(cad, "b")) {
        ptrpos->turno = 0;
        return BIEN;
    } else
        return ERROR;
}
//------------------------------------------------------------
int             LeeEnroque(char *cad, posicion * posptr)
{
    if (!strcmp(cad, "-"))
        return BIEN;

    for (; *cad != '\0'; cad++) {       // DERECHOS DE ENROQUE
        switch (*cad) {
        case 'K':
            posptr->pos_status |= E_CORTO_B;
            break;
        case 'Q':
            posptr->pos_status |= E_LARGO_B;
            break;
        case 'k':
            posptr->pos_status |= E_CORTO_N;
            break;
        case 'q':
            posptr->pos_status |= E_LARGO_N;
            break;
        default:
            Print("ayayayay!!!\n");
            return ERROR;
        }
    }
    return BIEN;
}
//-----------------------------------------------------------
int             LeeAlPaso(char *cad)
{
    int             aux = 0;
    AlPaso = 64;

    if (!strcmp(cad, "-"))
        return BIEN;

    if (strlen(cad) == 2) {
        if (*cad >= 'a' && *cad <= 'h')
            aux = *cad - 'a';
        else
            return ERROR;
        if (*(cad + 1) >= '1' && *(cad + 1) <= '8')
            aux += (8 - (*(cad + 1) - '0')) * 8;
        else
            return ERROR;

        if (Turno)
        {
          if (aux & 7 && Tablero[aux+7] == PEON_B)
            AlPaso = aux;
          else if ((aux & 7) != 7 &&Tablero[aux+9] == PEON_B) 
            AlPaso = aux;
        }
        else
        {
          if (aux & 7 && Tablero[aux-9] == PEON_N)
            AlPaso = aux;
          else if ((aux & 7) != 7 &&Tablero[aux-7] == PEON_N) 
            AlPaso = aux;
        }
    } else
        return ERROR;

    return BIEN;
}
//--------------------------------------------------------------
int             LeeMejorJug(nodo_jug ** ptrjug, char **resto_linea)
{

    nodo_jug       *pjaux;
    char           cad[256];
    int            len, no_pcoma = 1;


    *ptrjug = NULL;

    for (; no_pcoma && ExtraeArg(resto_linea, cad);) {

        pjaux = (nodo_jug *) malloc(sizeof(nodo_jug));

        len = strlen(cad)-1;
        if (cad[len] == ';')
        {
            cad[len] = 0;
            no_pcoma = 0;
        }

        if (LeeJugada(cad, &(pjaux->jug))) {
            pjaux->sig = *ptrjug;
            *ptrjug = pjaux;
        } else {
            free(pjaux);
            return ERROR;
        }
    }
    if (*ptrjug == NULL)
        return ERROR;
    else {
        return BIEN;
    }
}
//--------------------------------------------------------------
int             LeePV(nodo_jug ** ptrjug, char **resto_linea)
{

    nodo_jug       *pjaux;
    nodo_jug       *cola = NULL;
    char           cad[256];
    int            len, no_pcoma = 1;

    *ptrjug = NULL;

    for (; no_pcoma && ExtraeArg(resto_linea, cad);) {

        pjaux = (nodo_jug *) malloc(sizeof(nodo_jug));

        len = strlen(cad)-1;

        if (cad[len] == ';')
        {
            cad[len] = 0;
            no_pcoma = 0;
        }

        if (LeeJugada(cad, &(pjaux->jug))) {

            pjaux->sig = NULL;

            if (cola)
                cola->sig = pjaux;
            else
                *ptrjug = pjaux;

            cola = pjaux;
            Mueve(pjaux->jug);
            CambiaTurno();
        } else {

            while (*ptrjug)
            {
                CambiaTurno();
                DesMueve();
                *ptrjug = (*ptrjug)->sig;
            }

            free(pjaux);
            return ERROR;
        }
    }

    pjaux = *ptrjug;

    while (pjaux)
    {
        CambiaTurno();
        DesMueve();
        pjaux = pjaux->sig;
    }

    return *ptrjug == NULL ? ERROR : BIEN;
}
//--------------------------------------------------------------
int             LeeLinea(FILE ** fich, char *linea, int length)
{
    int             letra,
                    i = 0;

    if ((letra = fgetc(*fich)) == EOF)
        return ERROR;
    else
        ungetc(letra, *fich);

    while ((letra = fgetc(*fich)) != EOF && letra != '\n') {
        if ((char) letra != '\r')
            linea[i++] = letra;
        if (i == length) {
            Print("Error!!! (Line exceeds maximum legnth)\n");
            return 0;
        }
    }

    linea[i] = 0;
    return BIEN;
}
//---------------------------------------------------------------------------------*/
#define BORDE     "\n    +----+----+----+----+----+----+----+----+\n"
#define BORDE_INF "      a    b    c    d    e    f    g    h  \n"

void            PintaTablero()
{
    register int    i, pz, cpz;

    Print(BORDE);
    for (i = 0; i < 64; i++) {
        if (!(i & 7))
            Print(" %d  ", (63 - i) / 8 + 1);

        cpz = pz = Tablero[i];

        if (pz > 6)
            pz -= 6;

        if (cpz)
          Print("| %c%c ", cpz > 6 ? '*' : ' ',  piece_rep[pz-1]);
        else
          Print("|    ");

        if (!((i & 7) ^ 7)) {
            Print("|");
            Print(BORDE);
            if (i == 63)
                Print(BORDE_INF);
        }
    }
    Print("\n");
}
//---------------------------------------------------------
#define VuelcaVacias          if (vacias)                              \
                                fprintf(pfich, "%d",vacias);         \
                              vacias = 0

int             OutFEN(char *nombre)
{
    int             i,
                    vacias = 0;
    FILE           *pfich;

    pfich = fopen(nombre, "a");

    if (pfich == NULL)
        return 0;

    fprintf(pfich, "\n");

    for (i = 0; i < 64; i++) {
        switch (Tablero[i]) {
        case VACIA:
            vacias++;
            break;
        case PEON_B:
            VuelcaVacias;
            fprintf(pfich, "P");
            break;
        case PEON_N:
            VuelcaVacias;
            fprintf(pfich, "p");
            break;
        case CABALLO_B:
            VuelcaVacias;
            fprintf(pfich, "N");
            break;
        case CABALLO_N:
            VuelcaVacias;
            fprintf(pfich, "n");
            break;
        case ALFIL_B:
            VuelcaVacias;
            fprintf(pfich, "B");
            break;
        case ALFIL_N:
            VuelcaVacias;
            fprintf(pfich, "b");
            break;
        case TORRE_B:
            VuelcaVacias;
            fprintf(pfich, "R");
            break;
        case TORRE_N:
            VuelcaVacias;
            fprintf(pfich, "r");
            break;
        case DAMA_B:
            VuelcaVacias;
            fprintf(pfich, "Q");
            break;
        case DAMA_N:
            VuelcaVacias;
            fprintf(pfich, "q");
            break;
        case REY_B:
            VuelcaVacias;
            fprintf(pfich, "K");
            break;
        case REY_N:
            VuelcaVacias;
            fprintf(pfich, "k");
            break;
        default:
            break;
        }
        if (i && !((i + 1) & 7)) {
            VuelcaVacias;
            if (i < 63)
                fprintf(pfich, "/");
        }
    }

    fprintf(pfich, " %c ", Turno ? 'w' : 'b');
    if (Enroque & 0xf) {
        if (Enroque & E_CORTO_B)
            fprintf(pfich, "K");
        if (Enroque & E_LARGO_B)
            fprintf(pfich, "Q");
        if (Enroque & E_CORTO_N)
            fprintf(pfich, "k");
        if (Enroque & E_LARGO_N)
            fprintf(pfich, "q");
    } else
        fprintf(pfich, "-");

    if (AlPaso != 64)
        fprintf(pfich, " %c%d", 'a' + (AlPaso & 7), 8 - (AlPaso >> 3));
    else
        fprintf(pfich, " -");

    fclose(pfich);
    return (1);
}
