Example #1
0
MOVE AlgebToMove(const char *str_mov)
{
    MOVE curr_move = 0;
    char square = 0;
    
    /*Pieced promoted to:*/                
    square = CharToPiece(str_mov[4]);
    curr_move += square;
    curr_move = curr_move << 8;

    /*DEST:*/
    square = CharToCoordinate(str_mov[3]) + CharToCoordinate(str_mov[2]);
    curr_move += square;
    curr_move = curr_move << 8;

    /*ORIG:*/
    square = CharToCoordinate(str_mov[1]) + CharToCoordinate(str_mov[0]);
    curr_move += square;

    return curr_move;
}
Example #2
0
int
NextUnit (char **p)
{	// Main parser routine
	int coord[4], n, result, piece, i;
	char type[4], promoted, separator, slash, *oldp, *commentEnd, c;
        int wom = quickFlag ? quickFlag&1 : WhiteOnMove(yyboardindex);

	// ********* try white first, because it is so common **************************
	if(**p == ' ' || **p == '\n' || **p == '\t') { parseStart = (*p)++; return Nothing; }


	if(**p == NULLCHAR) { // make sure there is something to parse
	    if(fromString) return 0; // we are parsing string, so the end is really the end
	    *p = inPtr = inputBuf;
	    if(!ReadLine()) return 0; // EOF
	} else if(inPtr > inputBuf + PARSEBUFSIZE/2) { // buffer fills up with already parsed stuff
	    char *q = *p, *r = inputBuf;
	    while(*r++ = *q++);
	    *p = inputBuf; inPtr = r - 1;
	}
	parseStart = oldp = *p; // remember where we begin


	// ********* attempt to recognize a SAN move in the leading non-blank text *****
	piece = separator = promoted = slash = n = 0;
	for(i=0; i<4; i++) coord[i] = -1, type[i] = NOTHING;
	if(**p == '+') (*p)++, promoted++;
	if(**p >= 'a' && **p <= 'z' && (*p)[1]== '@') piece =*(*p)++ + 'A' - 'a'; else
	if(**p >= 'A' && **p <= 'Z') {
	     piece = *(*p)++; // Note we could test for 2-byte non-ascii names here
	     if(**p == '/') slash = *(*p)++;
	}
        while(n < 4) {
	    if(**p >= 'a' && **p < 'x') coord[n] = *(*p)++ - 'a', type[n++] = ALPHABETIC;
	    else if((i = Number(p)) != BADNUMBER) coord[n] = i, type[n++] = NUMERIC;
	    else break;
	    if(n == 2 && type[0] == type[1]) { // if two identical types, the opposite type in between must have been missing
		type[2] = type[1]; coord[2] = coord[1];
		type[1] = NOTHING; coord[1] = -1; n++;
	    }
	}
	// we always get here, and might have read a +, a piece, and upto 4 potential coordinates
	if(n <= 2) { // could be from-square or disambiguator, when -:xX follow, or drop with @ directly after piece, but also to-square
	     if(**p == '-' || **p == ':' || **p == 'x' || **p == 'X' || // these cannot be move suffix, so to-square must follow
		 (**p == '@' || **p == '*') && n == 0 && !promoted && piece) { // P@ must also be followed by to-square
		separator = *(*p)++;
		if(n == 1) coord[1] = coord[0]; // must be disambiguator, but we do not know which yet
		n = 2;
		while(n < 4) { // attempt to read to-square
		    if(**p >= 'a' && **p < 'x') coord[n] = *(*p)++ - 'a', type[n++] = ALPHABETIC;
		    else if((i = Number(p)) != BADNUMBER) coord[n] = i, type[n++] = NUMERIC;
		    else break;
		}
	    } else if((**p == '+' || **p == '=') && n == 1 && piece && type[0] == NUMERIC) { // can be traditional Xiangqi notation
		separator = *(*p)++;
		n = 2;
		if((i = Number(p)) != BADNUMBER) coord[n] = i, type[n++] = NUMERIC;
	    } else if(n == 2) { // only one square mentioned, must be to-square
		while(n < 4) { coord[n] = coord[n-2], type[n] = type[n-2], coord[n-2] = -1, type[n-2] = NOTHING; n++; }
	    }
	} else if(n == 3 && type[1] != NOTHING) { // must be hyphenless disambiguator + to-square
	    for(i=3; i>0; i--) coord[i] = coord[i-1], type[i] = type[i-1]; // move to-square to where it belongs
	    type[1] = NOTHING; // disambiguator goes in first two positions
	    n = 4;
	}
	// we always get here; move must be completely read now, with to-square coord(s) at end
	if(n == 3) { // incomplete to-square. Could be Xiangqi traditional, or stuff like fxg
	    if(piece && type[1] == NOTHING && type[0] == NUMERIC && type[2] == NUMERIC &&
		(separator == '+' || separator == '=' || separator == '-')) {
		     // Xiangqi traditional

		return ImpossibleMove; // for now treat as invalid
	    }
	    // fxg stuff, but also things like 0-0, 0-1 and 1-0
	    if(!piece && type[1] == NOTHING && type[0] == ALPHABETIC && type[2] == ALPHABETIC
		 && (coord[0] != 14 || coord[2] != 14) /* reserve oo for castling! */ ) {
		piece = 'P'; n = 4; // kludge alert: fake full to-square
	    }
	} else if(n == 1 && type[0] == NUMERIC && coord[0] > 1) { while(**p == '.') (*p)++; return Nothing; } // fast exit for move numbers
	if(n == 4 && type[2] != type[3] && // we have a valid to-square (kludge: type[3] can be NOTHING on fxg type move)
		     (piece || !promoted) && // promoted indicator only valid on named piece type
	             (type[2] == ALPHABETIC || gameInfo.variant == VariantShogi)) { // in Shogi also allow alphabetic rank
	    DisambiguateClosure cl;
	    int fromX, fromY, toX, toY;

	    if(slash && (!piece || type[1] == NOTHING)) goto badMove; // slash after piece only in ICS long format
	    if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */

	    if(type[2] == NUMERIC) { // alpha-rank
		coord[2] = BOARD_RGHT - BOARD_LEFT - coord[2];
		coord[3] = BOARD_HEIGHT - coord[3];
		if(coord[0] >= 0) coord[0] = BOARD_RGHT - BOARD_LEFT - coord[0];
		if(coord[1] >= 0) coord[1] = BOARD_HEIGHT - coord[1];
	    }
	    toX = cl.ftIn = (currentMoveString[2] = coord[2] + 'a') - AAA;
	    toY = cl.rtIn = (currentMoveString[3] = coord[3] + '0') - ONE;
	    if(type[3] == NOTHING) cl.rtIn = -1; // for fxg type moves ask for toY disambiguation
	    else if(toY >= BOARD_HEIGHT || toY < 0)   return ImpossibleMove; // vert off-board to-square
	    if(toX < BOARD_LEFT || toX >= BOARD_RGHT) return ImpossibleMove;
	    if(piece) {
		cl.pieceIn = CharToPiece(wom ? piece : ToLower(piece));
		if(cl.pieceIn == EmptySquare) return ImpossibleMove; // non-existent piece
		if(promoted) cl.pieceIn = (ChessSquare) (PROMOTED cl.pieceIn);
	    } else cl.pieceIn = EmptySquare;
	    if(separator == '@' || separator == '*') { // drop move. We only get here without from-square or promoted piece
		fromY = DROP_RANK; fromX = cl.pieceIn;
		currentMoveString[0] = piece;
		currentMoveString[1] = '@';
		return LegalityTest(boards[yyboardindex], PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, fromY, fromX, toY, toX, NULLCHAR);
	    }
	    if(type[1] == NOTHING && type[0] != NOTHING) { // there is a disambiguator
		if(type[0] != type[2]) coord[0] = -1, type[1] = type[0], type[0] = NOTHING; // it was a rank-disambiguator
	    }
	    if(  type[1] != type[2] && // means fromY is of opposite type as ToX, or NOTHING
		(type[0] == NOTHING || type[0] == type[2]) ) { // well formed

		fromX = (currentMoveString[0] = coord[0] + 'a') - AAA;
		fromY = (currentMoveString[1] = coord[1] + '0') - ONE;
		currentMoveString[4] = cl.promoCharIn = PromoSuffix(p);
		currentMoveString[5] = NULLCHAR;
		if(type[0] != NOTHING && type[1] != NOTHING && type[3] != NOTHING) { // fully specified.
		    // Note that Disambiguate does not work for illegal moves, but flags them as impossible
		    if(piece) { // check if correct piece indicated
			ChessSquare realPiece = boards[yyboardindex][fromY][fromX];
			if(PieceToChar(realPiece) == '~') realPiece = (ChessSquare) (DEMOTED realPiece);
			if(!(appData.icsActive && PieceToChar(realPiece) == '+') && // trust ICS if it moves promoted pieces
			   piece && realPiece != cl.pieceIn) return ImpossibleMove;
		    }
		    result = LegalityTest(boards[yyboardindex], PosFlags(yyboardindex), fromY, fromX, toY, toX, cl.promoCharIn);
		    if (currentMoveString[4] == NULLCHAR) { // suppy missing mandatory promotion character
		      if(result == WhitePromotion  || result == BlackPromotion) {
		        switch(gameInfo.variant) {
			  case VariantCourier:
			  case VariantShatranj: currentMoveString[4] = PieceToChar(BlackFerz); break;
			  case VariantGreat:    currentMoveString[4] = PieceToChar(BlackMan); break;
			  case VariantShogi:    currentMoveString[4] = '+'; break;
			  default:              currentMoveString[4] = PieceToChar(BlackQueen);
			}
		      } else if(result == WhiteNonPromotion  || result == BlackNonPromotion) {
						currentMoveString[4] = '=';
		      }
		    } else if(appData.testLegality && gameInfo.variant != VariantSChess && // strip off unnecessary and false promo characters
		       !(result == WhitePromotion  || result == BlackPromotion ||
		         result == WhiteNonPromotion || result == BlackNonPromotion)) currentMoveString[4] = NULLCHAR;
		    return result;
		} else if(cl.pieceIn == EmptySquare) cl.pieceIn = wom ? WhitePawn : BlackPawn;
		cl.ffIn = type[0] == NOTHING ? -1 : coord[0] + 'a' - AAA;
		cl.rfIn = type[1] == NOTHING ? -1 : coord[1] + '0' - ONE;

	        Disambiguate(boards[yyboardindex], PosFlags(yyboardindex), &cl);

		if(cl.kind == ImpossibleMove && !piece && type[1] == NOTHING // fxg5 type
			&& toY == (wom ? 4 : 3)) { // could be improperly written e.p.
		    cl.rtIn += wom ? 1 : -1; // shift target square to e.p. square
		    Disambiguate(boards[yyboardindex], PosFlags(yyboardindex), &cl);
		    if((cl.kind != WhiteCapturesEnPassant && cl.kind != BlackCapturesEnPassant))
			return ImpossibleMove; // nice try, but no cigar
		}

		currentMoveString[0] = cl.ff + AAA;
		currentMoveString[1] = cl.rf + ONE;
		currentMoveString[3] = cl.rt + ONE;
		currentMoveString[4] = cl.promoChar;

		if((cl.kind == WhiteCapturesEnPassant || cl.kind == BlackCapturesEnPassant) && (Match("ep", p) || Match("e.p.", p)));

		return (int) cl.kind;
	    }
	}
badMove:// we failed to find algebraic move
	*p = oldp;


	// Next we do some common symbols where the first character commits us to things that cannot possibly be a move

	// ********* PGN tags ******************************************
	if(**p == '[') {
	    oldp = ++(*p);
	    if(Match("--", p)) { // "[--" could be start of position diagram
		if(!Scan(']', p) && (*p)[-3] == '-' && (*p)[-2] == '-') return PositionDiagram;
		*p = oldp;
	    }
	    SkipWhite(p);
	    if(isdigit(**p) || isalpha(**p)) {
		do (*p)++; while(isdigit(**p) || isalpha(**p) || **p == '+' ||
				**p == '-' || **p == '=' || **p == '_' || **p == '#');
		SkipWhite(p);
		if(**p == '"') {
		    (*p)++;
		    while(**p != '\n' && (*(*p)++ != '"'|| (*p)[-2] == '\\')); // look for unescaped quote
		    if((*p)[-1] !='"') { *p = oldp; Scan(']', p); return Comment; } // string closing delimiter missing
		    SkipWhite(p); if(*(*p)++ == ']') return PGNTag;
		}
	    }
	    Scan(']', p); return Comment;
	}

	// ********* SAN Castings *************************************
	if(**p == 'O' || **p == 'o' || **p == '0' && !Match("00:", p)) { // exclude 00 in time stamps
	    int castlingType = 0;
	    if(Match("O-O-O", p) || Match("o-o-o", p) || Match("0-0-0", p) ||
	       Match("OOO", p) || Match("ooo", p) || Match("000", p)) castlingType = 2;
	    else if(Match("O-O", p) || Match("o-o", p) || Match("0-0", p) ||
		    Match("OO", p) || Match("oo", p) || Match("00", p)) castlingType = 1;
	    if(castlingType) { //code from old parser, collapsed for both castling types, and streamlined a bit
		int rf, ff, rt, ft; ChessSquare king;
		char promo=NULLCHAR;

		if(gameInfo.variant == VariantSChess) promo = PromoSuffix(p);

		if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */

		if (wom) {
		    rf = 0;
		    rt = 0;
		    king = WhiteKing;
		} else {
	            rf = BOARD_HEIGHT-1;
        	    rt = BOARD_HEIGHT-1;
		    king = BlackKing;
		}
		ff = (BOARD_WIDTH-1)>>1; // this would be d-file
	        if (boards[yyboardindex][rf][ff] == king) {
		    /* ICS wild castling */
        	    ft = castlingType == 1 ? BOARD_LEFT+1 : (gameInfo.variant == VariantJanus ? BOARD_RGHT-2 : BOARD_RGHT-3);
		} else {
        	    ff = BOARD_WIDTH>>1; // e-file
	            ft = castlingType == 1 ? BOARD_RGHT-2 : BOARD_LEFT+2;
		}
		if(PosFlags(0) & F_FRC_TYPE_CASTLING) {
		    if (wom) {
			ff = initialRights[2];
			ft = initialRights[castlingType-1];
		    } else {
			ff = initialRights[5];
			ft = initialRights[castlingType+2];
		    }
		    if (appData.debugMode) fprintf(debugFP, "Parser FRC (type=%d) %d %d\n", castlingType, ff, ft);
		    if(ff == NoRights || ft == NoRights) return ImpossibleMove;
		}
		sprintf(currentMoveString, "%c%c%c%c%c",ff+AAA,rf+ONE,ft+AAA,rt+ONE,promo);
		if (appData.debugMode) fprintf(debugFP, "(%d-type) castling %d %d\n", castlingType, ff, ft);

	        return (int) LegalityTest(boards[yyboardindex],
			      PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: e.p.!
			      rf, ff, rt, ft, promo);
	    }
	}
Example #3
0
int ReadFEN(const char *sFEN, BOARD *board)
{   /*TODO: check FEN validity.*/
  int fen_pos = 0;
  SQUARE square = 0x70;
  board->wk_castle = 0;
  board->bk_castle = 0;
  board->wq_castle = 0;
  board->bq_castle = 0;
  board->w_castled = 0;
  board->b_castled = 0;

  for (char on_board = 1; on_board; fen_pos++) {
    char empty = 0;
    switch (sFEN[fen_pos]) {
      case ' ': on_board = 0;
        break;      
      case '/': square -= 0x18;
        break;
      case '1': empty = 1;
        break;
      case '2':  empty = 2;
        break;
      case '3': empty = 3;
        break;
      case '4': empty = 4;
        break;
      case '5': empty = 5;
        break;
      case '6': empty = 6;
        break;
      case '7': empty = 7;
        break;
      case '8': empty = 8;
        break;
      default:
        board->squares[square] = CharToPiece(sFEN[fen_pos]);
        if (board->squares[square] == W_KING) board->wking_pos = square;
        else if (board->squares[square] == B_KING) board->bking_pos = square;
        square++;
        break;
    }
    for (int i = 0; i < empty; i++) board->squares[square+i] = EMPTY;
    square += empty;
  }

  board->white_to_move = (sFEN[fen_pos] == 'w');
  fen_pos+=2;
  
  for (char on_board = 1; on_board; fen_pos++) {    /*Castle rights loop.*/
    switch (sFEN[fen_pos]) {      
      case 'K':  board->wk_castle = 1;
        break;
      case 'k':  board->bk_castle = 1;
        break;
      case 'Q':  board->wq_castle = 1;
        break;
      case 'q':  board->bq_castle = 1;
        break;
      case '-':
        break;
      default: on_board = 0;
        break;
    }
  }
  /*Store En Passant coordinates. TODO: check.*/
  board->en_passant = 0x00;
  for (char on_board = 1; on_board; fen_pos++) {
    switch (sFEN[fen_pos]) {      
      case ' ': on_board = 0;
        break;
      default:
        board->en_passant += CharToCoordinate(sFEN[fen_pos]);
        break;
    }
  }
  /*halfmoves and moves.*/
  int rev = atoi(&sFEN[fen_pos]);
  while (sFEN[++fen_pos] != ' '); 
  board->ply = 2*atoi(&sFEN[fen_pos]) - board->white_to_move - 1;
  board->rev_plies[board->ply] = rev;
  InitZobrist(board);
  board->zobrist_history[board->ply] = board->zobrist_key;
  InitMaterial(board);
  return fen_pos;
}