
 /* ZugHilfe.c : allgemeine Zughilfsfunktionen */

#include "Adt.h"

Feld * Bauer();
Feld * Springer();
Feld * RestFig();

Feld feld[ 28 ];


ZugOK( s, fe1, fe2, sp )
    Figur s[ 9 ][ 9 ];
    Feld fe1, fe2;
    Special sp;
{
    Feld *fe, *fes;

     /* mögliche Züge der betroffenen Figur: */
    switch( s[ fe1 >> 4 ][ fe1 & yposmask ] & figmask ) {
    case bauer:     fe = Bauer( s, fe1, sp );   break;
    case springer:  fe = Springer( s, fe1 );    break;
    default:        fe = RestFig( s, fe1, sp ); break;
    }

    while( *fe && *fe != fe2 )
        fe ++;

    if( *fe == fe2 && RochOK ( s, fe1, fe2, sp ) )
	return 1;
    else
	return 0;
}

RochOK( s, fe1, fe2, sp )
    Figur s[ 9 ][ 9 ];
    Feld fe1, fe2;
    Special sp;
{
    int sx, sy, zx, ok;
    Farbe fa;

    sx = fe1 >> 4;	sy = fe1 & yposmask;    zx = fe2 >> 4;
    fa = s[ sx ][ sy ]&farbmask;

    ok = 1;
    if( ( s[ sx ][ sy ]&figmask ) == koenig )
	if( zx - sx == 2 || sx - zx == 2 ) {	/* dann ist es Rochade */
	    if( zx > sx ) {	/* kurz */
		ok &= !IstSchach( s, fa, fe1, sp );
		s[ 5 ][ sy ] = leer;	s[ 6 ][ sy ] = koenig | fa;
		ok &= !IstSchach( s, fa, 6<<4|sy, sp );
		s[ 6 ][ sy ] = leer;	s[ 7 ][ sy ] = koenig | fa;
		ok &= !IstSchach( s, fa, fe2, sp );
		s[ 7 ][ sy ] = leer;	s[ 5 ][ sy ] = koenig | fa;
		return ok;
	    } else {		/* lang */
		ok &= !IstSchach( s, fa, fe1, sp );
		s[ 5 ][ sy ] = leer;	s[ 4 ][ sy ] = koenig | fa;
		ok &= !IstSchach( s, fa, 4<<4|sy, sp );
		s[ 4 ][ sy ] = leer;	s[ 3 ][ sy ] = koenig | fa;
		ok &= !IstSchach( s, fa, fe2, sp );
		s[ 3 ][ sy ] = leer;	s[ 5 ][ sy ] = koenig | fa;
		return ok;
	    }
	}

    return 1;
}

Feld * Bauer( s, fe, sp )
    Figur s[ 9 ][ 9 ];
    Feld fe;
    Special sp;
{
    Feld *fes;
    Farbe fa, fas;
    int x, y;
    int dopzug, yp, yps;

    fes = feld;
    x = fe >> 4;
    y = fe & yposmask;
    fa = s[ x ][ y ] & farbmask;
    fas = (fa == weiss ? schwarz : weiss);

    if( fa == weiss ) {
        if( x!=1 && (s[ x-1 ][ y+1 ]&farbmask) == fas ) {
            *fes = ((x-1)<<4) | (y+1); fes ++; }
        if( s[ x ][ y+1 ] == leer ) {
            *fes = (x<<4) | (y+1); fes ++; }
        if( x!=8 && (s[ x+1 ][ y+1 ]&farbmask) == fas ) {
            *fes = ((x+1)<<4) | (y+1); fes ++; }
        if( y == 2 && s[ x ][ y+1 ] == leer && s[ x ][ y+2 ] == leer ) {
            *fes = (x<<4) | (y+2); fes ++; }
    } else {
        if( x!=8 && (s[ x+1 ][ y-1 ]&farbmask) == fas ) {
            *fes = ((x+1)<<4) | (y-1); fes ++; }
        if( s[ x ][ y-1 ] == leer ) {
            *fes = (x<<4) | (y-1); fes ++; }
        if( x!=1 && (s[ x-1 ][ y-1 ]&farbmask) == fas ) {
            *fes = ((x-1)<<4) | (y-1); fes ++; }
        if( y == 7 && s[ x ][ y-1 ] == leer && s[ x ][ y-2 ] == leer ) {
            *fes = (x<<4) | (y-2); fes ++; }
    }
     /* en-passant - Schlagen: */
    if( dopzug = ( sp & epmask ) ) {
	yp = fa == weiss ? 5 : 4;
	yps = fa == weiss ? 6 : 3;
	if( dopzug >= 2 && x == dopzug-1 && y == yp ) {
	    *fes = (dopzug<<4) | yps;	fes ++;
	} else if( dopzug <= 7 && x == dopzug+1 && y == yp ) {
	    *fes = (dopzug<<4) | yps;	fes ++;
	}
    }

    *fes = 0;
    return( feld );
}

