Not logged inCSS-Forum
Forum CSS-Online Help Search Login
CSS-Shop Impressum Datenschutz
Up Topic Hauptforen / Schachprogrammierung / Stellungsbewertung
- By Lothar Jung Date 2021-07-09 18:31 Edited 2021-07-09 18:36
Wikipedia-Artikel zur Strategie und Bewertungskriterien:

https://de.wikipedia.org/wiki/Strategie_(Schach)?wprov=sfti1

https://www.chessprogramming.org/Evaluation

Beitrag zur Bewertung von Figuren, abhängig von der Position auf dem Brett:

https://www.stmintz.com/ccc/index.php?id=28583
- By Lothar Jung Date 2021-07-11 12:23
Die Evolutionsstrategie soll Werte für die folgenden Merkmale der Stellungsbewertung optimieren:
1. die Werte für die einzelnen Figurtypen [0-1000]
2. einen Bestrafungswert für einen Läufer in der Anfangsposition [0-30]
3. ein Bonus für einen Bauern, der das Zentrum des Schachbrettes erreicht hat [0-30]
4. eine Bestrafung, wenn zwei Bauern auf der gleichen Linie stehen [0-30]
5. ein Bonus für einen Bauern, der auf beiden Nachbarlinien keinen gegnerischen Bau- ern hat [0-40]
6. eine Bestrafung für einen Bauern, der keinen Bauern auf den Nachbarlinien hat, der näher an der ersten Reihe des Gegners ist [0-30]
7. ein Bonus für einen Freibauern, der durch einen Turm beschützt wird [0-30]
8. ein Bonus für einen Bauern, wenn er in der Nähe der ersten Reihe des Gegners ist (Promotionsmöglichkeit) [100-500]
9. ein Bonus, wenn beide Läufer vorhanden sind [0-40]
10. eine Bestrafung für einen Läufer, der sich in der Startposition aufhält [0-30]
11. eine Bestrafung für Läufer in einer blockierten Stellung. Eine blockierte Stellung ist in diesem Zusammenhang eine Stellung, in der drei eigene Bauern sich im Bereich des erweiterten Zentrums befinden und Felder besetzen, die die gleiche Farbe haben wie die Felder auf denen sich der Läufer bewegt [0-40]
12. ein Bonus für den Springer, wenn es sich um eine blockierte Stellung handelt. Für einen Springer handelt es sich um eine blockierte Stellung, wenn sich mehr als sechs Bauern im erweiterten Zentrum aufhalten. Durch die Fortbewegungsweise des Springers wird er aufgewertet [0-50]
13. ein Bonus für den Springer, wenn er mehr als sechs Felder erreichen kann [0-30]
14. ein Bonus für den Springer in einer geschlossenen Position [0-40]
15. eine Bestrafung, wenn auf jeder Seite des Springers ein generischer Bauer steht [0-50]
2Shannon hat schon 1950 einen Artikel über den Aufbau von Schachprogrammen geschrieben, seine Vorstellungen sind bis heute in fast allen Programmen wiederzufinden.
16. ein Bonus für den Turm, falls er von dem anderen Turm gedeckt wird [0-20]
17. ein Bonus für den Turm, wenn er auf einer halboffenen Linie steht [0-30]
18. ein Bonus für den Turm, wenn er auf einer offenen Linie steht [0-30]
19. ein Bonus für den Turm für andere Vorteile [0-20]
20. eine Bestrafung für den König, wenn er die erste Reihe während des Eröffnungs- oder Mittelspiels verlässt [0-20]
21. ein Bonus, nachdem eine Rochade ausgeführt wurde [0-40]
22. eine Bestrafung für die Rochade, wenn es eine Schwäche in der Bauernstruktur vor dem König gibt [0-30]
23. eine Bestrafung, wenn die Möglichkeit einer Rochade vergeben wurde [0-50]
24. ein Zufallswert, der zum Wert der Stellung addiert oder subtrahiert wird [0-30]
- - By Lothar Jung Date 2021-07-11 20:52
Hier beispielhaft ein gut kommentierter Bewertungsquellcode in C:

/*
*  EVAL.C
*  Tom Kerrigan's Simple Chess Program (TSCP)
*
*  Copyright 1997 Tom Kerrigan
*/

#include <string.h>
#include "defs.h"
#include "data.h"
#include "protos.h"

#define DOUBLED_PAWN_PENALTY    10
#define ISOLATED_PAWN_PENALTY    20
#define BACKWARDS_PAWN_PENALTY    8
#define PASSED_PAWN_BONUS      20
#define ROOK_SEMI_OPEN_FILE_BONUS  10
#define ROOK_OPEN_FILE_BONUS    15
#define ROOK_ON_SEVENTH_BONUS    20

/* the values of the pieces */
int piece_value[6] = {
  100, 300, 300, 500, 900, 0
};

/* The "pcsq" arrays are piece/square tables. They're values
   added to the material value of the piece based on the
   location of the piece. */

int pawn_pcsq[64] = {
    0,   0,   0,   0,   0,   0,   0,   0,
    5,  10,  15,  20,  20,  15,  10,   5,
    4,   8,  12,  16,  16,  12,   8,   4,
    3,   6,   9,  12,  12,   9,   6,   3,
    2,   4,   6,   8,   8,   6,   4,   2,
    1,   2,   3, -10, -10,   3,   2,   1,
    0,   0,   0, -40, -40,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0
};

int knight_pcsq[64] = {
  -10, -10, -10, -10, -10, -10, -10, -10,
  -10,   0,   0,   0,   0,   0,   0, -10,
  -10,   0,   5,   5,   5,   5,   0, -10,
  -10,   0,   5,  10,  10,   5,   0, -10,
  -10,   0,   5,  10,  10,   5,   0, -10,
  -10,   0,   5,   5,   5,   5,   0, -10,
  -10,   0,   0,   0,   0,   0,   0, -10,
  -10, -30, -10, -10, -10, -10, -30, -10
};

int bishop_pcsq[64] = {
  -10, -10, -10, -10, -10, -10, -10, -10,
  -10,   0,   0,   0,   0,   0,   0, -10,
  -10,   0,   5,   5,   5,   5,   0, -10,
  -10,   0,   5,  10,  10,   5,   0, -10,
  -10,   0,   5,  10,  10,   5,   0, -10,
  -10,   0,   5,   5,   5,   5,   0, -10,
  -10,   0,   0,   0,   0,   0,   0, -10,
  -10, -10, -20, -10, -10, -20, -10, -10
};

int king_pcsq[64] = {
  -40, -40, -40, -40, -40, -40, -40, -40,
  -40, -40, -40, -40, -40, -40, -40, -40,
  -40, -40, -40, -40, -40, -40, -40, -40,
  -40, -40, -40, -40, -40, -40, -40, -40,
  -40, -40, -40, -40, -40, -40, -40, -40,
  -40, -40, -40, -40, -40, -40, -40, -40,
  -20, -20, -20, -20, -20, -20, -20, -20,
    0,  20,  40, -20,   0, -20,  40,  20
};

int king_endgame_pcsq[64] = {
    0,  10,  20,  30,  30,  20,  10,   0,
   10,  20,  30,  40,  40,  30,  20,  10,
   20,  30,  40,  50,  50,  40,  30,  20,
   30,  40,  50,  60,  60,  50,  40,  30,
   30,  40,  50,  60,  60,  50,  40,  30,
   20,  30,  40,  50,  50,  40,  30,  20,
   10,  20,  30,  40,  40,  30,  20,  10,
    0,  10,  20,  30,  30,  20,  10,   0
};

/* The flip array is used to calculate the piece/square
   values for DARK pieces. The piece/square value of a
   LIGHT pawn is pawn_pcsq[sq] and the value of a DARK
   pawn is pawn_pcsq[flip[sq]] */
int flip[64] = {
   56,  57,  58,  59,  60,  61,  62,  63,
   48,  49,  50,  51,  52,  53,  54,  55,
   40,  41,  42,  43,  44,  45,  46,  47,
   32,  33,  34,  35,  36,  37,  38,  39,
   24,  25,  26,  27,  28,  29,  30,  31,
   16,  17,  18,  19,  20,  21,  22,  23,
    8,   9,  10,  11,  12,  13,  14,  15,
    0,   1,   2,   3,   4,   5,   6,   7
};

