/* Pepito v1.59  -- file: input.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
*/

// lee y verifica la validez de una jugada introducida por teclado

#ifdef LINUX
#include <stdarg.h>
#include <string.h>
#include <sys/time.h>
#endif

#ifndef UNIQUE_SOURCE_FILE
#   include "datos.h"
#   ifndef LINUX
#      include <windows.h>
#      include <winbase.h>
#      include <wincon.h>
#      include <io.h>
#      include <time.h>
#   else
#      include <sys/time.h>
#   endif
#   include <string.h>
#   include <stdarg.h>
#endif

#ifdef LINUX
#	define _read(a,b,c)  read(a,b,c)
#       define Sleep(a) milisleep(a)

static          milisleep(unsigned long t)
{
    struct timespec aux;

    aux.tv_sec = 0;
    aux.tv_nsec = t * 1000 * 1000;

    nanosleep(&aux, NULL);
}
#endif


int             LeeJugada(char *linea, entero32 * ptrjug)
{
    char           *pos_cad;
    int             cas_ini = 0,
                    cas_fin = 0,
                    jug_validas = 0,
                    temp;
    entero64        mapa_origen = 0,
                    Vacias = ~(Blancas | Negras);
    entero32        jug_temp;

    for (pos_cad = linea; *pos_cad != '\0'; pos_cad++);

    while((*(--pos_cad) < '0' || *pos_cad > '9') && pos_cad > linea)
        ;

    if (*(pos_cad + 1) == '=') {
        *(pos_cad+1) = *(pos_cad + 2);
        *(pos_cad+2) = '\0';
    }

    if (pos_cad > linea)
        pos_cad--;

    if ((!strcmp(linea, "e1g1") && Tablero[E1] == REY_B) ||
        (!strcmp(linea, "e8g8") && Tablero[E8] == REY_N))
        goto CORTO;
    else if ((!strcmp(linea, "e1c1") && Tablero[E1] == REY_B) ||
             (!strcmp(linea, "e8c8") && Tablero[E8] == REY_N))
        goto LARGO;

    if (*pos_cad >= 'a' && *pos_cad <= 'h' && *(pos_cad + 1) >= '1' && *(pos_cad + 1) <= '8') { // si se especifica
        // // casilla de destino
        cas_fin = *pos_cad - 'a' + (8 - (*(pos_cad + 1) - '0')) * 8;
        if (MASK[cas_fin] & (Turno ? Blancas : Negras))
            return 0;

        while (*linea == '.')
            linea++;

        switch (*linea) {
        case 'K':
            if (Turno) {
                if (!(AtaquesHacia(cas_fin) & Negras))
                    mapa_origen = AtaquesRey(cas_fin) & ReyB;
            } else if (!(AtaquesHacia(cas_fin) & Blancas))
                mapa_origen = AtaquesRey(cas_fin) & ReyN;
            break;

        case 'Q':
            if (Turno)
                mapa_origen = AtaquesDama(cas_fin) & DamasB;
            else
                mapa_origen = AtaquesDama(cas_fin) & DamasN;
            break;

        case 'R':
            if (Turno)
                mapa_origen = AtaquesTorre(cas_fin) & TorresB;
            else
                mapa_origen = AtaquesTorre(cas_fin) & TorresN;
            break;

        case 'N':
            if (Turno)
                mapa_origen = AtaquesCaballo(cas_fin) & CaballosB;
            else
                mapa_origen = AtaquesCaballo(cas_fin) & CaballosN;

            break;
        case 'B':
            if (Turno)
                mapa_origen = AtaquesAlfil(cas_fin) & AlfilesB;
            else
                mapa_origen = AtaquesAlfil(cas_fin) & AlfilesN;

            break;

        default:
            if (*linea >= 'a' && *linea <= 'h' && *(linea + 1) >= '1' && *(linea + 1) <= '8') {
                cas_ini = *linea - 'a' + (8 - (*(linea + 1) - '0')) * 8;
                if (cas_ini == cas_fin) {       // notación reducida de peón
                    cas_ini = 64;
                    if (Turno) {
                        if ((MASK[cas_fin] << 8) & PeonesB && MASK[cas_fin] & Vacias) { // avanza una
                            cas_ini = cas_fin + 8;
                            jug_validas++;
                        } else if (DIV8(cas_fin) == 4 && (MASK[cas_fin] & Vacias) &&
                                   ((MASK[cas_fin] << 16) & PeonesB)) {
                            cas_ini = cas_fin + 16;
                            jug_validas++;
                        }
                    } else {
                        if ((MASK[cas_fin] >> 8) & PeonesN && MASK[cas_fin] & Vacias) {
                            cas_ini = cas_fin - 8;
                            jug_validas++;
                        } else if (DIV8(cas_fin) == 3 && (MASK[cas_fin] & Vacias) &&
                                   ((MASK[cas_fin] >> 16) & PeonesN)) {
                            cas_ini = cas_fin - 16;
                            jug_validas++;
                        }
                    }
                    mapa_origen = MASK[cas_ini];
                } else {
                    // -----  ALGEBRAICA EXTENDIDA y captura de peones  ---

                    mapa_origen = AtaquesHacia(cas_fin) & MASK[cas_ini];

                    switch (Tablero[cas_ini]) {
                    case PEON_N:
                        if (cas_fin == cas_ini + 8) {
                            if (MASK[cas_fin] && Vacias)
                                mapa_origen = MASK[cas_ini];
                        } else if (cas_fin == cas_ini + 16) {
                            if (cas_ini < A6 && MASK[cas_fin] & Vacias &&
                                MASK[cas_ini + 8] & Vacias)
                                mapa_origen = MASK[cas_ini];
                        } else if (cas_fin != AlPaso && MASK[cas_fin] & Vacias)
                            mapa_origen = 0;
                        break;
                    case PEON_B:
                        if (cas_fin == cas_ini - 8) {
                            if (MASK[cas_fin] && Vacias)
                                mapa_origen = MASK[cas_ini];
                        } else if (cas_fin == cas_ini - 16) {
                            if (cas_ini >= A2 && MASK[cas_fin] & Vacias &&
                                MASK[cas_ini - 8] & Vacias)
                                mapa_origen = MASK[cas_ini];
                        } else if (cas_fin != AlPaso && MASK[cas_fin] & Vacias)
                            mapa_origen = 0;
                        break;
                    }
                }

            } else if (*linea >= 'a' && *linea <= 'h' && *(linea + 1) == 'x') {
                mapa_origen = COLUMNA[*linea - 'a'] & (Turno ? PeonesB : PeonesN) &
                    AtaquesAlfil(cas_fin) & (Turno ? MASK[cas_fin + 7] | MASK[cas_fin + 9] :
                                     MASK[cas_fin - 7] | MASK[cas_fin - 9]);
            }
            break;
        }

        if (*(linea + 1) != *pos_cad || *(linea + 2) != *(pos_cad + 1)) {
            if (*(linea + 2) >= '1' && *(linea + 2) <= '8')
                mapa_origen &= FILA[8 - *(linea + 2) + '0'];
            if (*(linea + 1) >= 'a' && *(linea + 1) <= 'h')
                mapa_origen &= COLUMNA[*(linea + 1) - 'a'];
            else if (*(linea + 1) >= '1' && *(linea + 1) <= '8')
                mapa_origen &= FILA[8 - *(linea + 1) + '0'];
        }
        while (mapa_origen) {
            temp = Msb(mapa_origen);

            if ((Turno && MASK[temp] & Blancas) ||
                (!Turno && MASK[temp] & Negras)
                ) {
                jug_temp = temp | (cas_fin << 6) | (Tablero[cas_fin] << 12);
                if (Tablero[temp] == PEON_B) {
                    if (cas_fin < 8) {
                        jug_temp |= (DAMA_B << 16);
                    }
                    if (cas_fin == AlPaso)
                        jug_temp |= ((PEON_N + 0x100) << 12);
                } else if (Tablero[temp] == PEON_N) {
                    if (cas_fin == AlPaso)
                        jug_temp |= ((PEON_B + 0x100) << 12);
                }
                Mueve(jug_temp);

                if (!Jaque(Turno)) {
                    jug_validas++;
                    cas_ini = temp;
                }
                DesMueve();
            }
            mapa_origen ^= MASK[temp];
        }

        if (jug_validas) {      // si se ha especificado alguna jugada válida

            if (jug_validas == 1) {     // si la jugada está perfectamente
                // definida
                *ptrjug = cas_ini | (cas_fin << 6) | (Tablero[cas_fin] << 12);
                if (VALOR[Tablero[cas_ini]] == PEON_VAL) {
                    if (cas_fin == AlPaso)
                        *ptrjug |= ((Turno ? PEON_N : PEON_B) + 0x100) << 12;
                    if (MASK[cas_fin] & (entero64) 0xff000000000000ff) {
                        int             promocion;
                        switch (*(pos_cad + 2)) {
                        case 'N':
                        case 'n':
                            promocion = CABALLO_N - 6 * Turno;
                            break;
                        case 'B':
                        case 'b':
                            promocion = ALFIL_N - 6 * Turno;
                            break;
                        case 'R':
                        case 'r':
                            promocion = TORRE_N - 6 * Turno;
                            break;
                        default:
                            promocion = DAMA_N - 6 * Turno;
                        }
                        *ptrjug |= (promocion << 16);
                    }
                    if (cas_fin == cas_ini + (Turno ? -16 : 16))
                        *ptrjug |= PEON_DE_2;
                }
            } else {
                Print("Debe especificar la posición de origen.\n");
                jug_validas = 0;
            }
        }                       // si hay jugadas válidas
    }                           // si se especifica casilla de destino
    else {
        if (!strcmp(linea, "O-O") || !strcmp(linea, "O-O+") || !strcmp(linea, "O-O#")) {
    CORTO:
            if (Turno) {
                if (Enroque & E_CORTO_B && Vacias & MASK[F1] && Vacias & MASK[G1] &&
                    !(Negras & AtaquesHacia(F1)) && !(Negras & AtaquesHacia(G1))) {
                    *ptrjug = E1 | (G1 << 6) | 0x200000;
                    jug_validas = 1;
                }
            } else {
                if (Enroque & E_CORTO_N && Vacias & MASK[F8] && Vacias & MASK[G8] &&
                    !(Blancas & AtaquesHacia(F8)) && !(Blancas & AtaquesHacia(G8))) {
                    *ptrjug = E8 | (G8 << 6) | 0x200000;
                    jug_validas = 1;
                }
            }
        } else if (!strcmp(linea, "O-O-O") || !strcmp(linea, "O-O-O+") || !strcmp(linea, "O-O-O#")) {
    LARGO:
            if (Turno) {
                if (Enroque & E_LARGO_B && Vacias & MASK[C1] && Vacias & MASK[D1] &&
                    !(Negras & AtaquesHacia(C1)) && !(Negras & AtaquesHacia(D1))) {
                    *ptrjug = E1 | (C1 << 6) | 0x400000;
                    jug_validas = 1;
                }
            } else {
                if (Enroque & E_LARGO_N && Vacias & MASK[C8] && Vacias & MASK[D8] &&
                    !(Blancas & AtaquesHacia(C8)) && !(Blancas & AtaquesHacia(D8))) {
                    *ptrjug = E8 | (C8 << 6) | 0x400000;
                    jug_validas = 1;
                }
            }
        }
    }

    return jug_validas;
}

