Factor canBeCaptured() out of Shogi legal() check for east reuse.
[tagua/yd.git] / src / hlvariant / shogi / legalitycheck.h
blob6775897d216286f9f18736788d9d3628c16ad959
1 /*
2 Copyright (c) 2007 Paolo Capriotti <p.capriotti@gmail.com>
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.
9 */
11 #ifndef HLVARIANT__SHOGI__LEGALITYCHECK_H
12 #define HLVARIANT__SHOGI__LEGALITYCHECK_H
14 #include "interactiontype.h"
15 #include "turnpolicy.h"
17 namespace HLVariant {
18 namespace Shogi {
20 template <typename _GameState>
21 class LegalityCheck {
22 public:
23 typedef _GameState GameState;
24 typedef typename GameState::Board Board;
25 typedef typename Board::Piece Piece;
26 typedef typename GameState::Move Move;
27 protected:
28 const GameState& m_state;
30 virtual bool stuckPiece(const Piece& piece, const Point& p) const;
31 public:
32 LegalityCheck(const GameState& state);
33 virtual ~LegalityCheck();
35 virtual bool getMoveType(const Piece& piece, const Move& move) const;
36 bool legal(Move& move) const;
37 bool pseudolegal(Move& move) const;
38 bool canBeCaptured(const GameState& state, const Point& point) const;
40 virtual InteractionType movable(const TurnTest&, const Point& x) const;
41 virtual InteractionType droppable(const TurnTest&, int index) const;
44 // IMPLEMENTATION
46 template <typename GameState>
47 LegalityCheck<GameState>::LegalityCheck(const GameState& state)
48 : m_state(state) { }
50 template <typename GameState>
51 LegalityCheck<GameState>::~LegalityCheck() { }
53 template <typename GameState>
54 bool LegalityCheck<GameState>::getMoveType(const Piece& piece, const Move& move) const {
55 if (!move.valid())
56 return false;
58 if (move.from() == move.to())
59 return false;
61 if (m_state.board().get(move.to()).color() == piece.color())
62 return false;
63 Point delta = move.to() - move.from();
65 if (!piece.promoted()) {
66 switch (piece.type()) {
67 case Piece::KING:
68 return abs(delta.x) <= 1 && abs(delta.y) <= 1;
69 case Piece::GOLD:
70 return (delta.x == 0 && abs(delta.y) == 1)
71 || (delta.y == 0 && abs(delta.x) == 1)
72 || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1);
73 case Piece::SILVER:
74 return (abs(delta.x) == abs(delta.y) && abs(delta.x) == 1)
75 || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1);
76 case Piece::ROOK:
78 PathInfo path = m_state.board().path(move.from(), move.to());
79 return path.parallel() && path.clear();
81 case Piece::BISHOP:
83 PathInfo path = m_state.board().path(move.from(), move.to());
84 return path.diagonal() && path.clear();
86 case Piece::KNIGHT:
88 return abs(delta.x) == 1 && delta.y == m_state.direction(piece.color()).y * 2;
90 case Piece::LANCE:
92 PathInfo path = m_state.board().path(move.from(), move.to());
93 return delta.x == 0 &&
94 path.clear() &&
95 (delta.y * m_state.direction(piece.color()).y > 0);
97 case Piece::PAWN:
98 return delta == m_state.direction(piece.color());
99 default:
100 return false;
103 else {
104 switch (piece.type()) {
105 case Piece::SILVER:
106 case Piece::PAWN:
107 case Piece::LANCE:
108 case Piece::KNIGHT:
109 return (delta.x == 0 && abs(delta.y) == 1)
110 || (delta.y == 0 && abs(delta.x) == 1)
111 || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1);
112 case Piece::ROOK:
114 if (abs(delta.x) <= 1 && abs(delta.y) <= 1) return true;
115 PathInfo path = m_state.board().path(move.from(), move.to());
116 return path.parallel() && path.clear();
118 case Piece::BISHOP:
120 if (abs(delta.x) <= 1 && abs(delta.y) <= 1) return true;
121 PathInfo path = m_state.board().path(move.from(), move.to());
122 return path.diagonal() && path.clear();
124 default:
125 return false;
130 template <typename GameState>
131 bool LegalityCheck<GameState>::pseudolegal(Move& move) const {
132 if (move.drop() == Piece() &&
133 move.pool() != -1 &&
134 move.index() != -1) {
135 move.setDrop(m_state.pools().pool(move.pool()).get(move.index()));
138 Piece dropped = move.drop();
139 if (dropped != Piece()) {
140 if (m_state.board().get(move.to()) != Piece())
141 return false;
143 if (stuckPiece(dropped, move.to()))
144 return false;
146 if (dropped.type() == Piece::PAWN) {
147 for (int i = 0; i < m_state.board().size().y; i++) {
148 Piece other = m_state.board().get(Point(move.to().x, i));
149 if (other.type() == Piece::PAWN &&
150 other.color() == m_state.turn() &&
151 !other.promoted())
152 return false;
156 return true;
158 else {
159 Piece piece = m_state.board().get(move.from());
160 if (piece != Piece() && getMoveType(piece, move)) {
161 if (m_state.canPromote(piece) &&
162 (m_state.promotionZone(piece.color(), move.to()) ||
163 m_state.promotionZone(piece.color(), move.from())))
164 move.setType(Move::PROMOTION);
165 return true;
167 else {
168 //std::cerr << "CANNOT MOVE: piece type cannot go there" << std::endl;
169 return false;
175 template <typename GameState>
176 bool LegalityCheck<GameState>::canBeCaptured(const GameState& state, const Point& point) const {
177 for (int i = 0; i < m_state.board().size().x; i++) {
178 for (int j = 0; j < m_state.board().size().y; j++) {
179 Point p(i, j);
180 Piece piece = state.board().get(p);
181 LegalityCheck<GameState> check(state);
182 if (piece.color() == state.turn() && check.getMoveType(piece, Move(p, point))) {
183 std::cerr << state.board().get(point).name() << " can be captured" << std::endl;
184 return true;
188 return false;
191 template <typename GameState>
192 bool LegalityCheck<GameState>::legal(Move& move) const {
193 if (!pseudolegal(move))
194 return false;
196 GameState tmp(m_state);
197 tmp.move(move);
199 // find king position
200 Point king_pos = tmp.board().find(Piece(m_state.turn(), Piece::KING));
201 if (!king_pos.valid())
202 return false;
204 // check if the king can be captured
205 if (canBeCaptured(tmp, king_pos))
206 return false;
208 return true;
211 template <typename GameState>
212 bool LegalityCheck<GameState>::stuckPiece(const Piece& piece, const Point& p) const {
213 if (piece.type() == Piece::PAWN || piece.type() == Piece::LANCE) {
214 return p.y == m_state.startingRank(Piece::oppositeColor(piece.color()));
216 else if (piece.type() == Piece::KNIGHT) {
217 int rank = m_state.startingRank(Piece::oppositeColor(piece.color()));
218 return p.y == rank || p.y == rank - m_state.direction(piece.color()).y;
220 else {
221 return false;
225 template <typename GameState>
226 InteractionType LegalityCheck<GameState>::movable(const TurnTest& test, const Point& p) const {
227 Piece piece = m_state.board().get(p);
228 if (piece == Piece() || !test(piece.color()))
229 return NoAction;
231 return piece.color() == m_state.turn() ? Moving : Premoving;
234 template <typename GameState>
235 InteractionType LegalityCheck<GameState>::droppable(const TurnTest& test, int index) const {
236 if (!test(index))
237 return NoAction;
239 typename Piece::Color c = static_cast<typename Piece::Color>(index);
240 return c == m_state.turn() ? Moving : Premoving;
243 } // namespace Shogi
244 } // namespace HLVariant
246 #endif // HLVARIANT__SHOGI__LEGALITYCHECK_H