2009年3月19日 星期四

ACM10196 西洋棋之"將軍!!"

[ACM] Q10196 - 10196 - Check The Check

(來源 : Lucky貓 http://luckycat.kshs.kh.edu.tw/)

你的任務是寫一個程式,讀入一西洋棋盤的狀態,然後回答是否有國王(king)正處於可以攻擊(check)的狀態。(像中國象棋的"將軍")

白方以大寫字元來表達各個角色,黑方以小寫字元來表達各個角色。棋賽一開始時白方在棋盤下方,黑方在棋盤上方。如果你對西洋棋不熟的話,以下是各棋子角色的說明:

  • Pawn(士兵,以p或P表示)一次只能往前走一步,但是攻擊時卻是往左前方或右前方一格攻擊。
  • Knight(騎士,以n或N表示)走法比較特別,是走L形的,像中國象棋的馬,參考下面的圖。
  • Bishop(主教,以b或B表示)可以走對角線任意格。
  • Rook(城堡,以r或R表示)可以走直線任意格。
  • Queen(皇后,以q或Q表示)可以走對角線及直線任意格。像Bishop及Rook的綜合體。
  • King(國王,以k或K表示)可以走前後左右及對角線一格。

下圖就是各棋子的走法(*表示該棋子可以攻擊的格子)

Pawn       Rook       Bishop     Queen      King       Knight
........ ...*.... .......* ...*...* ........ ........
........ ...*.... *.....*. *..*..*. ........ ........
........ ...*.... .*...*.. .*.*.*.. ........ ..*.*...
........ ...*.... ..*.*... ..***... ..***... .*...*..
...p.... ***r**** ...b.... ***q**** ..*k*... ...n....
..*.*... ...*.... ..*.*... ..***... ..***... .*...*..
........ ...*.... .*...*.. .*.*.*.. ........ ..*.*...
........ ...*.... *.....*. *..*..*. ........ ........


記住:只有騎士可以跨過棋子攻擊,而士兵的攻擊是有方向性的(白士兵只能向左上、右上攻擊,黑士兵只能向左下、右下攻擊)

Input

每組測試資料8列,每列有8個字元。'.'
代表空白格子而其他英文字元則代表上面說明的各角色。不會有不該出現的字元出現,而且我們也保證不會有黑白雙方的國王均處於被check的狀態。

測試資料間有一空白列。輸入的最後一組測試資料內容全為'.',代表輸入結束。(此組測試不需有輸出)

Output

每組測試資料請輸出下列3種其中之一:

Game #d: white king is in check.
Game #d: black king is in check.
Game #d: no king is in check.

這裡d代表第幾組測試資料,從1開始。

Sample input

..k.....
ppp.pppp
........
.R...B..
........
........
PPPPPPPP
K.......

rnbqkbnr
pppppppp
........
........
........
........
PPPPPPPP
RNBQKBNR

rnbqk.nr
ppp..ppp
....p...
...p....
.bPP....
.....N..
PP..PPPP
RNBQKB.R

........
........
........
........
........
........
........
........

Sample Output

Game #1: black king is in check.
Game #2: no king is in check.
Game #3: white king is in check.

【程式碼】
#include
#include
 
char board[8][8]; // 棋盤
 
bool find( int r, int c, char ch1)
{ // 定點尋找
  if(r<0 || r>=8 || c<0 || c>=8) return false;
  return (board[r][c]==ch1 );
}

 
bool loopfind( int r, int c, int dr, int dc, char ch1, char ch2 )
{ // 依向尋找
  if(r<0 || r>=8 || c<0 || c>=8) return false;
  if (board[r][c]=='.')
     return loopfind( r+dr, c+dc, dr, dc, ch1, ch2 );
  return (board[r][c]==ch1 || board[r][c]==ch2);
}

 
bool CheckKing(int King, char *ch) 
{ //ch : [0]Pawn [1]Rook [2]Bishop [3]Queen [4]Knight
 int d = (ch[0]>='a')? -1: 1;
 int c = King%8;
 int r = King/8;
 
 return (find(r+d,c-1,ch[0]) || find(r+d,c+1,ch[0])
      || find(r-2,c-1,ch[4]) || find(r-2,c+1,ch[4]) 
      || find(r-1,c-2,ch[4]) || find(r-1,c+2,ch[4])
      || find(r+1,c-2,ch[4]) || find(r+1,c+2,ch[4])    
      || find(r+2,c-1,ch[4]) || find(r+2,c+1,ch[4])
      || loopfind(r-1,  c,-1, 0, ch[1], ch[3])
      || loopfind(r+1,  c, 1, 0, ch[1], ch[3])
      || loopfind(  r,c-1, 0,-1, ch[1], ch[3])
      || loopfind(  r,c+1, 0, 1, ch[1], ch[3])
      || loopfind(r-1,c-1,-1,-1, ch[2], ch[3])
      || loopfind(r+1,c+1, 1, 1, ch[2], ch[3])
      || loopfind(r+1,c-1, 1,-1, ch[2], ch[3])
      || loopfind(r-1,c+1,-1, 1, ch[2], ch[3]));
}

 
int main()
{
 char Wch[] = "PRBQN";  //白子--對黑王的威脅
 char Bch[] = "prbqn";  //黑子--對白王的威脅
 char ch, WK, Bk;
 
 for(int i=1; ;i++)
 {
   bool empty = true;
   for(int p=0; p<64; p++)
   { // 取得(輸入)盤面
     do{ scanf("%c", &ch);  
     }while(ch<'.');
     if (ch!='.') empty=false; //不是空棋盤
     if (ch=='k') Bk = p;  // 黑王位置
     if (ch=='K') WK = p;  // 白王位置
     board[p/8][p%8]=ch;
   }
   if (empty) break;  // 空棋盤 -- 離開
   if (CheckKing(WK, Bch))      // 檢查白王
       printf("Game #%d: white king is in check.\n",i);
   else if (CheckKing(Bk, Wch)) // 檢查黑王
       printf("Game #%d: black king is in check.\n",i);
   else
       printf("Game #%d: no king is in check.\n",i);
 }
 return 0;
}

// ====== END

沒有留言:

張貼留言