Feld * Springer( s, fe )
    Figur s[ 9 ][ 9 ];
    Feld fe;
{
    Feld *fes;
    Farbe fa;
    int x, y;

    fes = feld;
    x = fe >> 4;
    y = fe & yposmask;
    fa = s[ x ][ y ] & farbmask;

    if( x<=7 && y<=6 && (s[ x+1 ][ y+2 ]&farbmask)!=fa ) {
        *fes = ((x+1)<<4) | (y+2); fes ++; }
    if( x<=6 && y<=7 && (s[ x+2 ][ y+1 ]&farbmask)!=fa ) {
        *fes = ((x+2)<<4) | (y+1); fes ++; }
    if( x<=6 && y>=2 && (s[ x+2 ][ y-1 ]&farbmask)!=fa ) {
        *fes = ((x+2)<<4) | (y-1); fes ++; }
    if( x<=7 && y>=3 && (s[ x+1 ][ y-2 ]&farbmask)!=fa ) {
        *fes = ((x+1)<<4) | (y-2); fes ++; }
    if( x>=2 && y>=3 && (s[ x-1 ][ y-2 ]&farbmask)!=fa ) {
        *fes = ((x-1)<<4) | (y-2); fes ++; }
    if( x>=3 && y>=2 && (s[ x-2 ][ y-1 ]&farbmask)!=fa ) {
        *fes = ((x-2)<<4) | (y-1); fes ++; }
    if( x>=3 && y<=7 && (s[ x-2 ][ y+1 ]&farbmask)!=fa ) {
        *fes = ((x-2)<<4) | (y+1); fes ++; }
    if( x>=2 && y<=6 && (s[ x-1 ][ y+2 ]&farbmask)!=fa ) {
        *fes = ((x-1)<<4) | (y+2); fes ++; }

    *fes = 0;
    return( feld );
}

