
 /* Zug.c : individuelle Zugbewertung */

#include "Adt.h"

Feld * Bauer();
Feld * Springer();
Feld * RestFig();
struct Knoten * GibKnoten();

long ZugBaumI();
long ZugBaumII();

int Figurwert[] = { 0, 100, 300, 300, 500, 900, 21000 };
int Stelwert[][ 8 ][ 8 ] = {
  { /* wbauer: */
  {  0,  0,  0,  0,  0,  0,  0,  0 },
  { 35, 70, 55, 75, 75, 55, 70, 35 },
  { 30, 65, 50, 70, 70, 50, 65, 30 },
  { 25, 60, 45, 65, 65, 45, 60, 25 },
  { 20, 55, 40, 62, 62, 40, 55, 20 },
  { 10, 50, 30, 40, 40, 30, 50, 10 },
  {  0,  0,  0,  0,  0,  0,  0,  0 },
  {  0,  0,  0,  0,  0,  0,  0,  0 } },
  { /* sbauer: */
  {  0,  0,  0,  0,  0,  0,  0,  0 },
  {  0,  0,  0,  0,  0,  0,  0,  0 },
  { 10, 50, 30, 40, 40, 30, 50, 10 },
  { 20, 55, 40, 62, 62, 40, 55, 20 },
  { 25, 60, 45, 65, 65, 45, 60, 25 },
  { 30, 65, 50, 70, 70, 50, 65, 30 },
  { 35, 70, 55, 75, 75, 55, 70, 35 },
  {  0,  0,  0,  0,  0,  0,  0,  0 } },
  { /* springer: */
  {  0, 12, 24, 24, 24, 24, 12,  0 },
  { 12, 24, 48, 48, 48, 48, 24, 12 },
  { 24, 48, 72, 72, 72, 72, 48, 24 },
  { 24, 48, 72, 72, 72, 72, 48, 24 },
  { 24, 48, 72, 72, 72, 72, 48, 24 },
  { 24, 48, 72, 72, 72, 72, 48, 24 },
  { 12, 24, 48, 48, 48, 48, 24, 12 },
  {  0, 12, 24, 24, 24, 24, 12,  0 } },
  { /* laeufer: */
  {  7,  7,  0,  0,  0,  0,  7,  7 },
  {  7, 21, 21, 14, 14, 21, 21,  7 },
  { 21, 21, 35, 35, 35, 35, 21, 21 },
  { 35, 14, 35, 35, 35, 35, 14, 35 },
  { 35, 14, 35, 35, 35, 35, 14, 35 },
  { 21, 21, 35, 35, 35, 35, 21, 21 },
  {  7, 21, 21, 14, 14, 21, 21,  7 },
  {  7,  7,  0,  0,  0,  0,  7,  7 } },
  { /* turm: */
  {  0, 10, 20, 30, 30, 20, 10,  0 },
  { 10, 10, 20, 30, 30, 20, 10, 10 },
  { 20, 20, 20, 25, 25, 20, 20, 20 },
  { 20, 20, 20, 25, 25, 20, 20, 20 },
  { 20, 20, 20, 25, 25, 20, 20, 20 },
  { 20, 20, 20, 25, 25, 20, 20, 20 },
  { 10, 10, 20, 30, 30, 20, 10, 10 },
  {  0, 10, 20, 30, 30, 20, 10,  0 } },
  { /* dame: */
  {  4,  0,  0,  4,  4,  0,  0,  4 },
  {  0, 12,  8, 12, 12,  8, 12,  0 },
  {  0,  8, 20, 20, 20, 20,  8,  0 },
  {  0,  8, 16, 28, 28, 16,  8,  0 },
  {  0,  8, 16, 28, 28, 16,  8,  0 },
  {  0,  8, 20, 20, 20, 20,  8,  0 },
  {  0, 12,  8, 12, 12,  8, 12,  0 },
  {  4,  0,  0,  4,  4,  0,  0,  4 } },
  { /* koenig: */
  {  0, 12, 12, 12, 12, 12, 12,  0 },
  { 12, 30, 30, 30, 30, 30, 30, 12 },
  { 12, 30, 30, 30, 30, 30, 30, 12 },
  { 12, 30, 30, 30, 30, 30, 30, 12 },
  { 12, 30, 30, 30, 30, 30, 30, 12 },
  { 12, 30, 30, 30, 30, 30, 30, 12 },
  { 12, 30, 30, 30, 30, 30, 30, 12 },
  {  0, 12, 12, 12, 12, 12, 12,  0 } } };


