Check the Check

2013-04-14 Robert Zhang 更多博文 » 博客 » GitHub »

原文链接 http://huiming.io/2013/04/14/check-the-check.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


分析:不需要一般象棋程序的“着法生成器”也可以求解<!--more-->

#include <iostream>
#include <vector>

using namespace std;

typedef char Board[8][8];
typedef struct _Position {
  int row;
  int col;
} Position;

bool load_board(Board & board, Position & k, Position & K) {
  bool empty = true;
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      char ch;
      if (!(cin >> ch))
        break;

      if (empty && ch != '.')
        empty = false;

      board[i][j] = ch;

      if (ch == 'k') {
        k.row = i;
        k.col = j;
      }
      else if (ch == 'K') {
        K.row = i;
        K.col = j;
      }
    }
  }
  return !empty;
}

bool check_black(const Board & board, const Position & k) {
  //horizontal check
  for (int i = k.col + 1; i < 8; i++) {
    char ch = board[k.row][i];
    if (ch == '.')
      continue;
    if (ch == 'R' || ch == 'Q')
      return true;
    break;
  }

  for (int i = k.col - 1; i >= 0; i--) {
    char ch = board[k.row][i];
    if (ch == '.')
      continue;
    if (ch == 'R' || ch == 'Q')
      return true;
    break;
  }

  //vertical check
  for (int i = k.row - 1; i >= 0; i--) {
    char ch = board[i][k.col];
    if (ch == '.')
      continue;
    if (ch == 'R' || ch == 'Q')
      return true;
    break;
  }

  for (int i = k.row + 1; i < 8; i++) {
    char ch = board[i][k.col];
    if (ch == '.')
      continue;
    if (ch == 'R' || ch == 'Q')
      return true;
    break;
  }

  //diagonal check
  for (int i = k.row + 1, j = k.col + 1; i < 8 && j < 8; i++, j++) {
    char ch = board[i][j];
    if (ch == '.')
      continue;
    if (ch == 'B' || ch == 'Q' || (ch == 'P' && i == k.row + 1))
      return true;
    break;
  }

  for (int i = k.row + 1, j = k.col - 1; i < 8 && j >= 0; i++, j--) {
    char ch = board[i][j];
    if (ch == '.')
      continue;
    if (ch == 'B' || ch == 'Q' || (ch == 'P' && i == k.row + 1))
      return true;
    break;
  }

  for (int i = k.row - 1, j = k.col - 1; i >= 0 && j >= 0; i--, j--) {
    char ch = board[i][j];
    if (ch == '.')
      continue;
    if (ch == 'B' || ch == 'Q')
      return true;
    break;
  }

  for (int i = k.row - 1, j = k.col + 1; i >= 0 && j < 8; i--, j++) {
    char ch = board[i][j];
    if (ch == '.')
      continue;
    if (ch == 'B' || ch == 'Q')
      return true;
    break;
  }

  //knight check
  Position pos[8];
  pos[0].row = k.row + 1;
  pos[0].col = k.col + 2;

  pos[1].row = k.row + 2;
  pos[1].col = k.col + 1;

  pos[2].row = k.row + 2;
  pos[2].col = k.col - 1;

  pos[3].row = k.row + 1;
  pos[3].col = k.col - 2;

  pos[4].row = k.row - 1;
  pos[4].col = k.col - 2;

  pos[5].row = k.row - 2;
  pos[5].col = k.col - 1;

  pos[6].row = k.row - 2;
  pos[6].col = k.col + 1;

  pos[7].row = k.row - 1;
  pos[7].col = k.col + 2;

  for (int i = 0; i < 8; i++) {
    Position & p = pos[i];
    if (p.row < 8 && p.row >= 0 && p.col < 8 && p.col >= 0
      && board[p.row][p.col] == 'N')
      return true;
  }

  return false;
}

inline char flip_char(char ch) {
  if (ch == '.')
    return ch;
  return ch >= 'a' ? (ch - ('a' - 'A')) : (ch + ('a' - 'A'));
}

void flip_board(Board & board, Position & K) {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 4; j++) {
      char up = board[j][i];
      char down = board[7 - j][i];
      board[j][i] = flip_char(down);
      board[7 - j][i] = flip_char(up);
    }
  }
  K.row = 7 - K.row;
}

int check_board(Board & board, Position & k, Position & K) {
  if (check_black(board, k))
    return 1;
  flip_board(board, K);
  return check_black(board, K) ? 2 : 0;
}

int main() {
  Board board;
  Position k, K;
  int d = 0;
  while (load_board(board, k, K)) {
    int r = check_board(board, k, K);
    const char * who;
    switch (r) {
      case 0:
        who = "no king";
      break;
      case 1:
        who = "black king";
      break;
      case 2:
        who = "white king";
      break;
    }
    cout << "Game #" << ++d << ": " << who << " is in check." << endl;
  }
  return 0;
}