Scid  4.7.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
movegen.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011-2017 Fulvio Benini
3  *
4  * This file is part of Scid (Shane's Chess Information Database).
5  *
6  * Scid is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation.
9  *
10  * Scid is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Scid. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /** @file
20  * Implements functions for the validation of chess moves.
21  */
22 
23 #include <utility>
24 
25 // These functions use the following move classification:
26 // - a VALID move is a move that respects the basic rules for moving the pieces,
27 // for example a bishop should move diagonally. Validating this type of moves
28 // do not require any info about the current position.
29 // - an ATTACK move is a valid move that can capture an enemy piece at the
30 // destination square. It takes into account the special rule for pawns that
31 // can capture only diagonally and the board position for obstacles, for
32 // example a valid diagonal bishop move is an attack move only if the
33 // in-between squares are empty. To validate this type of moves it is
34 // necessary to know the location of empty squares in the current position.
35 // - a PSEUDO-LEGAL move is an attack move, or a non-capture pawn move, or a
36 // castle move.
37 // - a LEGAL move is a pseudo-legal move where the destination square is not
38 // occupied by a friendly piece and that do not leave the king in check.
39 // To validate this type of moves it is necessary to know the type and
40 // position of every piece.
41 
42 namespace movegen {
43 
44 const int NSQUARES = 8;
45 
46 inline bool valid_king(squareT sqFrom, squareT sqTo) {
47  unsigned distRank = 1 + (sqTo / NSQUARES) - (sqFrom / NSQUARES);
48  unsigned distFyle = 1 + (sqTo % NSQUARES) - (sqFrom % NSQUARES);
49  return distRank <= 2 && distFyle <= 2;
50 }
51 
52 inline bool valid_knight(squareT sqFrom, squareT sqTo) {
53  int distRank = (sqTo / NSQUARES) - (sqFrom / NSQUARES);
54  int distFyle = (sqTo % NSQUARES) - (sqFrom % NSQUARES);
55  int distProduct = distRank * distFyle;
56  return (distProduct == 2 || distProduct == -2);
57 }
58 
59 inline int valid_slider(squareT sqFrom, squareT sqTo, pieceT pieceType) {
60  ASSERT(pieceType == QUEEN || pieceType == ROOK || pieceType == BISHOP);
61 
62  int distRank = (sqTo / NSQUARES) - (sqFrom / NSQUARES);
63  int distFyle = (sqTo % NSQUARES) - (sqFrom % NSQUARES);
64 
65  // Make sure the direction is valid:
66  int sqStep;
67  bool isDiagonal = false;
68  if (distRank == 0) {
69  sqStep = 1; // horizontal
70  } else if (distFyle == 0) {
71  sqStep = NSQUARES; // vertical
72  } else if (distFyle == distRank) {
73  sqStep = NSQUARES + 1;
74  isDiagonal = true;
75  } else if (distFyle == -distRank) {
76  sqStep = NSQUARES - 1;
77  isDiagonal = true;
78  } else {
79  return 0;
80  }
81  if (pieceType == ROOK && isDiagonal)
82  return 0;
83  if (pieceType == BISHOP && !isDiagonal)
84  return 0;
85 
86  return sqStep;
87 }
88 
89 inline bool attack_pawn(squareT sqFrom, squareT sqTo, colorT pieceCol) {
90  int distRank = (sqTo / NSQUARES) - (sqFrom / NSQUARES);
91  int distFyle = (sqTo % NSQUARES) - (sqFrom % NSQUARES);
92  if (pieceCol == WHITE && distRank != 1)
93  return false;
94  if (pieceCol == BLACK && distRank != -1)
95  return false;
96 
97  return (distFyle == 1 || distFyle == -1);
98 }
99 
100 template <typename TBoard>
101 bool attack_slider(squareT sqFrom, squareT sqTo, pieceT pieceType,
102  const TBoard* board, const TBoard EMPTY_SQUARE) {
103  int sqStep = valid_slider(sqFrom, sqTo, pieceType);
104  if (sqStep == 0)
105  return false;
106 
107  // Make sure all the in-between squares are empty:
108  if (sqFrom > sqTo)
109  sqStep = -sqStep;
110 
111  for (int sq = sqFrom + sqStep; sq != sqTo; sq += sqStep) {
112  if (board[sq] != EMPTY_SQUARE)
113  return false;
114  }
115 
116  return true;
117 }
118 
119 /**
120  * Validate an ATTACK move, that is if a piece placed at @e sqFrom can capture
121  * an enemy piece at @e sqTo.
122  * @param sqFrom: square of the piece.
123  * @param sqTo: square of the piece to be captured.
124  * @param pieceCol: color of the moving piece.
125  * @param pieceType: type of the moving piece.
126  * @param board: pointer to the board position; it's is irrelevant if the
127  * position is the one before or after the move was made.
128  * @param EMPTY_SQUARE: value of an empty square in the board position.
129  * @returns true if the move is a valid ATTACK move.
130  */
131 template <typename TBoard>
132 bool attack(squareT sqFrom, squareT sqTo, pieceT pieceCol, pieceT pieceType,
133  const TBoard* board, const TBoard EMPTY_SQUARE) {
134  switch (pieceType) {
135  case KING:
136  return valid_king(sqFrom, sqTo);
137  case KNIGHT:
138  return valid_knight(sqFrom, sqTo);
139  case PAWN:
140  return attack_pawn(sqFrom, sqTo, pieceCol);
141  default:
142  break;
143  }
144  return attack_slider(sqFrom, sqTo, pieceType, board, EMPTY_SQUARE);
145 }
146 
147 template <typename TBoard>
148 bool pseudo(squareT sqFrom, squareT sqTo, colorT /*pieceCol*/, pieceT pieceType,
149  const TBoard* board, const TBoard EMPTY_SQUARE) {
150  // TODO: pawn and king moves
151  ASSERT(pieceType != PAWN && pieceType != KING);
152 
153  switch (pieceType) {
154  case KNIGHT:
155  return valid_knight(sqFrom, sqTo);
156  default:
157  break;
158  }
159  return attack_slider(sqFrom, sqTo, pieceType, board, EMPTY_SQUARE);
160 }
161 
162 /**
163  * Given a pseudo-legal move, this functions return the type and the location of
164  * the piece that can possibly pin the moving piece, making the move not legal.
165  * @param sqFrom: start square of the pseudo-legal move.
166  * @param sqTo: destination square of the pseudo-legal move.
167  * @param sqRay: the projected ray starts from @e sqRay and goes through
168  * @e sqFrom; it is usually the square where the king is.
169  * @param board: pointer to the board position where the pseudo-legal
170  * move has to be made.
171  * @param EMPTY_SQUARE: value of an empty square in the board position.
172  * @returns a std::pair with the type (INVALID_PIECE, BISHOP, ROOK) and the
173  * square of the candidate pinning piece. If the type is INVALID_PIECE there is
174  * no pin and the move is legal, otherwise it's necessary to test the board
175  * position and if the returned square is occupied by an enemy QUEEN, or an
176  * enemy piece matching the returned type, the move is not legal.
177  */
178 template <typename TBoard>
179 inline std::pair<pieceT, squareT> opens_ray(squareT sqFrom, squareT sqTo,
180  squareT sqRay, const TBoard* board,
181  const TBoard EMPTY_SQUARE) {
182  ASSERT(sqRay != sqFrom);
183 
184  int fyleFrom = sqFrom % NSQUARES;
185  int distFyle = (sqRay % NSQUARES) - fyleFrom;
186  int distRank = (sqRay / NSQUARES) - (sqFrom / NSQUARES);
187 
188  // Make sure the direction is valid:
189  int fyleEdge;
190  int sqStep;
191  pieceT pt;
192  if (distFyle == 0) {
193  sqStep = NSQUARES; // vertical
194  fyleEdge = -1;
195  pt = ROOK;
196  } else {
197  if (fyleFrom == 0 || fyleFrom == (NSQUARES - 1))
198  return std::pair<pieceT, squareT>(INVALID_PIECE, 0);
199 
200  if (distRank == 0) {
201  sqStep = 1; // horizontal
202  fyleEdge = 0;
203  pt = ROOK;
204  } else if (distFyle == distRank) {
205  sqStep = NSQUARES + 1;
206  fyleEdge = 0;
207  pt = BISHOP;
208  } else if (distFyle == -distRank) {
209  sqStep = NSQUARES - 1;
210  fyleEdge = NSQUARES - 1;
211  pt = BISHOP;
212  } else {
213  return std::pair<pieceT, squareT>(INVALID_PIECE, 0);
214  }
215  }
216  if (sqFrom > sqRay) {
217  sqStep = -sqStep;
218  fyleEdge = NSQUARES - 1 - fyleEdge;
219  }
220 
221  for (int sq = sqFrom + sqStep; sq != sqRay; sq += sqStep) {
222  if (sq == sqTo || board[sq] != EMPTY_SQUARE)
223  return std::pair<pieceT, squareT>(INVALID_PIECE, 0);
224  }
225 
226  for (int sq = sqFrom - sqStep; sq < NSQUARES * NSQUARES; sq -= sqStep) {
227  if (sq < 0 || sq == sqTo)
228  break;
229 
230  if (board[sq] != EMPTY_SQUARE)
231  return std::make_pair(pt, static_cast<squareT>(sq));
232 
233  if ((sq % NSQUARES) == fyleEdge)
234  break;
235  }
236  return std::pair<pieceT, squareT>(INVALID_PIECE, 0);
237 }
238 
239 
240 } // end of namespace movegen
const colorT WHITE
Definition: common.h:207
sqsqname
Definition: board.tcl:292
bool attack(squareT sqFrom, squareT sqTo, pieceT pieceCol, pieceT pieceType, const TBoard *board, const TBoard EMPTY_SQUARE)
Validate an ATTACK move, that is if a piece placed at sqFrom can capture an enemy piece at sqTo...
Definition: movegen.h:132
#define ASSERT(f)
Definition: common.h:59
const int NSQUARES
Definition: movegen.h:44
bool pseudo(squareT sqFrom, squareT sqTo, colorT, pieceT pieceType, const TBoard *board, const TBoard EMPTY_SQUARE)
Definition: movegen.h:148
const pieceT KING
Definition: common.h:226
const colorT BLACK
Definition: common.h:208
const pieceT BISHOP
Definition: common.h:229
std::pair< pieceT, squareT > opens_ray(squareT sqFrom, squareT sqTo, squareT sqRay, const TBoard *board, const TBoard EMPTY_SQUARE)
Given a pseudo-legal move, this functions return the type and the location of the piece that can poss...
Definition: movegen.h:179
const pieceT KNIGHT
Definition: common.h:230
bool valid_king(squareT sqFrom, squareT sqTo)
Definition: movegen.h:46
bool attack_pawn(squareT sqFrom, squareT sqTo, colorT pieceCol)
Definition: movegen.h:89
bool valid_knight(squareT sqFrom, squareT sqTo)
Definition: movegen.h:52
const pieceT INVALID_PIECE
Definition: common.h:225
const pieceT QUEEN
Definition: common.h:227
Definition: board.tcl:276
const pieceT ROOK
Definition: common.h:228
bool attack_slider(squareT sqFrom, squareT sqTo, pieceT pieceType, const TBoard *board, const TBoard EMPTY_SQUARE)
Definition: movegen.h:101
const pieceT PAWN
Definition: common.h:231
byte colorT
Definition: common.h:104
int valid_slider(squareT sqFrom, squareT sqTo, pieceT pieceType)
Definition: movegen.h:59
byte squareT
Definition: common.h:105
byte pieceT
Definition: common.h:103