1 #ifndef HLVARIANT__CHESS__LEGALITYCHECK_H
2 #define HLVARIANT__CHESS__LEGALITYCHECK_H
5 #include "interactiontype.h"
6 #include "turnpolicy.h"
11 template <typename _GameState
>
14 typedef _GameState GameState
;
15 typedef typename
GameState::Board Board
;
16 typedef typename
GameState::Move Move
;
17 typedef typename
GameState::Piece Piece
;
19 const GameState
& m_state
;
21 LegalityCheck(const GameState
& state
);
22 virtual ~LegalityCheck();
24 virtual typename
Move::Type
getMoveType(
27 const Piece
& target
= Piece()) const;
28 virtual bool pseudolegal(Move
& move
) const;
29 virtual bool legal(Move
& move
) const;
31 typename
Piece::Color color
,
33 const Piece
& target
= Piece()) const;
34 virtual bool checkPromotion(typename
Piece::Type type
) const;
36 virtual InteractionType
movable(const TurnTest
&, const Point
& x
) const;
37 virtual InteractionType
droppable(const TurnTest
&, int index
) const;
42 template <typename GameState
>
43 LegalityCheck
<GameState
>::~LegalityCheck() { }
45 template <typename GameState
>
46 LegalityCheck
<GameState
>::LegalityCheck(const GameState
& state
)
49 template <typename GameState
>
50 bool LegalityCheck
<GameState
>::legal(Move
& move
) const {
51 if (pseudolegal(move
)) {
52 Piece piece
= m_state
.board().get(move
.from());
53 typename
Piece::Color turn
= piece
.color();
55 GameState
tmp(m_state
);
58 Point kingPos
= tmp
.board().find(Piece(turn
, Piece::KING
));
60 if (kingPos
== Point::invalid())
63 LegalityCheck
<GameState
> tmpLegality(tmp
);
64 if (tmpLegality
.attacks(Piece::oppositeColor(turn
), kingPos
))
74 template <typename GameState
>
75 bool LegalityCheck
<GameState
>::pseudolegal(Move
& move
) const {
76 if (!move
.valid()) return false;
78 if (!m_state
.board().valid(move
.from())) return false;
79 if (!m_state
.board().valid(move
.to())) return false;
81 Piece piece
= m_state
.board().get(move
.from());
82 if (piece
== Piece()) return false;
84 typename
Piece::Color thisTurn
= piece
.color();
85 typename
Piece::Color otherTurn
= Piece::oppositeColor(thisTurn
);
87 if (piece
!= Piece() && m_state
.turn() == thisTurn
) {
88 typename
Move::Type move_type
= getMoveType(piece
, move
);
89 move
.setType(move_type
);
92 if (!checkPromotion(static_cast<typename
Piece::Type
>(move
.promoteTo())))
94 if (move
.kingSideCastling()) {
95 if (attacks(otherTurn
, move
.from()) ||
96 attacks(otherTurn
, move
.from() + Point(1, 0), piece
))
99 if (move
.queenSideCastling()) {
100 if (attacks(otherTurn
, move
.from()) ||
101 attacks(otherTurn
, move
.from() + Point(-1, 0), piece
))
112 template <typename GameState
>
113 typename
GameState::Move::Type
114 LegalityCheck
<GameState
>::
115 getMoveType(const Piece
& piece
, const Move
& move
, const Piece
& _target
) const {
116 Piece target
= _target
== Piece() ? m_state
.board().get(move
.to()) : _target
;
118 switch (piece
.type())
122 if (move
.from() == move
.to())
123 return Move::INVALID
;
124 PathInfo path
= m_state
.board().path(move
.from(), move
.to());
125 if (path
.parallel() && path
.clear() && target
.color() != piece
.color())
128 return Move::INVALID
;
133 if (move
.from() == move
.to())
134 return Move::INVALID
;
135 PathInfo path
= m_state
.board().path(move
.from(), move
.to());
136 if (path
.diagonal() && path
.clear() && target
.color() != piece
.color())
139 return Move::INVALID
;
143 if (target
.color() == piece
.color())
144 return Move::INVALID
;
147 Point delta
= move
.from() - move
.to();
148 if (abs(delta
.x
) == 1 && abs(delta
.y
) == 2)
150 if (abs(delta
.y
) == 1 && abs(delta
.x
) == 2)
152 return Move::INVALID
;
157 if (move
.from() == move
.to())
158 return Move::INVALID
;
159 PathInfo path
= m_state
.board().path(move
.from(), move
.to());
160 if (path
.valid() && path
.clear() && target
.color() != piece
.color())
163 return Move::INVALID
;
168 if (move
.from() == move
.to())
169 return Move::INVALID
;
170 Point delta
= move
.to() - move
.from();
171 if (abs(delta
.x
) <= 1 && abs(delta
.y
) <= 1 && target
.color() != piece
.color()) {
174 else if (move
.from() == m_state
.kingStartingPosition(piece
.color())) {
175 if (delta
== Point(2,0)) {
176 if (m_state
.board().get(move
.from() + Point(1,0)) == Piece() &&
177 m_state
.board().get(move
.to()) == Piece() &&
178 m_state
.kingCastling(piece
.color()))
179 return Move::KING_SIDE_CASTLING
;
181 else if (delta
== Point(-2,0)) {
182 if (m_state
.board().get(move
.from() - Point(1, 0)) == Piece() &&
183 m_state
.board().get(move
.to() + Point(1, 0)) == Piece() &&
184 m_state
.board().get(move
.to()) == Piece() &&
185 m_state
.queenCastling(piece
.color()))
186 return Move::QUEEN_SIDE_CASTLING
;
189 return Move::INVALID
;
194 Point delta
= move
.to() - move
.from();
195 bool enPassant
= m_state
.enPassant() == move
.to();
198 if (target
== Piece() && !enPassant
) {
199 if (delta
== m_state
.direction(piece
.color())) {
200 if (move
.to().y
== m_state
.promotionRank(piece
.color()))
201 return Move::PROMOTION
;
206 if (move
.from().y
== m_state
.startingRank(piece
.color())
207 + m_state
.direction(piece
.color()).y
&&
208 delta
== m_state
.direction(piece
.color()) * 2 &&
209 m_state
.board().get(move
.from() + m_state
.direction(piece
.color())) == Piece())
210 return Move::EN_PASSANT_TRIGGER
;
212 return Move::INVALID
;
216 else if (enPassant
|| target
.color() != piece
.color()) {
217 if (delta
.y
== m_state
.direction(piece
.color()).y
&&
220 return Move::EN_PASSANT_CAPTURE
;
221 else if (move
.to().y
== m_state
.promotionRank(piece
.color()))
222 return Move::PROMOTION
;
228 return Move::INVALID
;
232 return Move::INVALID
;
236 template <typename GameState
>
237 bool LegalityCheck
<GameState
>::attacks(typename
Piece::Color color
, const Point
& to
, const Piece
& target
) const {
238 for (int i
= 0; i
< m_state
.board().size().x
; i
++) {
239 for (int j
= 0; j
< m_state
.board().size().y
; j
++) {
241 Piece piece
= m_state
.board().get(p
);
243 if (piece
!= Piece() && piece
.color() == color
244 && getMoveType(piece
, move
, target
) != Move::INVALID
)
251 template <typename GameState
>
252 bool LegalityCheck
<GameState
>::checkPromotion(typename
Piece::Type type
) const {
254 type
== Piece::QUEEN
||
255 type
== Piece::ROOK
||
256 type
== Piece::BISHOP
||
257 type
== Piece::KNIGHT
;
260 template <typename GameState
>
261 InteractionType LegalityCheck
<GameState
>::movable(const TurnTest
& test
, const Point
& p
) const {
262 Piece piece
= m_state
.board().get(p
);
263 if (piece
== Piece() || !test(piece
.color()))
266 return piece
.color() == m_state
.turn() ? Moving
: Premoving
;
269 template <typename GameState
>
270 InteractionType LegalityCheck
<GameState
>::droppable(const TurnTest
& test
, int index
) const {
274 typename
Piece::Color c
= static_cast<typename
Piece::Color
>(index
);
275 return c
== m_state
.turn() ? Moving
: Premoving
;
279 } // namespace HLVariant
281 #endif // HLVARIANT__CHESS__LEGALITYCHECK_H