//------------------------------------------------------------------------------
int             MatchesPonderMove(char *linea)
{
    int             l = strlen(linea),
                    cas_fin;
    char           *pos_cad;

    if ((!strcmp(linea, "O-O-O") || !strcmp(linea, "e1c1") || !strcmp(linea, "e8c8"))
        && tab.ponder_mv.jug & ENROQUE_LARGO)
        return 1;

    if ((!strcmp(linea, "O-O") || !strcmp(linea, "e1g1") || !strcmp(linea, "e8g8"))
        && tab.ponder_mv.jug & ENROQUE_CORTO)
        return 1;

    for (pos_cad = linea; *pos_cad != '\0'; pos_cad++);

    if (*(pos_cad - 2) > '0' && *(pos_cad - 2) < '9')
        pos_cad--;

    if (*(pos_cad - 2) == '=' && pos_cad - 2 > linea) {
        pos_cad -= 2;
        *pos_cad = *(pos_cad + 1);
        *(pos_cad + 1) = '\0';
    } else if (*(pos_cad - 3) == '=' && pos_cad - 3 > linea) {
        pos_cad -= 3;
        *pos_cad = *(pos_cad + 1);
        *(pos_cad + 1) = '\0';
    }
    pos_cad -= 2;
    if (*pos_cad >= 'a' && *pos_cad <= 'h' && *(pos_cad + 1) >= '1' && *(pos_cad + 1) <= '8') {
        cas_fin = *pos_cad - 'a' + (8 - (*(pos_cad + 1) - '0')) * 8;
        if ((cas_fin << 6) ^ (tab.ponder_mv.jug & 0xfc0))
            return 0;
        switch (*linea) {
        case 'K':
            if (tab.ponder_mv.pieza_mov == REY_B || tab.ponder_mv.pieza_mov == REY_N)
                return 1;
            break;
        case 'Q':
            if (tab.ponder_mv.pieza_mov == DAMA_B || tab.ponder_mv.pieza_mov == DAMA_N)
                return 1;
            break;
        case 'N':
            if (tab.ponder_mv.pieza_mov == CABALLO_B || tab.ponder_mv.pieza_mov == CABALLO_N)
                return 1;
            break;
        case 'B':
            if (tab.ponder_mv.pieza_mov == ALFIL_B || tab.ponder_mv.pieza_mov == ALFIL_N)
                return 1;
            break;
        default:
            switch (l) {
            case 2:
                if ((tab.ponder_mv.pieza_mov == PEON_B || tab.ponder_mv.pieza_mov == PEON_N)
                    && !(tab.ponder_mv.jug & CAPTURA))
                    return 1;
                return 0;
            case 4:
                if ((*linea + 1) == 'x' && (tab.ponder_mv.pieza_mov == PEON_B || tab.ponder_mv.pieza_mov == PEON_N)
                    && !(tab.ponder_mv.jug & CAPTURA))
                    return 1;
            case 5:
                if (*linea >= 'a' && *linea <= 'h' && *(linea + 1) >= '1' && *(linea + 1) <= '8') {
                    cas_fin = (*linea - 'a' + (8 - (*(linea + 1) - '0')) * 8);
                    if ((unsigned)cas_fin == (tab.ponder_mv.jug & 0x3f))
                        return 1;
                }
            default:
                return 0;
            }
        }
    }
    return 0;
}
//------------------------------------------------------------------------------
int             ExtraeArg(char **pcadena, char *palabra)
{
    int             i;

    while (**pcadena == ' ')
        *pcadena += 1;

    if (**pcadena == '\0')
        return 0;

    for (i = 0; **pcadena != ' ' && **pcadena != '\0'; *pcadena += 1, i++)
        *(palabra + i) = **pcadena;

    *(palabra + i) = '\0';

    return 1;
}
//----------------------------------------------------------
static char     ibuffer[4096] = {0};
static int      lbuffer = 0,
                blockinp = 0;