Feld * RestFig( s, fe, sp )
    Figur s[ 9 ][ 9 ];
    Feld fe;
    Special sp;
{
    Feld *fes;
    Farbe fa, fas;
    int x, y, flag, i;
    int xmin, xmax, ymin, ymax;
    int yp;

    fes = feld;
    x = fe >> 4;
    y = fe & yposmask;
    fa = s[ x ][ y ] & farbmask;
    fas = (fa == weiss ? schwarz : weiss);

     /* die Reichweite des Königs ist beschränkt: */
    if( (s[ x ][ y ]&figmask) == koenig ) {
        xmin = x>=2 ? x-1 : x;  xmax = x<=7 ? x+1 : x;
        ymin = y>=2 ? y-1 : y;  ymax = y<=7 ? y+1 : y;
    } else {
        xmin = ymin = 1;        xmax = ymax = 8;
    }

    if( (s[ x ][ y ] & figmask) != laeufer ) { /* horiz. u. vert. */
        flag = i = 1;
        while( flag && y+i<=ymax && (s[ x ][ y+i ]&farbmask)!=fa ) {
            flag = (s[ x ][ y+i ]&farbmask) != fas;
            *fes = (x<<4) | (y+i); fes ++; i ++; }
        flag = i = 1;
        while( flag && x+i<=xmax && (s[ x+i ][ y ]&farbmask)!=fa ) {
            flag = (s[ x+i ][ y ]&farbmask) != fas;
            *fes = ((x+i)<<4) | y; fes ++; i ++; }
        flag = i = 1;
        while( flag && y-i>=ymin && (s[ x ][ y-i ]&farbmask)!=fa ) {
            flag = (s[ x ][ y-i ]&farbmask) != fas;
            *fes = (x<<4) | (y-i); fes ++; i ++; }
        flag = i = 1;
        while( flag && x-i>=xmin && (s[ x-i ][ y ]&farbmask)!=fa ) {
            flag = (s[ x-i ][ y ]&farbmask) != fas;
            *fes = ((x-i)<<4) | y; fes ++; i ++; }
    }
    if( (s[ x ][ y ] & figmask) != turm ) { /* diagonal */
        flag = i = 1;
        while( flag && x+i<=xmax && y+i<=ymax && (s[ x+i ][ y+i ]&farbmask)!=fa ) {
            flag = (s[ x+i ][ y+i ]&farbmask) != fas;
            *fes = ((x+i)<<4) | (y+i); fes ++; i ++; }
        flag = i = 1;
        while( flag && x+i<=xmax && y-i>=ymin && (s[ x+i ][ y-i ]&farbmask)!=fa ) {
            flag = (s[ x+i ][ y-i ]&farbmask) != fas;
            *fes = ((x+i)<<4) | (y-i); fes ++; i ++; }
        flag = i = 1;
        while( flag && x-i>=xmin && y-i>=ymin && (s[ x-i ][ y-i ]&farbmask)!=fa ) {
            flag = (s[ x-i ][ y-i ]&farbmask) != fas;
            *fes = ((x-i)<<4) | (y-i); fes ++; i ++; }
        flag = i = 1;
        while( flag && x-i>=xmin && y+i<=ymax && (s[ x-i ][ y+i ]&farbmask)!=fa ) {
            flag = (s[ x-i ][ y+i ]&farbmask) != fas;
            *fes = ((x-i)<<4) | (y+i); fes ++; i ++; }
    }
     /* Rochade: */
    if( ( s[ x ][ y ]&figmask ) == koenig )
	if( ( fa==weiss && sp&wroch ) || ( fa==schwarz && sp&sroch ) ) {
	    yp = fa == weiss ? 1 : 8;
	    if( (fa==weiss && sp&wkroch) || (fa==schwarz && sp&skroch) ) {
		if( s[ 6 ][ yp ]==leer && s[ 7 ][ yp ]==leer &&
		  s[ 8 ][ yp ]==turm|fa ) {
		    *fes = 7<<4|yp;	fes ++;
		}
	    }
	    if( (fa==weiss && sp&wlroch) || (fa==schwarz && sp&slroch) ) {
		if( s[ 2 ][ yp ]==leer && s[ 3 ][ yp ]==leer &&
		  s[ 4 ][ yp ]==leer && s[ 1 ][ yp ]==turm|fa ) {
		    *fes = 3<<4|yp;	fes ++;
		}
	    }
	}

    *fes = 0;
    return( feld );
}

IstSchach( s, fa, fe, sp )
    Figur s[ 9 ][ 9 ];
    Farbe fa;
    Feld fe;
    Special sp;
{
    Figur fig;
    Farbe fas;
    Feld *fes;
    int i, j, x, y;

    if( fe ) {
        x = fe >> 4;    y = fe & yposmask;
    } else
         /* den König finden: */
        for( i=1; i<=8; i++ )
            for( j=1; j<=8; j++ )
                if( s[ i ][ j ] == (koenig | fa) ) {
                    x = i; y = j; fe = x << 4 | y;
                }

     /* König von einem Bauer bedroht? */
    if( fa == weiss ) {
        if( y <= 6 )
            if( ( x>=2 && s[ x-1 ][ y+1 ] == sbauer ) ||
              ( x<=7 && s[ x+1 ][ y+1 ] == sbauer ) )
                return( 1 );
    } else
        if( y >= 3 )
            if( ( x<=7 && s[ x+1 ][ y-1 ] == wbauer ) ||
              ( x>=2 && s[ x-1 ][ y-1 ] == wbauer ) )
                return( 1 );

     /* König durch Springer bedroht? */
    fas = ( fa == weiss ) ? schwarz : weiss;
    s[ x ][ y ] = springer | fa;
    fes = Springer( s, fe );
    while( *fes ) {
        if( s[ *fes >> 4 ][ *fes & yposmask ] == (springer | fas) ) {
            s[ x ][ y ] = koenig | fa;
            return( 1 );
        }
        fes ++;
    }

     /* Läufer, Turm oder Dame gefährlich? */
    s[ x ][ y ] = laeufer | fa;
    fes = RestFig( s, fe, sp );
    while( *fes ) {
        fig = s[ *fes >> 4 ][ *fes & yposmask ];
        if( fig == (laeufer | fas) || fig == (dame | fas ) ) {
            s[ x ][ y ] = koenig | fa;
            return( 1 );
        }
        fes ++;
    }
    s[ x ][ y ] = turm | fa;
    fes = RestFig( s, fe, sp );
    while( *fes ) {
        fig = s[ *fes >> 4 ][ *fes & yposmask ];
        if( fig == (turm | fas) || fig == (dame | fas ) ) {
            s[ x ][ y ] = koenig | fa;
            return( 1 );
        }
        fes ++;
    }

     /* König/König-Annäherung nicht erlaubt: */
    s[ x ][ y ] = koenig | fa;
    fes = RestFig( s, fe, sp );
    while( *fes ) {
        if( s[ *fes >> 4 ][ *fes & yposmask ] == (koenig | fas) )
            return( 1 );
        fes ++;
    }

    return( 0 );
}