/* pawn_rank[x][y] is the rank of the least advanced pawn of color x on file
   y - 1. There are "buffer files" on the left and right to avoid special-case
   logic later. If there's no pawn on a rank, we pretend the pawn is
   impossibly far advanced (0 for LIGHT and 7 for DARK). This makes it easy to
   test for pawns on a rank and it simplifies some pawn evaluation code. */
int pawn_rank[2][10];

int piece_mat[2];  /* the value of a side's pieces */
int pawn_mat[2];  /* the value of a side's pawns */

int eval()
{
  int i;
  int f;  /* file */
  int score[2];  /* each side's score */

  /* this is the first pass: set up pawn_rank, piece_mat, and pawn_mat. */
  for (i = 0; i < 10; ++i) {
    pawn_rank[LIGHT] = 0;
    pawn_rank[DARK] = 7;
  }
  piece_mat[LIGHT] = 0;
  piece_mat[DARK] = 0;
  pawn_mat[LIGHT] = 0;
  pawn_mat[DARK] = 0;
  for (i = 0; i < 64; ++i) {
    if (color == EMPTY)
      continue;
    if (piece == PAWN) {
      pawn_mat[color] += piece_value[PAWN];
      f = COL(i) + 1;  /* add 1 because of the extra file in the array */
      if (color == LIGHT) {
        if (pawn_rank[LIGHT][f] < ROW(i))
          pawn_rank[LIGHT][f] = ROW(i);
      }
      else {
        if (pawn_rank[DARK][f] > ROW(i))
          pawn_rank[DARK][f] = ROW(i);
      }
    }
    else
      piece_mat[color] += piece_value[piece];
  }

  /* this is the second pass: evaluate each piece */
  score[LIGHT] = piece_mat[LIGHT] + pawn_mat[LIGHT];
  score[DARK] = piece_mat[DARK] + pawn_mat[DARK];
  for (i = 0; i < 64; ++i) {
    if (color == EMPTY)
      continue;
    if (color == LIGHT) {
      switch (piece) {
        case PAWN:
          score[LIGHT] += eval_light_pawn(i);
          break;
        case KNIGHT:
          score[LIGHT] += knight_pcsq;
          break;
        case BISHOP:
          score[LIGHT] += bishop_pcsq;
          break;
        case ROOK:
          if (pawn_rank[LIGHT][COL(i) + 1] == 0) {
            if (pawn_rank[DARK][COL(i) + 1] == 7)
              score[LIGHT] += ROOK_OPEN_FILE_BONUS;
            else
              score[LIGHT] += ROOK_SEMI_OPEN_FILE_BONUS;
          }
          if (ROW(i) == 1)
            score[LIGHT] += ROOK_ON_SEVENTH_BONUS;
          break;
        case KING:
          if (piece_mat[DARK] <= 1200)
            score[LIGHT] += king_endgame_pcsq;
          else
            score[LIGHT] += eval_light_king(i);
          break;
      }
    }
    else {
      switch (piece) {
        case PAWN:
          score[DARK] += eval_dark_pawn(i);
          break;
        case KNIGHT:
          score[DARK] += knight_pcsq[flip];
          break;
        case BISHOP:
          score[DARK] += bishop_pcsq[flip];
          break;
        case ROOK:
          if (pawn_rank[DARK][COL(i) + 1] == 7) {
            if (pawn_rank[LIGHT][COL(i) + 1] == 0)
              score[DARK] += ROOK_OPEN_FILE_BONUS;
            else
              score[DARK] += ROOK_SEMI_OPEN_FILE_BONUS;
          }
          if (ROW(i) == 6)
            score[DARK] += ROOK_ON_SEVENTH_BONUS;
          break;
        case KING:
          if (piece_mat[LIGHT] <= 1200)
            score[DARK] += king_endgame_pcsq[flip];
          else
            score[DARK] += eval_dark_king(i);
          break;
      }
    }
  }

  /* the score[] array is set, now return the score relative
     to the side to move */
  if (side == LIGHT)
    return score[LIGHT] - score[DARK];
  return score[DARK] - score[LIGHT];
}