struct Zugstat * BesterZug( s, fa, ite, sp )
    Figur s[ 9 ][ 9 ];
    Farbe fa;
    int ite;
    Special sp;
{
    static struct Zugstat zs;
    struct Knoten *k, *ks;
    struct Zug *z;
    long kn;
    int best, ok, sx, sy, zx, zy;
    Figur fi;
    int spz;

    Zeit( 0L );
    kn = ZugBaumI( s, &k, &k, fa, ite, sp );

    if( kn ) {
         /* besten Zug aussuchen und merken: */
        best = -30000; ks = k;
        do {
            if( ks->zugwertung > best ) {

                sx = ks->zug.start >> 4;    sy = ks->zug.start & yposmask;
                zx = ks->zug.ziel >> 4;     zy = ks->zug.ziel & yposmask;
                 /* Zug ausführen: */
		fi = s[zx][zy]; s[sx][sy] = leer; spz = 0;
		if( (ks->zug.figur&figmask)==koenig && (zx-sx==2 ||
		  sx-zx==2) ) {
		    spz = 1; s[zx][zy] = ks->zug.figur;
		    if( zx==7 ) {
			s[6][sy] = s[8][sy]; s[8][sy] = leer;
		    } else {
			s[4][sy] = s[1][sy]; s[1][sy] = leer;
		    }
		} else if( (ks->zug.figur&figmask)==bauer && fi==leer &&
		  sx!=zx ) {
		    spz = 1; s[zx][zy] = ks->zug.figur; s[zx][sy] = leer;
		} else if( (ks->zug.figur&figmask)==bauer && (zy==1 ||
		  zy==8) ) {
		    s[zx][zy] = (ks->zug.figur&farbmask)|dame;
		} else
		    s[zx][zy] = ks->zug.figur;

                ok = !IstSchach( s, fa, 0, sp );

                 /* Zug zurücknehmen: */
		s[sx][sy] = ks->zug.figur; s[zx][zy] = fi;
		if( spz )
		    if( zx-sx==2 || sx-zx==2 ) {
			if( zx==7 ) {
			    s[8][sy] = s[6][sy]; s[6][sy] = leer;
			} else {
			    s[1][sy] = s[4][sy]; s[4][sy] = leer;
			}
		    } else
			s[zx][sy] = bauer|(zy==6?schwarz:weiss);

		ok &= RochOK( s, ks->zug.start, ks->zug.ziel, sp );

                if( ok ) { /* ins (bei Roch. durchs) Schach ziehen verboten */
                    best = ks->zugwertung;
                    z = &(ks->zug);
                } else
                    ks->zugwertung = -30000;
            }
            ks = ks->nachbar;
        } while( ks );
    } else
        return( 0L );

    zs.zug.figur = z->figur;
    zs.zug.start = z->start;
    zs.zug.ziel  = z->ziel;
    LoescheBaum( &k );
    Zeit( &(zs.zeit) );
    zs.knoten = kn;
    zs.wertung = GesamtWert( s, &(zs.zug) );
    return( &zs );
}

long
ZugBaumI( s, ks, k, fa, iteration, sp )
    Figur s[ 9 ][ 9 ];
    struct Knoten **ks, **k;
    Farbe fa;
    int iteration;
    Special sp;
{
    int i, j;
    long knoten;
    Feld *fe;
    Feld fes;
    struct Knoten **kmerk;
    struct Knoten *k1;

    knoten = 0;
    kmerk = k;

     /* Spielbrett nach eigenen Figuren durchsuchen: */
    for( i=1; i<=8; i++ )
        for( j=1; j<=8; j++ )
            if( (s[ i ][ j ] & farbmask) == fa ) {

                 /* mögliche Züge der Figur ermitteln: */
                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;
                }

                 /* alle neuen Züge in den Zugbaum: */
                while( *fe ) {
                    if(( k1 = GibKnoten()) == 0L ) {
                        LoescheBaum( ks );
                        SchliesseDisplay();
                        exit( 1 );
                    }
                    knoten ++;
                    k1->zug.figur = s[ i ][ j ];
                    k1->zug.start = fes;
                    k1->zug.ziel  = *fe;
                    k1->nachbar = k1->nachfolger = 0L;
                    *kmerk = k1;
                    kmerk = &(k1->nachbar);
                    fe ++;
                }
            }

    if( knoten )
         /* alle neuen Züge bewerten: */
        knoten += ZugBaumII( s, ks, k, fa, iteration, sp );

    return( knoten );
}

