/** (C) 1999 World Xiangqi League, Confidential, All Rights Reserved */


public class GameRule {

  /** For BOARDPOS, would move from POS1 to POS2 be legal? */
  public static boolean isLegal(String boardPos, int pos1,int pos2) {
    if (sameArmy(boardPos,pos1,pos2))
      return false;
    else if (!moveRule(boardPos, pos1, pos2))
      return false;
    else if (isCheck(boardPos,pos1,pos2,1))
      return false;
    else
      return true;
  }

  /** For BOARDPOS, would move from POS1 to POS2 be legal? */  
  private static boolean moveRule(String boardPos,int pos1,int pos2) {
    int x1=xpos(pos1), y1=ypos(pos1);
    int x2=xpos(pos2), y2=ypos(pos2);

    char chess=boardPos.charAt(pos1);
    int mycolor=polarity(chess);
    char target=boardPos.charAt(pos2);
    char cap=Character.toUpperCase(chess);

    int i,j,k,dir=1;
    
    if (boardPos.indexOf('k')<45) dir=-1; //attacking direction

    switch(cap) {
    case(' '): {		// space/unoccupied
      return false;
    }
    case('P'): {		// pawn/bing
      if ((1 != (int)(Math.abs(y2-y1)+Math.abs(x2-x1)))||
	  mycolor*(y2-y1)*dir<0||((y1==y2)&&(dir*mycolor*(y1*10-45)<0))) {
	return false;
      }
      return true;
    }
    case('C'): {		// cannon/pao
      k=count(boardPos,pos1,pos2);
      if ((k==1 && target!=' ') || (k==0 &&target==' '))
	return true;
      return false;
    }
    case('R'): {		// chariot/rook/jiang
      if (count(boardPos,pos1,pos2)==0)
	return true;
      return false;
    }
    case('H'): {		// horse/knight/mar
      if (Math.abs((x1-x2)*(y1-y2)) !=2)
	return false;
      if (boardPos.charAt(pos(x1+(int)((x2-x1)/2),y1+(int)((y2-y1)/2))) != ' ')
	return false;
      return true;
    }
    case('E'): {		// elephant/bishop/xiang
      if (Math.abs(x1-x2)!=2 || Math.abs(y1-y2) != 2 ||
	  boardPos.charAt(pos((int)((x1+x2)/2),(int)((y1+y2)/2)))
	  != ' ' || dir*mycolor*(45-10*y2)<0)
	return false;
      return true;
    }
    case('A'): {		// advisor/guard/counsellor
      if (Math.abs((x1-x2)*(y1-y2)) !=1 ||
	  x2<3 || x2>5 || (y1<5 && y2>2) || (y1>4 && y2<7) )
	return false;
      return true;
    }
    case('K'): {		// king
      if (Math.abs(x1-x2)+Math.abs(y1-y2) !=1 ||
	  x2<3 || x2>5 || (y1<5 && y2>2) || (y1>4 && y2<7) )
	return false;
      return true;
    }
    }
    return true;
  }

  /** In BOARDPOS, who is in check right now? 0=red, 1=blue, -1=nobody. */
  public static int inCheck(String boardPos) {
    int redKing=boardPos.indexOf("K"); // pos
    int blueKing=boardPos.indexOf("k");
    for (int i=0;i<90;i++) {
      if (polarity(boardPos.charAt(i))*polarity('K') ==-1) {
        if (moveRule(boardPos,i,redKing))
          return 0;  //red is checked
      }
      if (polarity(boardPos.charAt(i))*polarity('k') ==-1) {
        if (moveRule(boardPos,i,blueKing))
          return 1;  //blue is checked
      }
    }
    return -1;
  }

  /** For BOARDPOS, will move from POS1 to POS2 create a check?
   * If WHO=1, will it check me? Else will it check my opponent.
   */
  private static boolean isCheck(String boardPos,int p1,int p2,int who) {
    int thecolor;
    char myKing,heKing;
    if (who==1)
      thecolor=polarity(boardPos.charAt(p1));
    else
      thecolor=-polarity(boardPos.charAt(p1));
    boardPos=makeMove(boardPos,p1,p2);
    if (thecolor==1) {
      myKing='K';
      heKing='k';
    } else {
      myKing='k';
      heKing='K';
    }
    p1=boardPos.indexOf(myKing);
    p2=boardPos.indexOf(heKing);
    for (int i=0;i<90;i++) {
      if (polarity(boardPos.charAt(i))*thecolor ==-1) {
	if (moveRule(boardPos,i,p1))
	  return true;
      }
    }
    if (who==1 && count(boardPos,p1,p2)==0)
      return true;
    else
      return false;
  }

  /** For BOARDPOS, how many legal moves does PLAYER have now? */
  public static int count(String boardPos, int who) {
    int pos1,pos2,count=0;
    for (pos1=0;pos1<90;pos1++) {
      if ((polarity(boardPos.charAt(who)) *
	   polarity(boardPos.charAt(pos1)))==-1) {
	for (pos2=0;pos2<90;pos2++) {
	  if (isLegal(boardPos,pos1,pos2)) {
	    count++;
	  }
	}
      }
    }
    return count;
  }

  // -----------------------------------------------------------------
  private static String makeMove(String boardPos, int pos1, int pos2) {
    char newBoard[];
    newBoard=boardPos.toCharArray();
    newBoard[pos2]=newBoard[pos1];
    newBoard[pos1]=' ';
    return String.valueOf(newBoard);
  }

  private static int xpos(int pos) { return pos-(int)(pos/9)*9; }
  private static int ypos(int pos) { return (pos-xpos(pos))/9; }
  private static int pos(int x,int y) { return x+y*9; }

  private static int polarity(char c) {
    if (c==' ')
      return 0;
    else if (Character.isUpperCase(c))
      return 1;			// red
    else
      return -1;		// blue
  }

  public static int count(String boardPos,int pos1,int pos2) {
    int x1=xpos(pos1);
    int y1=ypos(pos1);
    int x2=xpos(pos2);
    int y2=ypos(pos2);
    if (x1==x2) {
      int number=0;
      int nopos=Math.abs(y2-y1);
      for (int i=1;i<nopos;i++) {
	int bpos=pos(x1,y1+i*(y2-y1)/nopos);
	if (boardPos.charAt(bpos) != ' ') {
	  number++;
	}
      }
      return number;
    }
    if (y1==y2) {
      int number=0;
      int nopos=Math.abs(x2-x1);
      for (int i=1;i<nopos;i++) {
	int bpos=pos(x1+i*(x2-x1)/nopos,y1);
	if (boardPos.charAt(bpos) != ' ') {
	  number++;
	}
      }
      return number;
    }
    return -1;
  }

  private static boolean sameArmy(String boardPos,int pos1, int pos2) {
    return (polarity(boardPos.charAt(pos1)) ==
	    polarity(boardPos.charAt(pos2)));
  }
}

