#include "position.h"
#include "psqtab.h"
#include "rkiss.h"
-#include "san.h"
#include "tt.h"
#include "ucioption.h"
operator[]('B') = WB; operator[]('b') = BB;
operator[]('N') = WN; operator[]('n') = BN;
operator[]('P') = WP; operator[]('p') = BP;
- operator[](' ') = PIECE_NONE; operator[]('.') = PIECE_NONE_DARK_SQ;
+ operator[](' ') = PIECE_NONE;
+ operator[]('.') = PIECE_NONE_DARK_SQ;
}
char from_piece(Piece p) const {
- std::map<char, Piece>::const_iterator it;
- for (it = begin(); it != end(); ++it)
- if (it->second == p)
- return it->first;
+ std::map<char, Piece>::const_iterator it;
+ for (it = begin(); it != end(); ++it)
+ if (it->second == p)
+ return it->first;
- assert(false);
- return 0;
+ assert(false);
+ return 0;
}
- } pieceLetters;
+ };
+
+ PieceLetters pieceLetters;
}
nodes = 0;
}
-Position::Position(const string& fen, int th) {
+Position::Position(const string& fen, bool isChess960, int th) {
- from_fen(fen);
+ from_fen(fen, isChess960);
threadID = th;
}
/// string. This function is not very robust - make sure that input FENs are
/// correct (this is assumed to be the responsibility of the GUI).
-void Position::from_fen(const string& fen) {
+void Position::from_fen(const string& fen, bool c960) {
/*
A FEN string defines a particular position using only the ASCII character set.
A FEN string contains six fields. The separator between fields is a space. The fields are:
1) Piece placement (from white's perspective). Each rank is described, starting with rank 8 and ending
- with rank 1; within each rank, the contents of each square are described from file a through file h.
+ with rank 1; within each rank, the contents of each square are described from file A through file H.
Following the Standard Algebraic Notation (SAN), each piece is identified by a single letter taken
from the standard English names. White pieces are designated using upper-case letters ("PNBRQK")
while Black take lowercase ("pnbrqk"). Blank squares are noted using digits 1 through 8 (the number
*/
char token;
+ int hmc, fmn;
std::istringstream ss(fen);
- Rank rank = RANK_8;
- File file = FILE_A;
+ Square sq = SQ_A8;
clear();
// 1. Piece placement field
while (ss.get(token) && token != ' ')
{
- if (isdigit(token))
+ if (pieceLetters.find(token) != pieceLetters.end())
{
- file += File(token - '0'); // Skip the given number of files
- continue;
+ put_piece(pieceLetters[token], sq);
+ sq++;
}
+ else if (isdigit(token))
+ sq += Square(token - '0'); // Skip the given number of files
else if (token == '/')
- {
- file = FILE_A;
- rank--;
- continue;
- }
-
- if (pieceLetters.find(token) == pieceLetters.end())
+ sq -= SQ_A3; // Jump back of 2 rows
+ else
goto incorrect_fen;
-
- put_piece(pieceLetters[token], make_square(file, rank));
- file++;
}
// 2. Active color
// 3. Castling availability
while (ss.get(token) && token != ' ')
- {
- if (token == '-')
- continue;
-
if (!set_castling_rights(token))
goto incorrect_fen;
- }
- // 4. En passant square -- ignore if no capture is possible
+ // 4. En passant square
char col, row;
if ( (ss.get(col) && (col >= 'a' && col <= 'h'))
&& (ss.get(row) && (row == '3' || row == '6')))
{
- Square fenEpSquare = make_square(file_from_char(col), rank_from_char(row));
- Color them = opposite_color(sideToMove);
+ st->epSquare = make_square(file_from_char(col), rank_from_char(row));
- if (attacks_from<PAWN>(fenEpSquare, them) & pieces(PAWN, sideToMove))
- st->epSquare = fenEpSquare;
+ // Ignore if no capture is possible
+ Color them = opposite_color(sideToMove);
+ if (!(attacks_from<PAWN>(st->epSquare, them) & pieces(PAWN, sideToMove)))
+ st->epSquare = SQ_NONE;
}
- // 5-6. Halfmove clock and fullmove number are not parsed
+ // 5. Halfmove clock
+ if (ss >> hmc)
+ st->rule50 = hmc;
+
+ // 6. Fullmove number
+ if (ss >> fmn)
+ startPosPlyCounter = (fmn - 1) * 2 + int(sideToMove == BLACK);
// Various initialisations
castleRightsMask[make_square(initialKFile, RANK_1)] ^= WHITE_OO | WHITE_OOO;
castleRightsMask[make_square(initialQRFile, RANK_1)] ^= WHITE_OOO;
castleRightsMask[make_square(initialQRFile, RANK_8)] ^= BLACK_OOO;
- isChess960 = initialKFile != FILE_E
- || initialQRFile != FILE_A
- || initialKRFile != FILE_H;
-
+ isChess960 = c960;
find_checkers();
st->key = compute_key();
initialKRFile = rookFile;
}
}
- else return false;
+ else
+ return token == '-';
return true;
}
case WB: case BB: return attacks_from<BISHOP>(s);
case WR: case BR: return attacks_from<ROOK>(s);
case WQ: case BQ: return attacks_from<QUEEN>(s);
- default: return StepAttackBB[p][s];
+ default: return NonSlidingAttacksBB[p][s];
}
}
case WB: case BB: return bishop_attacks_bb(s, occ);
case WR: case BR: return rook_attacks_bb(s, occ);
case WQ: case BQ: return bishop_attacks_bb(s, occ) | rook_attacks_bb(s, occ);
- default: return StepAttackBB[p][s];
+ default: return NonSlidingAttacksBB[p][s];
}
}
// A non-king move is legal if and only if it is not pinned or it
// is moving along the ray towards or away from the king.
- return ( !pinned
- || !bit_is_set(pinned, from)
- || (direction_between_squares(from, king_square(us)) == direction_between_squares(move_to(m), king_square(us))));
+ return !pinned
+ || !bit_is_set(pinned, from)
+ || squares_aligned(from, move_to(m), king_square(us));
}
{
// For pawn and king moves we need to verify also direction
if ( (pt != PAWN && pt != KING)
- ||(direction_between_squares(from, ci.ksq) != direction_between_squares(to, ci.ksq)))
+ || !squares_aligned(from, to, ci.ksq))
return true;
}
}
+/// Position::do_setup_move() makes a permanent move on the board.
+/// It should be used when setting up a position on board.
+/// You can't undo the move.
+
+void Position::do_setup_move(Move m) {
+
+ StateInfo newSt;
+
+ do_move(m, newSt);
+
+ // Reset "game ply" in case we made a non-reversible move.
+ // "game ply" is used for repetition detection.
+ if (st->rule50 == 0)
+ st->gamePly = 0;
+
+ // Update the number of plies played from the starting position
+ startPosPlyCounter++;
+
+ // Our StateInfo newSt is about going out of scope so copy
+ // its content inside pos before it disappears.
+ detach();
+}
+
/// Position::do_move() makes a move, and saves all information necessary
/// to a StateInfo object. The move is assumed to be legal.
/// Pseudo-legal moves should be filtered out before this function is called.
assert(is_ok());
assert(move_is_ok(m));
+ assert(&newSt != st);
nodes++;
Key key = st->key;
Value npMaterial[2];
};
- if (&newSt != st)
- memcpy(&newSt, st, sizeof(ReducedStateInfo));
+ memcpy(&newSt, st, sizeof(ReducedStateInfo));
newSt.previous = st;
st = &newSt;
}
-/// Position::reset_game_ply() simply sets gamePly to 0. It is used from the
-/// UCI interface code, whenever a non-reversible move is made in a
-/// 'position fen <fen> moves m1 m2 ...' command. This makes it possible
-/// for the program to handle games of arbitrary length, as long as the GUI
-/// handles draws by the 50 move rule correctly.
-
-void Position::reset_game_ply() {
-
- st->gamePly = 0;
-}
-
-void Position::inc_startpos_ply_counter() {
-
- startPosPlyCounter++;
-}
-
/// Position::put_piece() puts a piece on the given square of the board,
/// updating the board array, pieces list, bitboards, and piece counts.
return true;
// Draw by the 50 moves rule?
- if (st->rule50 > 99 && (st->rule50 > 100 || !is_mate()))
+ if (st->rule50 > 99 && !is_mate())
return true;
// Draw by repetition?
bool Position::is_mate() const {
MoveStack moves[MOVES_MAX];
- return is_check() && generate_moves(*this, moves) == moves;
+ return is_check() && generate<MV_LEGAL>(*this, moves) == moves;
}
do_null_move(st1);
// Then generate pseudo-legal moves that could give check
- last = generate_non_capture_checks(*this, mlist);
- last = generate_captures(*this, last);
+ last = generate<MV_NON_CAPTURE_CHECK>(*this, mlist);
+ last = generate<MV_CAPTURE>(*this, last);
// Loop through the moves, and see if one of them gives mate
Bitboard pinned = pinned_pieces(sideToMove);