int eval_light_pawn(int sq)
{
  int r;  /* the value to return */
  int f;  /* the pawn's file */

  r = 0;
  f = COL(sq) + 1;

  r += pawn_pcsq[sq];

  /* if there's a pawn behind this one, it's doubled */
  if (pawn_rank[LIGHT][f] > ROW(sq))
    r -= DOUBLED_PAWN_PENALTY;

  /* if there aren't any friendly pawns on either side of
     this one, it's isolated */
  if ((pawn_rank[LIGHT][f - 1] == 0) &&
      (pawn_rank[LIGHT][f + 1] == 0))
    r -= ISOLATED_PAWN_PENALTY;

  /* if it's not isolated, it might be backwards */
  else if ((pawn_rank[LIGHT][f - 1] < ROW(sq)) &&
      (pawn_rank[LIGHT][f + 1] < ROW(sq)))
    r -= BACKWARDS_PAWN_PENALTY;

  /* add a bonus if the pawn is passed */
  if ((pawn_rank[DARK][f - 1] >= ROW(sq)) &&
      (pawn_rank[DARK][f] >= ROW(sq)) &&
      (pawn_rank[DARK][f + 1] >= ROW(sq)))
    r += (7 - ROW(sq)) * PASSED_PAWN_BONUS;

  return r;
}

int eval_dark_pawn(int sq)
{
  int r;  /* the value to return */
  int f;  /* the pawn's file */

  r = 0;
  f = COL(sq) + 1;

  r += pawn_pcsq[flip[sq]];

  /* if there's a pawn behind this one, it's doubled */
  if (pawn_rank[DARK][f] < ROW(sq))
    r -= DOUBLED_PAWN_PENALTY;

  /* if there aren't any friendly pawns on either side of
     this one, it's isolated */
  if ((pawn_rank[DARK][f - 1] == 7) &&
      (pawn_rank[DARK][f + 1] == 7))
    r -= ISOLATED_PAWN_PENALTY;

  /* if it's not isolated, it might be backwards */
  else if ((pawn_rank[DARK][f - 1] > ROW(sq)) &&
      (pawn_rank[DARK][f + 1] > ROW(sq)))
    r -= BACKWARDS_PAWN_PENALTY;

  /* add a bonus if the pawn is passed */
  if ((pawn_rank[LIGHT][f - 1] <= ROW(sq)) &&
      (pawn_rank[LIGHT][f] <= ROW(sq)) &&
      (pawn_rank[LIGHT][f + 1] <= ROW(sq)))
    r += ROW(sq) * PASSED_PAWN_BONUS;

  return r;
}

int eval_light_king(int sq)
{
  int r;  /* the value to return */
  int i;

  r = king_pcsq[sq];

  /* if the king is castled, use a special function to evaluate the
     pawns on the appropriate side */
  if (COL(sq) < 3) {
    r += eval_lkp(1);
    r += eval_lkp(2);
    r += eval_lkp(3) / 2;  /* problems with pawns on the c & f files
                  are not as severe */
  }
  else if (COL(sq) > 4) {
    r += eval_lkp(8);
    r += eval_lkp(7);
    r += eval_lkp(6) / 2;
  }

  /* otherwise, just assess a penalty if there are open files near
     the king */
  else {
    for (i = COL(sq); i <= COL(sq) + 2; ++i)
      if ((pawn_rank[LIGHT] == 0) &&
          (pawn_rank[DARK] == 7))
        r -= 10;
  }

  /* scale the king safety value according to the opponent's material;
     the premise is that your king safety can only be bad if the
     opponent has enough pieces to attack you */
  r *= piece_mat[DARK];
  r /= 3100;

  return r;
}

/* eval_lkp(f) evaluates the Light King Pawn on file f */

int eval_lkp(int f)
{
  int r = 0;

  if (pawn_rank[LIGHT][f] == 6);  /* pawn hasn't moved */
  else if (pawn_rank[LIGHT][f] == 5)
    r -= 10;  /* pawn moved one square */
  else if (pawn_rank[LIGHT][f] != 0)
    r -= 20;  /* pawn moved more than one square */
  else
    r -= 25;  /* no pawn on this file */

  if (pawn_rank[DARK][f] == 7)
    r -= 15;  /* no enemy pawn */
  else if (pawn_rank[DARK][f] == 5)
    r -= 10;  /* enemy pawn on the 3rd rank */
  else if (pawn_rank[DARK][f] == 4)
    r -= 5;   /* enemy pawn on the 4th rank */

  return r;
}