long
ZugBaumII( s, ks, k, fa, iteration, sp )
    Figur s[ 9 ][ 9 ];
    struct Knoten **ks, **k;
    Farbe fa;
    int iteration;
    Special sp;
{
    long knoten, kneu;
    int bonus, figwert, best;
    struct Knoten *k1, *k2;
    int sx, sy, zx, zy;
    Figur fi;
    int spz, spbonus;
    Special sps;

    knoten = 0;
    k1 = *k;

    while( k1 ) {

	sx = k1->zug.start >> 4;       sy = k1->zug.start & yposmask;
        zx = k1->zug.ziel >> 4;        zy = k1->zug.ziel & yposmask;

         /* bei Bauernumwandlung gibt's Bonuspunkte: */
        if( (k1->zug.figur & figmask) == bauer && (zy == 1 || zy == 8) )
            bonus = Figurwert[ dame ] - Figurwert[ bauer ];
        else
            bonus = 0;

         /* Figuren schlagen bringt auch Punkte: */
        fi = s[ zx ][ zy ];
        figwert = ( fi == leer ) ? 0 : Figurwert[ fi & figmask ] +
          Stellungswert( fi, k1->zug.ziel );

	 /* jeweils Punkte für Rochade und ep-Schlagen: */
	if( (k1->zug.figur&figmask)==koenig && (zx-sx==2 || sx-zx==2) )
	    spbonus = 100;
	else if( (k1->zug.figur&figmask)==bauer && fi==leer && sx!=zx )
	    spbonus = 100;
	else
	    spbonus = 0;

         /* auch Gegenzüge erkunden? */
        if( iteration > 1 ) {

	     /* neue Special - Variable: */
	    sps = sp & ~epmask;
	    if( (k1->zug.figur&figmask)==bauer && (zy-sy==2 || sy-zy==2) )
		sps |= sx;
	    if( (k1->zug.figur&figmask)==koenig )
		if( (k1->zug.figur&farbmask)==weiss )
		    sps &= ~wroch;
		else
		    sps &= ~sroch;
	    if( (k1->zug.figur&figmask)==turm )
		if( (k1->zug.figur&farbmask)==weiss ) {
		    if( sx==1 )
			sps &= ~wlroch;
		    else if( sx==8 )
			sps &= ~wkroch;
		} else
		    if( sx==1 )
			sps &= ~slroch;
		    else
			sps &= ~skroch;

             /* Zug auf Spielbrett ausführen: */
	    s[sx][sy] = leer; spz = 0;
	    if( (k1->zug.figur&figmask)==koenig && (zx-sx==2 || sx-zx==2) ) {
		spz = 1; s[zx][zy] = k1->zug.figur;
		if( zx==7 ) {
		    s[6][sy] = s[8][sy]; s[8][sy] = leer;
		} else {
		    s[4][sy] = s[1][sy]; s[1][sy] = leer;
		}
	    } else if( (k1->zug.figur&figmask)==bauer && fi==leer && sx!=zx ) {
		spz = 1; s[zx][zy] = k1->zug.figur; s[zx][sy] = leer;
	    } else if( bonus ) {
		s[zx][zy] = fa|dame;
	    } else
		s[zx][zy] = k1->zug.figur;

             /* Unterbaum aufbauen lassen: */
            kneu = ZugBaumI( s, ks, &(k1->nachfolger),
              fa == weiss ? schwarz : weiss, iteration-1, sps );
            knoten += kneu;

             /* besten Gegenzug ermitteln: */
            if( kneu ) {
                best = -30000;
                k2 = k1->nachfolger;
                do {
                    if( k2->zugwertung > best )
                        best = k2->zugwertung;
                    k2 = k2->nachbar;
                } while( k2 );
            } else
                best = 5000;

             /* Unterbaum wegwerfen: */
            LoescheBaum( &(k1->nachfolger) );

             /* Zug auf Spielbrett rückgängig machen: */
	    s[sx][sy] = k1->zug.figur; s[zx][zy] = fi;
	    if( spz )
		if( zx-sx==2 || sx-zx==2 ) {
		    if(zx==7) {
			s[8][sy] = s[6][sy]; s[6][sy] = leer;
		    } else {
			s[1][sy] = s[4][sy]; s[4][sy] = leer;
		    }
		} else
		    s[zx][sy] = bauer|(zy==6?schwarz:weiss);

        } else
            best = 0;

         /* auch Positionswechsel kann Punkte bedeuten: */
        k1->zugwertung = bonus + spbonus + figwert - best +
          Stellungswert( k1->zug.figur, k1->zug.ziel ) -
          Stellungswert( k1->zug.figur, k1->zug.start );

        k1 = k1->nachbar;
    }

    return( knoten );
}