IstMatt( s, fa, sp )
    Figur s[ 9 ][ 9 ];
    Farbe fa;
    Special sp;
{
    int i, j, x, y, ok;
    Feld *fe, fes, fesk[ 28 ], *fek;
    Figur qu, merk;

    for( i=1; i<=8; i++ )
        for( j=1; j<=8; j++ )
            if( (s[ i ][ j ] & farbmask) == fa ) {
                fes = i << 4 | j;
                switch( s[ i ][ j ] & figmask ) {
                case bauer:     fe = Bauer( s, fes, sp );   break;
                case springer:  fe = Springer( s, fes );    break;
                default:        fe = RestFig( s, fes, sp ); break;
                }
                qu = s[ i ][ j ];
                s[ i ][ j ] = leer;

                 /* Züge kopieren, da fe überschrieben wird */
                fek = fesk;
                while( *fe ) {
                    *fek = *fe;
                    fek ++;
                    fe ++;
                }
                *fek = 0;
                fek = fesk;

                 /* führt ein Zug dieser Figur ins 'nicht-schach'? */
                while( *fek ) {
                    x = *fek >> 4;   y = *fek & yposmask;
                    merk = s[ x ][ y ];
                    s[ x ][ y ] = qu;
                    if( qu == (koenig | fa ) )
                        ok = !IstSchach( s, fa, *fek, sp );
                    else
                        ok = !IstSchach( s, fa, 0, sp );
                    s[ x ][ y ] = merk;
                    if( ok ) {
                        s[ i ][ j ] = qu;
                        return( 0 );
                    }
                    fek ++;
                }
                s[ i ][ j ] = qu;
            }

    return( 1 );
}

IstPatt( s, fa, sp )
    Figur s[ 9 ][ 9 ];
    Farbe fa;
    Special sp;
{
    Figur merk;
    Feld fes, *fe, fesk[ 28 ], *fek;
    int i, j, xk, yk, zx, zy;

    for( i=1; i<=8; i++ )
        for( j=1; j<=8; j++ )
            if( (s[ i ][ j ] & farbmask) == fa )
                if( s[ i ][ j ] == (koenig | fa) ) {
                    xk = i; yk = j;
                } else {
                    fes = i << 4 | j;
                    switch( s[ i ][ j ] & figmask ) {
                    case bauer:     fe = Bauer( s, fes, sp );   break;
                    case springer:  fe = Springer( s, fes );    break;
                    default:        fe = RestFig( s, fes, sp ); break;
                    }
                    if( *fe ) /* ein eigener 'nicht-König' kann ziehen */
                        return( 0 );
                }

     /* kann König ins 'nicht-schach' ziehen? */
    fes = xk << 4 | yk;
    fe = RestFig( s, fes, sp );
    if( *fe ) {

         /* Züge kopieren, da fe überschrieben wird */
        fek = fesk;
        while( *fe ) {
            *fek = *fe;
            fek ++;
            fe ++;
        }
        *fek = 0;
        fek = fesk;

        s[ xk ][ yk ] = leer;
        do {
            zx = *fek >> 4;
            zy = *fek & yposmask;
            merk = s[ zx ][ zy ];
            s[ zx ][ zy ] = koenig | fa;
            if( !IstSchach( s, fa, *fek, sp ) ) {
                s[ zx ][ zy ] = merk;
                s[ xk ][ yk ] = koenig | fa;
                return( 0 );
            }
            s[ zx ][ zy ] = merk;
            fek ++;
        } while( *fek );
        s[ xk ][ yk ] = koenig | fa;
    }

    return( 1 );
}