int eval_dark_king(int sq)
{
  int r;
  int i;

  r = king_pcsq[flip[sq]];
  if (COL(sq) < 3) {
    r += eval_dkp(1);
    r += eval_dkp(2);
    r += eval_dkp(3) / 2;
  }
  else if (COL(sq) > 4) {
    r += eval_dkp(8);
    r += eval_dkp(7);
    r += eval_dkp(6) / 2;
  }
  else {
    for (i = COL(sq); i <= COL(sq) + 2; ++i)
      if ((pawn_rank[LIGHT] == 0) &&
          (pawn_rank[DARK] == 7))
        r -= 10;
  }
  r *= piece_mat[LIGHT];
  r /= 3100;
  return r;
}

int eval_dkp(int f)
{
  int r = 0;

  if (pawn_rank[DARK][f] == 1);
  else if (pawn_rank[DARK][f] == 2)
    r -= 10;
  else if (pawn_rank[DARK][f] != 7)
    r -= 20;
  else
    r -= 25;

  if (pawn_rank[LIGHT][f] == 0)
    r -= 15;
  else if (pawn_rank[LIGHT][f] == 2)
    r -= 10;
  else if (pawn_rank[LIGHT][f] == 3)
    r -= 5;

  return r;
}
Parent - - By Thomas Plaschke Date 2021-07-12 20:17
Mir ist dieser Code aufgefallen:
Code:
int pawn_rank[2][10];
...

int eval()
{
  int i;
...
  /* this is the first pass: set up pawn_rank, piece_mat, and pawn_mat. */
  for (i = 0; i < 10; ++i) {
    pawn_rank[LIGHT] = 0;
    pawn_rank[DARK] = 7;
  }
...
}

Setzen Compiler das als pawn_rank[LIGHT][ i ] = 0; pawn_rank[DARK][ i ] = 7; um?
pawn_rank[LIGHT] und pawn_rank[DARK] sind als Ausdrücke eigentlich Adressen und können (in diesem Kontext) keine Werte zugewiesen werden.
Ist das der originale TSCP-Quelltext?

Viele Grüße
Th. Plaschke
Parent - - By Lothar Jung Date 2021-07-12 21:49
Hallo Thomas,

schön, dass Du dabei bist.

Der C-Code von eval ist aus dem Quellcode des TSCP Programms.
Ich hatte die Quelle angegeben, Homepage des Autors.

Ich bin jetzt noch in Frankreich, ohne PC und Compiler.
Ich würde erstmal das Progamm compilieren und schauen, was der Compiler anmeckert.
Die Routine füllt das Array mit den Bauernwerten.

Wieso 10 Schleifendurchläufe bei int Werten von 0 bis 7?

Grüße

Lothar
Parent - By Thomas Plaschke Date 2021-07-12 21:57

>Wieso 10 Schleifendurchläufe bei int Werten von 0 bis 7?


Steht im Kommentar zur Deklaration von pawn_rank[2][10].
Code:
/* pawn_rank[x][y] is the rank of the least advanced pawn of color x on file
   y - 1. There are "buffer files" on the left and right to avoid special-case
   logic later. If there's no pawn on a rank, we pretend the pawn is
   impossibly far advanced (0 for LIGHT and 7 for DARK). This makes it easy to
   test for pawns on a rank and it simplifies some pawn evaluation code. */
TDM-GCC 4.9.2 gibt die Fehlermeldung incompatible types in assignment of 'int' to 'int [10]' aus.

Ich hatte den Code vor Jahren schon mal am Wickel und den Code korrigiert - wie ich eben bemerkt habe.

Viele Grüße
Th. Plaschke
Up Topic Hauptforen / Schachprogrammierung / Stellungsbewertung

Powered by mwForum 2.29.3 © 1999-2014 Markus Wichitill