LoescheBaum( k )
    struct Knoten **k;
{
    struct Knoten *k1, *kmerk;

    k1 = *k;
    *k = 0L;
    while( k1 ) {
        LoescheBaum( &(k1->nachfolger) );
        kmerk = k1->nachbar;
        NimmKnoten( k1 );
        k1 = kmerk;
    }
}

Stellungswert( fi, fe )
    Figur fi;
    Feld fe;
{
    int fstdim;

    fstdim = ( fi == wbauer ) ? 0 : ( fi & figmask );
    return( Stelwert[ fstdim ][ 8 - (fe & yposmask) ][ (fe >> 4)-1 ] );
}

GesamtWert( s, z )
    Figur s[ 9 ][ 9 ];
    struct Zug *z;
{
    int sx, sy, zx, zy;
    Figur fi;
    int spz;
    long wert;
    int i, j, neu;
    Feld fe;

    sx = z->start >> 4; sy = z->start & yposmask;
    zx = z->ziel >> 4;  zy = z->ziel & yposmask;
     /* Zug ausführen: */
    fi = s[zx][zy]; s[sx][sy] = leer; spz = 0;
    if( (z->figur&figmask)==koenig && (zx-sx==2 || sx-zx==2) ) {
	spz = 1; s[zx][zy] = z->figur;
	if( zx==7 ) {
	    s[6][sy] = s[8][sy]; s[8][sy] = leer;
	} else {
	    s[4][sy] = s[1][sy]; s[1][sy] = leer;
	}
    } else if( (z->figur&figmask)==bauer && fi==leer && sx!=zx ) {
	spz = 1; s[zx][zy] = z->figur; s[zx][sy] = leer;
    } else if( (z->figur&figmask)==bauer && (zy==1 || zy==8) ) {
	s[zx][zy] = (z->figur&farbmask)|dame;
    } else
	s[zx][zy] = z->figur;

    wert = 0;
    for( i=1; i<=8; i++ )
        for( j=1; j<=8; j++ )
            if( s[ i ][ j ] != leer ) {
                fe = i << 4 | j;
                neu = Figurwert[ s[ i ][ j ] & figmask ] +
                  Stellungswert( s[ i ][ j ], fe );
                if( (s[ i ][ j ] & farbmask) == weiss )
                    wert += neu;
                else
                    wert -= neu;
            }

     /* Zug rückgängig machen: */
    s[sx][sy] = z->figur; s[zx][zy] = fi;
    if( spz )
	if( zx-sx==2 || sx-zx==2 ) {
	    if( zx==7 ) {
		s[8][sy] = s[6][sy]; s[6][sy] = leer;
	    } else {
		s[1][sy] = s[4][sy]; s[4][sy] = leer;
	    }
	} else
	    s[zx][sy] = bauer|(zy==6?schwarz:weiss);

    return( (int)wert );
}
