void hdist_table_generate() {
  int size = 10;
  int size2 = 205;

  float hdist_table[size2][size2];
  memset(&hdist_table, 0, sizeof(hdist_table));

  for (int af = 0; af < size; af++) {
    for (int ar = 0; ar < size; ar++) {
      for (int bf = 0; bf < size; bf++) {
        for (int br = 0; br < size; br++) {
          square_t a = square_of(af, ar);
          square_t b = square_of(bf, br);
          int df = abs(af - bf);
          int dr = abs(ar - br);
          hdist_table[a][b] = (1.0 / (df + 1)) + (1.0 / (dr + 1));
          printf("%d %d %d %d %.6f\n", a, b, df, dr, hdist_table[a][b]);
        }
      }
    }
  }

  FILE *f = fopen("hdist_table.h", "w");
  fprintf(f, "static float hdist_table[%d][%d] = {\n", size2, size2);
  for (int a = 0; a < size2; a++) {
    fprintf(f, "{");
    for (int b = 0; b < size2; b++) {
      fprintf(f, "%.6f,", hdist_table[a][b]);
    }
    fprintf(f, "},\n");
  }
  fprintf(f, "};\n");
  fclose(f);
}
// KFACE heuristic: bonus (or penalty) for King facing toward the other King
ev_score_t kface(position_t *p, fil_t f, rnk_t r) {
  square_t sq = square_of(f, r);
  piece_t x = p->board[sq];
  color_t c = color_of(x);
  square_t opp_sq = p->kloc[opp_color(c)];
  int delta_fil = fil_of(opp_sq) - f;
  int delta_rnk = rnk_of(opp_sq) - r;
  int bonus;

  switch (ori_of(x)) {
    case NN:
      bonus = delta_rnk;
      break;

    case EE:
      bonus = delta_fil;
      break;

    case SS:
      bonus = -delta_rnk;
      break;

    case WW:
      bonus = -delta_fil;
      break;

    default:
      bonus = 0;
      tbassert(false, "Illegal King orientation.\n");
  }

  return (bonus * KFACE) / (abs(delta_rnk) + abs(delta_fil));
}
// KAGGRESSIVE heuristic: bonus for King with more space to back
ev_score_t kaggressive_old(position_t *p, fil_t f, rnk_t r) {
  square_t sq = square_of(f, r);
  piece_t x = p->board[sq];
  color_t c = color_of(x);
  tbassert(ptype_of(x) == KING, "ptype_of(x) = %d\n", ptype_of(x));

  square_t opp_sq = p->kloc[opp_color(c)];
  fil_t of = fil_of(opp_sq);
  rnk_t _or = (rnk_t) rnk_of(opp_sq);

  int delta_fil = of - f;
  int delta_rnk = _or - r;

  int bonus = 0;

  if (delta_fil >= 0 && delta_rnk >= 0) {
    bonus = (f + 1) * (r + 1);
  } else if (delta_fil <= 0 && delta_rnk >= 0) {
    bonus = (BOARD_WIDTH - f) * (r + 1);
  } else if (delta_fil <= 0 && delta_rnk <= 0) {
    bonus = (BOARD_WIDTH - f) * (BOARD_WIDTH - r);
  } else if (delta_fil >= 0 && delta_rnk <= 0) {
    bonus = (f + 1) * (BOARD_WIDTH - r);
  }

  return (KAGGRESSIVE * bonus) / (BOARD_WIDTH * BOARD_WIDTH);
}
Beispiel #4
0
// returns 0 if no error
static int get_sq_from_str(char *fen, int *c_count, int *sq) {
  char c, next_c;

  while ((c = fen[*c_count++]) != '\0') {
    // skip whitespace
    if ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r')) {
      continue;
    } else {
      break;  // found nonwhite character
    }
  }

  if (c == '\0') {
    *sq = 0;
    return 0;
  }

  // get file and rank
  if ((c - 'a' < 0) || (c - 'a') > BOARD_WIDTH) {
    fen_error(fen, *c_count, "Illegal specification of last move");
    return 1;
  }
  next_c = fen[*c_count++];
  if (next_c == '\0') {
    fen_error(fen, *c_count, "FEN ended before last move fully specified");

    if ((next_c - '0' < 0) || (next_c - '0') > BOARD_WIDTH) {
      fen_error(fen, *c_count, "Illegal specification of last move");
      return 1;
    }

    *sq = square_of(next_c - '0', c - 'a');
    return 0;
  }
  return 0;
}
// H_SQUARES_ATTACKABLE heuristic: for shooting the enemy king
int h_squares_attackable(position_t *p, color_t c) {
  char* laser_map;
  if (c == WHITE) {
    laser_map = laser_map_white;
  } else {
    laser_map = laser_map_black;
  }
  square_t o_king_sq = p->kloc[opp_color(c)];
  tbassert(ptype_of(p->board[o_king_sq]) == KING,
           "ptype: %d\n", ptype_of(p->board[o_king_sq]));
  tbassert(color_of(p->board[o_king_sq]) != c,
           "color: %d\n", color_of(p->board[o_king_sq]));

  float h_attackable_temp = 0;
  for (fil_t f = 0; f < BOARD_WIDTH; f++) {
    for (rnk_t r = 0; r < BOARD_WIDTH; r++) {
      square_t sq = square_of(f, r);
      if (laser_map[sq] != 0) {
        h_attackable_temp += h_dist(sq, o_king_sq);
      }
    }
  }
  return h_attackable_temp;
}
Beispiel #6
0
// Translate a fen string into a board position struct
//
int fen_to_pos(position_t *p, char *fen) {
  static position_t dmy1, dmy2;

  // these sentinels simplify checking previous
  // states without stepping past null pointers.
  dmy1.key = 0;
  dmy1.victims.stomped = 1;
  dmy1.victims.zapped = 1;
  dmy1.history = NULL;

  dmy2.key = 0;
  dmy2.victims.stomped = 1;
  dmy2.victims.zapped = 1;
  dmy2.history = &dmy1;


  p->key = 0;          // hash key
  p->victims.stomped = 0;       // piece destroyed by stomper
  p->victims.zapped = 0;       // piece destroyed by shooter
  p->history = &dmy2;  // history

  memset(&base_board, 0, sizeof(full_board_t));

  if (fen[0] == '\0') {  // Empty FEN => use starting position
    fen = "ss3nw5/3nw2nw3/2nw7/1nw6SE1/nw9/9SE/1nw6SE1/7SE2/3SE2SE3/5SE3NN W";
  }

  int c_count = 0;  // Invariant: fen[c_count] is next char to be read

  for (int i = 0; i < ARR_SIZE; ++i) {
    base_board.board[i] = INVALID_PIECE;
  }

  c_count = parse_fen_board(p, fen);
  if (!c_count) {
    return 1;  // parse error of board
  }

  // King check

  int Kings[2] = {0, 0};
  for (fil_t f = 0; f < BOARD_WIDTH; ++f) {
    for (rnk_t r = 0; r < BOARD_WIDTH; ++r) {
      square_t sq = square_of(r, f);
      piece_t x = base_board.board[sq];
      ptype_t typ = ptype_of(x);
      if (typ == KING) {
        Kings[color_of(x)]++;
      }
    }
  }

  if (Kings[WHITE] == 0) {
    fen_error(fen, c_count, "No White Kings");
    return 1;
  } else if (Kings[WHITE] > 1) {
    fen_error(fen, c_count, "Too many White Kings");
    return 1;
  } else if (Kings[BLACK] == 0) {
    fen_error(fen, c_count, "No Black Kings");
    return 1;
  } else if (Kings[BLACK] > 1) {
    fen_error(fen, c_count, "Too many Black Kings");
    return 1;
  }

  char c;
  bool done = false;
  // Look for color to move and set ply accordingly
  while (!done && (c = fen[c_count++]) != '\0') {
    switch (c) {
      // ignore whitespace until the end
      case ' ':
      case '\t':
      case '\n':
      case '\r':
        break;

        // White to move
      case 'W':
      case 'w':
        p->ply = 0;
        base_board.ply = 0;
        done = true;
        break;

        // Black to move
      case 'B':
      case 'b':
        p->ply = 1;
        base_board.ply = 1;
        done = true;
        break;

      default:
        fen_error(fen, c_count, "Must specify White (W) or Black (B) to move");
        return 1;
        break;
    }
  }

  // Look for last move, if it exists
  int lm_from_sq, lm_to_sq, lm_rot;
  if (get_sq_from_str(fen, &c_count, &lm_from_sq) != 0) {  // parse error
    return 1;
  }
  if (lm_from_sq == 0) {   // from-square of last move
    p->last_move = 0;  // no last move specified
    p->key = compute_zob_key(p, &base_board);
    return 0;
  }

  c = fen[c_count];

  switch (c) {
    case 'R':
    case 'r':
      lm_to_sq = lm_from_sq;
      lm_rot = RIGHT;
      break;
    case 'U':
    case 'u':
      lm_to_sq = lm_from_sq;
      lm_rot = UTURN;
      break;
    case 'L':
    case 'l':
      lm_to_sq = lm_from_sq;
      lm_rot = LEFT;
      break;

    default:  // Not a rotation
      lm_rot = NONE;
      if (get_sq_from_str(fen, &c_count, &lm_to_sq) != 0) {
        return 1;
      }
      break;
  }
  p->last_move = move_of(EMPTY, lm_rot, lm_from_sq, lm_to_sq);
  p->key = compute_zob_key(p, &base_board);

  return 0;  // everything is okay
}
Beispiel #7
0
// parse_fen_board
// Input:   board representation as a fen string
//          unpopulated board position struct
// Output:   index of where board description ends or 0 if parsing error
//          (populated) board position struct
static int parse_fen_board(position_t *p, char *fen) {
  // Invariant: square (f, r) is last square filled.
  // Fill from last rank to first rank, from first file to last file
  fil_t f = -1;
  rnk_t r = BOARD_WIDTH - 1;

  // Current and next characters from input FEN description
  char c, next_c;

  // Invariant: fen[c_count] is next character to be read
  int c_count = 0;

  // Loop also breaks internally if (f, r) == (BOARD_WIDTH-1, 0)
  while ((c = fen[c_count++]) != '\0') {
    int ori;
    ptype_t typ;

    switch (c) {
      // ignore whitespace until the end
      case ' ':
      case '\t':
      case '\n':
      case '\r':
        if ((f == BOARD_WIDTH - 1) && (r == 0)) {  // our job is done
          return c_count;
        }
        break;

        // digits
      case '1':
        if (fen[c_count] == '0') {
          c_count++;
          c += 9;
        }
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        while (c > '0') {
          if (++f >= BOARD_WIDTH) {
            fen_error(fen, c_count, "Too many squares in rank.\n");
            return 0;
          }
          base_board.board[square_of(r, f)] = EMPTY_PIECE;
          c--;
        }
        break;

        // pieces
      case 'N':
        if (++f >= BOARD_WIDTH) {
          fen_error(fen, c_count, "Too many squares in rank");
          return 0;
        }
        next_c = fen[c_count++];

        if (next_c == 'N') {  // White King facing North
          ori = NN;
          typ = KING;
        } else if (next_c == 'W') {  // White Pawn facing NW
          ori = NW;
          typ = PAWN;
        } else if (next_c == 'E') {  // White Pawn facing NE
          ori = NE;
          typ = PAWN;
        } else {
          fen_error(fen, c_count+1, "Syntax error");
          return 0;
        }
        set_piece(p, r, f, typ, ori, WHITE, &base_board);
        break;

      case 'n':
        if (++f >= BOARD_WIDTH) {
          fen_error(fen, c_count, "Too many squares in rank");
          return 0;
        }
        next_c = fen[c_count++];

        if (next_c == 'n') {  // Black King facing North
          ori = NN;
          typ = KING;
        } else if (next_c == 'w') {  // Black Pawn facing NW
          ori = NW;
          typ = PAWN;
        } else if (next_c == 'e') {  // Black Pawn facing NE
          ori = NE;
          typ = PAWN;
        } else {
          fen_error(fen, c_count+1, "Syntax error");
          return 0;
        }
        set_piece(p, r, f, typ, ori, BLACK, &base_board);
        break;

      case 'S':
        if (++f >= BOARD_WIDTH) {
          fen_error(fen, c_count, "Too many squares in rank");
          return 0;
        }
        next_c = fen[c_count++];

        if (next_c == 'S') {  // White King facing SOUTH
          ori = SS;
          typ = KING;
        } else if (next_c == 'W') {  // White Pawn facing SW
          ori = SW;
          typ = PAWN;
        } else if (next_c == 'E') {  // White Pawn facing SE
          ori = SE;
          typ = PAWN;
        } else {
          fen_error(fen, c_count+1, "Syntax error");
          return 0;
        }
        set_piece(p, r, f, typ, ori, WHITE, &base_board);
        break;

      case 's':
        if (++f >= BOARD_WIDTH) {
          fen_error(fen, c_count, "Too many squares in rank");
          return 0;
        }
        next_c = fen[c_count++];

        if (next_c == 's') {  // Black King facing South
          ori = SS;
          typ = KING;
        } else if (next_c == 'w') {  // Black Pawn facing SW
          ori = SW;
          typ = PAWN;
        } else if (next_c == 'e') {  // Black Pawn facing SE
          ori = SE;
          typ = PAWN;
        } else {
          fen_error(fen, c_count+1, "Syntax error");
          return 0;
        }
        set_piece(p, r, f, typ, ori, BLACK, &base_board);
        break;

      case 'E':
        if (++f >= BOARD_WIDTH) {
          fen_error(fen, c_count, "Too many squares in rank");
          return 0;
        }
        next_c = fen[c_count++];

        if (next_c == 'E') {  // White King facing East
          set_piece(p, r, f, KING, EE, WHITE, &base_board);
        } else {
          fen_error(fen, c_count+1, "Syntax error");
          return 0;
        }
        break;

      case 'W':
        if (++f >= BOARD_WIDTH) {
          fen_error(fen, c_count, "Too many squares in rank");
          return 0;
        }
        next_c = fen[c_count++];

        if (next_c == 'W') {  // White King facing West
        	set_piece(p, r, f, KING, WW, WHITE, &base_board);
        } else {
          fen_error(fen, c_count+1, "Syntax error");
          return 0;
        }
        break;

      case 'e':
        if (++f >= BOARD_WIDTH) {
          fen_error(fen, c_count, "Too many squares in rank");
          return 0;
        }
        next_c = fen[c_count++];

        if (next_c == 'e') {  // Black King facing East
        	set_piece(p, r, f, KING, EE, BLACK, &base_board);
        } else {
          fen_error(fen, c_count+1, "Syntax error");
          return 0;
        }
        break;

      case 'w':
        if (++f >= BOARD_WIDTH) {
          fen_error(fen, c_count, "Too many squares in rank");
          return 0;
        }
        next_c = fen[c_count++];

        if (next_c == 'w') {  // Black King facing West
        	set_piece(p, r, f, KING, WW, BLACK, &base_board);
        } else {
          fen_error(fen, c_count+1, "Syntax error");
          return 0;
        }
        break;

        // end of rank
      case '/':
        if (f == BOARD_WIDTH - 1) {
          f = -1;
          if (--r < 0) {
            fen_error(fen, c_count, "Too many ranks");
            return 0;
          }
        } else {
          fen_error(fen, c_count, "Too few squares in rank");
          return 0;
        }
        break;

      default:
        fen_error(fen, c_count, "Syntax error");
        return 0;
        break;
    }  // end switch
  }  // end while

  if ((f == BOARD_WIDTH - 1) && (r == 0)) {
    return c_count;
  } else {
    fen_error(fen, c_count, "Too few squares specified");
    return 0;
  }
}
// Static evaluation.  Returns score
score_t eval(position_t *p, bool verbose) {
  // seed rand_r with a value of 1, as per
  // http://linux.die.net/man/3/rand_r
  static __thread unsigned int seed = 1;
  // verbose = true: print out components of score
  ev_score_t score[2] = { 0, 0 };
  //  int corner[2][2] = { {INF, INF}, {INF, INF} };
  ev_score_t bonus;

  //char buf[MAX_CHARS_IN_MOVE];
  color_t c;
  for (fil_t f = 0; f < BOARD_WIDTH; f++) {
    for (rnk_t r = 0; r < BOARD_WIDTH; r++) {
      square_t sq = square_of(f, r);
      piece_t x = p->board[sq];

      //if (verbose) {
      //  square_to_str(sq, buf, MAX_CHARS_IN_MOVE);
      //}

      switch (ptype_of(x)) {
        case EMPTY:
          break;
        case PAWN:
          c = color_of(x);

          // MATERIAL heuristic: Bonus for each Pawn
          bonus = PAWN_EV_VALUE;
          // if (verbose) {
          //  printf("MATERIAL bonus %d for %s Pawn on %s\n", bonus, color_to_str(c), buf);
          // }
          score[c] += bonus;

          // PBETWEEN heuristic
          bonus = pbetween(p, f, r);
          // if (verbose) {
          //   printf("PBETWEEN bonus %d for %s Pawn on %s\n", bonus, color_to_str(c), buf);
          // }
          score[c] += bonus;

          // PCENTRAL heuristic
          bonus = pcentral(f, r);
          // if (verbose) {
          //   printf("PCENTRAL bonus %d for %s Pawn on %s\n", bonus, color_to_str(c), buf);
         //  }
          score[c] += bonus;
          break;

        case KING:
          c = color_of(x);

          // KFACE heuristic
          bonus = kface(p, f, r);
          // if (verbose) {
          //   printf("KFACE bonus %d for %s King on %s\n", bonus,
          //          color_to_str(c), buf);
          // }
          score[c] += bonus;

          // KAGGRESSIVE heuristic
          color_t othercolor = opp_color(c);
          square_t otherking = p->kloc[othercolor];
          fil_t otherf = fil_of(otherking);
          rnk_t otherr = rnk_of(otherking);
          bonus = kaggressive(f, r, otherf, otherr);
          assert(bonus == kaggressive_old(p, f, r));

          // if (verbose) {
          //   printf("KAGGRESSIVE bonus %d for %s King on %s\n", bonus, color_to_str(c), buf);
         //  }
          score[c] += bonus;
          break;
        case INVALID:
          break;
        default:
          tbassert(false, "Jose says: no way!\n");   // No way, Jose!
      }
      laser_map_black[sq] = 0;
      laser_map_white[sq] = 0;
    }
  }
   
  int black_pawns_unpinned = mark_laser_path(p, laser_map_white, WHITE, 1);  // 1 = path of laser with no moves
  
  ev_score_t w_hattackable = HATTACK * (int) h_attackable;
  score[WHITE] += w_hattackable;
  // if (verbose) {
  //   printf("HATTACK bonus %d for White\n", w_hattackable);
  // }

  // PAWNPIN Heuristic --- is a pawn immobilized by the enemy laser.
  int b_pawnpin = PAWNPIN * black_pawns_unpinned;
  score[BLACK] += b_pawnpin;

  int b_mobility = MOBILITY * mobility(p, BLACK);
  score[BLACK] += b_mobility;
  // if (verbose) {
  //   printf("MOBILITY bonus %d for Black\n", b_mobility);
  // }

  int white_pawns_unpinned = mark_laser_path(p, laser_map_black, BLACK, 1);  // 1 = path of laser with no moves
  
  ev_score_t b_hattackable = HATTACK * (int) h_attackable;
  score[BLACK] += b_hattackable;
  // if (verbose) {
  //   printf("HATTACK bonus %d for Black\n", b_hattackable);
  // }

  int w_mobility = MOBILITY * mobility(p, WHITE);
  score[WHITE] += w_mobility;
  // if (verbose) {
  //   printf("MOBILITY bonus %d for White\n", w_mobility);
  // }
  int w_pawnpin = PAWNPIN * white_pawns_unpinned;
  score[WHITE] += w_pawnpin;


  // score from WHITE point of view
  ev_score_t tot = score[WHITE] - score[BLACK];

  if (RANDOMIZE) {
    ev_score_t  z = rand_r(&seed) % (RANDOMIZE*2+1);
    tot = tot + z - RANDOMIZE;
  }

  if (color_to_move_of(p) == BLACK) {
    tot = -tot;
  }

  return tot / EV_SCORE_RATIO;
}