2 Copyright (c) 2007 Paolo Capriotti <p.capriotti@sns.it>
3 (c) 2007 Maurizio Monge <maurizio.monge@kdemail.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
11 #ifndef HLVARIANT__CHESS__LEGALITYCHECK_H
12 #define HLVARIANT__CHESS__LEGALITYCHECK_H
14 #include "gamestate.h"
15 #include "interactiontype.h"
16 #include "turnpolicy.h"
21 template <typename _GameState
>
24 typedef _GameState GameState
;
25 typedef typename
GameState::Board Board
;
26 typedef typename
GameState::Move Move
;
27 typedef typename
GameState::Piece Piece
;
29 const GameState
& m_state
;
31 LegalityCheck(const GameState
& state
);
32 virtual ~LegalityCheck();
34 virtual typename
Move::Type
getMoveType(
37 const Piece
& target
= Piece()) const;
38 virtual bool pseudolegal(Move
& move
) const;
39 virtual bool legal(Move
& move
) const;
41 typename
Piece::Color color
,
43 const Piece
& target
= Piece()) const;
44 virtual bool checkPromotion(typename
Piece::Type type
) const;
46 virtual typename
Piece::Color
mover(const Move
& move
) const;
47 virtual InteractionType
movable(const TurnTest
&, const Point
& x
) const;
48 virtual InteractionType
droppable(const TurnTest
&, int index
) const;
53 template <typename GameState
>
54 LegalityCheck
<GameState
>::~LegalityCheck() { }
56 template <typename GameState
>
57 LegalityCheck
<GameState
>::LegalityCheck(const GameState
& state
)
60 template <typename GameState
>
61 bool LegalityCheck
<GameState
>::legal(Move
& move
) const {
62 if (pseudolegal(move
)) {
63 typename
Piece::Color turn
= mover(move
);
65 GameState
tmp(m_state
);
68 Point kingPos
= tmp
.board().find(Piece(turn
, Piece::KING
));
70 if (kingPos
== Point::invalid())
73 LegalityCheck
<GameState
> tmpLegality(tmp
);
74 if (tmpLegality
.attacks(Piece::oppositeColor(turn
), kingPos
))
84 template <typename GameState
>
85 bool LegalityCheck
<GameState
>::pseudolegal(Move
& move
) const {
86 if (!move
.valid()) return false;
88 if (!m_state
.board().valid(move
.from())) return false;
89 if (!m_state
.board().valid(move
.to())) return false;
91 Piece piece
= m_state
.board().get(move
.from());
92 if (piece
== Piece()) return false;
94 typename
Piece::Color thisTurn
= piece
.color();
95 typename
Piece::Color otherTurn
= Piece::oppositeColor(thisTurn
);
97 if (piece
!= Piece() && m_state
.turn() == thisTurn
) {
98 typename
Move::Type move_type
= getMoveType(piece
, move
);
99 move
.setType(move_type
);
102 if (!checkPromotion(static_cast<typename
Piece::Type
>(move
.promoteTo())))
104 if (move
.kingSideCastling()) {
105 if (attacks(otherTurn
, move
.from()) ||
106 attacks(otherTurn
, move
.from() + Point(1, 0), piece
))
109 if (move
.queenSideCastling()) {
110 if (attacks(otherTurn
, move
.from()) ||
111 attacks(otherTurn
, move
.from() + Point(-1, 0), piece
))
122 template <typename GameState
>
123 typename
GameState::Move::Type
124 LegalityCheck
<GameState
>::
125 getMoveType(const Piece
& piece
, const Move
& move
, const Piece
& _target
) const {
126 Piece target
= _target
== Piece() ? m_state
.board().get(move
.to()) : _target
;
128 switch (piece
.type())
132 if (move
.from() == move
.to())
133 return Move::INVALID
;
134 PathInfo path
= m_state
.board().path(move
.from(), move
.to());
135 if (path
.parallel() && path
.clear() && target
.color() != piece
.color())
138 return Move::INVALID
;
143 if (move
.from() == move
.to())
144 return Move::INVALID
;
145 PathInfo path
= m_state
.board().path(move
.from(), move
.to());
146 if (path
.diagonal() && path
.clear() && target
.color() != piece
.color())
149 return Move::INVALID
;
153 if (target
.color() == piece
.color())
154 return Move::INVALID
;
157 Point delta
= move
.from() - move
.to();
158 if (abs(delta
.x
) == 1 && abs(delta
.y
) == 2)
160 if (abs(delta
.y
) == 1 && abs(delta
.x
) == 2)
162 return Move::INVALID
;
167 if (move
.from() == move
.to())
168 return Move::INVALID
;
169 PathInfo path
= m_state
.board().path(move
.from(), move
.to());
170 if (path
.valid() && path
.clear() && target
.color() != piece
.color())
173 return Move::INVALID
;
178 if (move
.from() == move
.to())
179 return Move::INVALID
;
180 Point delta
= move
.to() - move
.from();
181 if (abs(delta
.x
) <= 1 && abs(delta
.y
) <= 1 && target
.color() != piece
.color()) {
184 else if (move
.from() == m_state
.kingStartingPosition(piece
.color())) {
185 if (delta
== Point(2,0)) {
186 if (m_state
.board().get(move
.from() + Point(1,0)) == Piece() &&
187 m_state
.board().get(move
.to()) == Piece() &&
188 m_state
.kingCastling(piece
.color()))
189 return Move::KING_SIDE_CASTLING
;
191 else if (delta
== Point(-2,0)) {
192 if (m_state
.board().get(move
.from() - Point(1, 0)) == Piece() &&
193 m_state
.board().get(move
.to() + Point(1, 0)) == Piece() &&
194 m_state
.board().get(move
.to()) == Piece() &&
195 m_state
.queenCastling(piece
.color()))
196 return Move::QUEEN_SIDE_CASTLING
;
199 return Move::INVALID
;
204 Point delta
= move
.to() - move
.from();
205 bool enPassant
= m_state
.enPassant() == move
.to();
208 if (target
== Piece() && !enPassant
) {
209 if (delta
== m_state
.direction(piece
.color())) {
210 if (move
.to().y
== m_state
.promotionRank(piece
.color()))
211 return Move::PROMOTION
;
216 if (move
.from().y
== m_state
.startingRank(piece
.color())
217 + m_state
.direction(piece
.color()).y
&&
218 delta
== m_state
.direction(piece
.color()) * 2 &&
219 m_state
.board().get(move
.from() + m_state
.direction(piece
.color())) == Piece())
220 return Move::EN_PASSANT_TRIGGER
;
222 return Move::INVALID
;
226 else if (enPassant
|| target
.color() != piece
.color()) {
227 if (delta
.y
== m_state
.direction(piece
.color()).y
&&
230 return Move::EN_PASSANT_CAPTURE
;
231 else if (move
.to().y
== m_state
.promotionRank(piece
.color()))
232 return Move::PROMOTION
;
238 return Move::INVALID
;
242 return Move::INVALID
;
246 template <typename GameState
>
247 bool LegalityCheck
<GameState
>::attacks(typename
Piece::Color color
, const Point
& to
, const Piece
& target
) const {
248 for (int i
= 0; i
< m_state
.board().size().x
; i
++) {
249 for (int j
= 0; j
< m_state
.board().size().y
; j
++) {
251 Piece piece
= m_state
.board().get(p
);
253 if (piece
!= Piece() && piece
.color() == color
254 && getMoveType(piece
, move
, target
) != Move::INVALID
)
261 template <typename GameState
>
262 bool LegalityCheck
<GameState
>::checkPromotion(typename
Piece::Type type
) const {
264 type
== Piece::QUEEN
||
265 type
== Piece::ROOK
||
266 type
== Piece::BISHOP
||
267 type
== Piece::KNIGHT
;
270 template <typename GameState
>
271 typename LegalityCheck
<GameState
>::Piece::Color
272 LegalityCheck
<GameState
>::mover(const Move
& move
) const {
273 return m_state
.board().get(move
.from()).color();
276 template <typename GameState
>
277 InteractionType LegalityCheck
<GameState
>::movable(const TurnTest
& test
, const Point
& p
) const {
278 Piece piece
= m_state
.board().get(p
);
279 if (piece
== Piece() || !test(piece
.color()))
282 return piece
.color() == m_state
.turn() ? Moving
: Premoving
;
285 template <typename GameState
>
286 InteractionType LegalityCheck
<GameState
>::droppable(const TurnTest
& test
, int index
) const {
290 typename
Piece::Color c
= static_cast<typename
Piece::Color
>(index
);
291 return c
== m_state
.turn() ? Moving
: Premoving
;
295 } // namespace HLVariant
297 #endif // HLVARIANT__CHESS__LEGALITYCHECK_H