static char     linea[4096] = {0};
static char    *line_pointer = linea;

int             PollInput()
{
#ifdef LINUX
    static fd_set   readfds;
    struct timeval  tv;
    int             ret;

    FD_ZERO(&readfds);
    FD_SET(fileno(stdin), &readfds);
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    select(16, &readfds, NULL, NULL, &tv);
    ret = FD_ISSET(fileno(stdin), &readfds);
    return (ret);
#else
#include <conio.h>
    static int      init = 0,
                    pipe;
    static HANDLE   inh;
    static INPUT_RECORD Buffer[256];
    DWORD           dw=0;

    if (!init) {
        init = 1;
        inh = GetStdHandle(STD_INPUT_HANDLE);
        pipe = !GetConsoleMode(inh, &dw);
        if (!pipe) {
            SetConsoleMode(inh, dw & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
            FlushConsoleInputBuffer(inh);
        }
    }
    if (pipe) {
        if (!PeekNamedPipe(inh, NULL, 0, NULL, &dw, NULL))
            return 1;
        return dw;
    } else {
        GetNumberOfConsoleInputEvents(inh, &dw);
        return dw <= 1 ? 0 : dw;
    }
#endif
}

//--------------------------------------------------------------------------------
int             ReadStdin()
{
    int             n;

    if (!blockinp && !PollInput())
        return 0;
    n = _read(fileno(stdin), ibuffer + lbuffer, 4096 - lbuffer);
    // while (n<0);

    lbuffer += n;
    ibuffer[lbuffer] = '\0';
    return 1;
}
//--------------------------------------------------------------------------------
int             ReadInputLine(char *string)
{
    int             i,
                    j;

    if (batch_file)
    {
        if (fgets(string,4096,batch_file))
        {
            string[strlen(string)-1] = 0;
            return 1;
        }

        batch_file = NULL;
    }


    for (i = 0; ibuffer[i] != 0 && ibuffer[i] != '\n'; i++) {
        string[i] = ibuffer[i];
    }

    string[i] = 0;
    if (ibuffer[i])
        i++;
    else
        return 0;
    lbuffer -= i;

    for (j = 0; ibuffer[i]; j++, i++)
        ibuffer[j] = ibuffer[i];

    ibuffer[j] = 0;

    return 1;
}
//--------------------------------------------------------------------------------
int             FullInput()
{
    int             i = lbuffer - 1;

    while (i >= 0) {
        if (ibuffer[i--] == '\n')
            return 1;
    }

    ReadStdin();
    return 0;
}
//--------------------------------------------------------------------------------
void            ReadString(char *string)
{
    if ((char) *line_pointer && ExtraeArg(&line_pointer, string))
        return;

    blockinp = 1;
    if (!batch_file)
      while (!FullInput())
          Sleep(10);
    blockinp = 0;

    ReadInputLine(linea);
    Log("%s\n",linea);

    line_pointer = linea;
    *string = 0;
    ExtraeArg(&line_pointer, string);
}
//--------------------------------------------------------------------------------
void            ClearIbuffer()
{
    ibuffer[0] = 0;
    lbuffer = 0;
    linea[0] = 0;
    line_pointer = linea;
}
//--------------------------------------------------------------------------------
int             CountIArgs()
{
    int             n = 0;
    char           *lp = linea;
    char            tmp[80];

    while (ExtraeArg(&lp, tmp))
        n++;

    return n;
}
//--------------------------------------------------------------------------------
void            UnGetString()
{
    line_pointer = linea;
}
//--------------------------------------------------------------------------------
void            GetRestofInput(char *str)
{
    for (; *line_pointer; str++, line_pointer++)
        *str = *line_pointer;
    *str = 0;
}
//--------------------------------------------------------------------------------
void CDECL      Print(char *fmt,...)
{
    va_list         ap;
    va_start(ap, fmt);
    vprintf(fmt, ap);
    fflush(stdout);
    if (log_file) {
//        char s[512];
        vfprintf(log_file, fmt, ap);
/*
        vsprintf(s, fmt, ap);
        if (s[strlen(s)-1] == '\n')
            sprintf(s+strlen(s)-1," (%d)\n",clock());
        fputs(s,log_file);*/
        fflush(log_file);
    }
    va_end(ap);
}
//--------------------------------------------------------------------------------
void CDECL      Kibitz(char *fmt,...)
{
    va_list         ap;
    static char     kbuffer[4096];
    static int      ikbuffer=0;

    va_start(ap, fmt);
    vprintf(fmt, ap);
    fflush(stdout);
    if (log_file) {
        vfprintf(log_file, fmt, ap);
        fflush(log_file);
    }

    if (ICS_MODE)
    {
       ikbuffer += vsprintf(kbuffer+ikbuffer, fmt, ap);
       if (kbuffer[ikbuffer-1] == '\n')
       {
         Print("tellics kibitz %s", kbuffer);
         ikbuffer=0;
       }
       fflush(stdout);
    }
    va_end(ap);
}
//--------------------------------------------------------------------------------
void CDECL      Log(char *fmt,...)
{
    va_list         ap;
//    char s[512];

    va_start(ap, fmt);
    if (log_file) {
        vfprintf(log_file, fmt, ap);
        /* vsprintf(s, fmt, ap); if (s[strlen(s)-1] == '\n')
         * sprintf(s+strlen(s)-1," (%d)\ndit ",clock()); fputs(s,log_file); */
        fflush(log_file);
    }
    va_end(ap);
}
//--------------------------------------------------------------------------------
#define MAX_LINE 80

void CDECL      GameLog(char *fmt,...)
{
    va_list         ap;
    char            str[1024], buffer[1024];
    static int      linepos = 0;
    int             i, j, skip_blanks;

    va_start(ap, fmt);
    if (gamelog_file) {

        vsprintf(str, fmt, ap);

        for (i=0; str[i];)
        {
              skip_blanks = !linepos;

              for(j=0; j + linepos < MAX_LINE && str[i] && str[i] != '\n'; i++)
              {
                 buffer[j] = str[i];
                 if (str[i] != ' ' || !skip_blanks)
                 {
                    skip_blanks = 0;
                    j++;
                 }
              }

              buffer[j] = 0;
              linepos += j;

              if (linepos == MAX_LINE && str[i] && str[i] != ' ' && str[i] != '\n')
              {
                  while(j && buffer[j-1] != ' ')
                  {
                      j--;
                      i--;
                  }

                  buffer[j] = 0;
              }

              fprintf(gamelog_file,"%s", buffer);

              if (linepos == MAX_LINE || str[i] == '\n')
              {
                  fprintf(gamelog_file, "\n");
                  linepos = 0;
                  if (str[i] == '\n')
                      i++;
              }
        }


        fflush(gamelog_file);
    }
    va_end(ap);
}



//--------------------------------------------------------------------------------
char Pieza(int);

int ImprimeJugada(entero32 jug, char *str)
{
    entero64        mapa_origen = 0;
    entero64        mapa_legales;
    int desde, hacia;
    int (*clavada)(int);
    int aux;

    *str = 0;

    if (jug & (ENROQUE_CORTO|ENROQUE_LARGO))
    {
        strcat(str,"O-O");
        if (jug & ENROQUE_LARGO)
            strcat(str,"-O");
        return 0;
    }

    desde = jug & 0x3f;
    hacia = (jug >> 6) & 0x3f;

    switch(Tablero[desde])
    {

        case REY_N:
        case REY_B:
            
               mapa_origen = Mask(desde);
               break;

        case DAMA_B:

               mapa_origen = AtaquesDama(hacia) & DamasB;
               break;

        case DAMA_N:

               mapa_origen = AtaquesDama(hacia) & DamasN;
               break;

        case TORRE_B:
            
               mapa_origen = AtaquesTorre(hacia) & TorresB;
               break;

        case TORRE_N:
            
               mapa_origen = AtaquesTorre(hacia) & TorresN;
               break;

        case CABALLO_B:

               mapa_origen = AtaquesCaballo(hacia) & CaballosB;
               break;

        case CABALLO_N:

               mapa_origen = AtaquesCaballo(hacia) & CaballosN;
               break;

        case ALFIL_B:

               mapa_origen = AtaquesAlfil(hacia) & AlfilesB;
               break;

        case ALFIL_N:

               mapa_origen = AtaquesAlfil(hacia) & AlfilesN;
               break;

        case PEON_B:

               if (jug & CAPTURA)
                   mapa_origen = AtaquesPeonN(hacia) & PeonesB;
               else
                   mapa_origen = Mask(desde);
               break;

        case PEON_N:

               if (jug & CAPTURA)
                   mapa_origen = AtaquesPeonB(hacia) & PeonesN;
               else
                   mapa_origen = Mask(desde);
               break;

        default:

               return -1;

    } // switch...

    clavada = Turno ? ClavadaReyB : ClavadaReyN;

    mapa_legales = 0;

    while(mapa_origen)
    {
        entero32 jug_temp, backup;
        aux = Lsb(mapa_origen);
        mapa_origen &= mapa_origen-1;

        jug_temp = desde | (hacia << 6) | (Tablero[hacia] << 12);
        if (Tablero[desde] == PEON_B) {
             if (hacia == AlPaso)
                jug_temp |= ((PEON_N + 0x100) << 12);
        } else if (Tablero[desde] == PEON_N) {
             if (hacia == AlPaso)
                jug_temp |= ((PEON_B + 0x100) << 12);
        }


        backup = Historial[NumJug].jug;
        Mueve(jug_temp);

        if (!Jaque(Turno))
            mapa_legales |= Mask(aux);

        DesMueve();
        Historial[NumJug].jug = backup;
    }

    if ((aux = Pieza(Tablero[desde])))
       *str++ = aux;

    mapa_legales ^= Mask(desde);

    if (mapa_legales) // necesario desambiguar...
    {
        int col=0, fil=0;

        do
        {
            aux = Lsb(mapa_legales);
            mapa_legales &= mapa_legales-1;

            if ((aux&7) != (desde&7))
                col = 1;
            else 
                fil = 1;

        } while (mapa_legales);

        if (col)
            *str++ = 'a' + (desde & 7);
        if (fil)
            *str++ = '8' - (desde >> 3);
    }
    else if (!aux && jug & CAPTURA)
        *str++ = 'a' + (desde & 7);

    if (jug & CAPTURA)
        *str++ = 'x';

    *str++ = 'a' + (hacia & 7);
    *str++ = '8' - (hacia >> 3);

    if (jug & PROMOCION)
    {
        *str++ = '=';
        *str++ = Pieza((jug >> 16) & 0xf);
    }

    *str = 0;
    return 0;
}
