Replaced all std::cout with kDebug.
[tagua/yd.git] / src / hlvariant / shogi / legalitycheck.h
blob9540eb963745f79721158fcf74890eefdab4cc08
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());
100 case Piece::DRUNKEN_ELEPHANT:
101 return (abs(delta.x) == 1 && abs(delta.y) <= 1)
102 || (delta.x == 0 && delta.y == m_state.direction(piece.color()).y);
103 default:
104 return false;
107 else {
108 switch (piece.type()) {
109 case Piece::SILVER:
110 case Piece::PAWN:
111 case Piece::LANCE:
112 case Piece::KNIGHT:
113 return (delta.x == 0 && abs(delta.y) == 1)
114 || (delta.y == 0 && abs(delta.x) == 1)
115 || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1);
116 case Piece::ROOK:
118 if (abs(delta.x) <= 1 && abs(delta.y) <= 1) return true;
119 PathInfo path = m_state.board().path(move.from(), move.to());
120 return path.parallel() && path.clear();
122 case Piece::BISHOP:
124 if (abs(delta.x) <= 1 && abs(delta.y) <= 1) return true;
125 PathInfo path = m_state.board().path(move.from(), move.to());
126 return path.diagonal() && path.clear();
129 case Piece::DRUNKEN_ELEPHANT: // Crown Prince
130 return abs(delta.x) <= 1 && abs(delta.y) <= 1;
132 default:
133 return false;
138 template <typename GameState>
139 bool LegalityCheck<GameState>::pseudolegal(Move& move) const {
140 if (move.drop() == Piece() &&
141 move.pool() != -1 &&
142 move.index() != -1) {
143 move.setDrop(m_state.pools().pool(move.pool()).get(move.index()));
146 Piece dropped = move.drop();
147 if (dropped != Piece()) {
148 if (m_state.board().get(move.to()) != Piece())
149 return false;
151 if (stuckPiece(dropped, move.to()))
152 return false;
154 if (dropped.type() == Piece::PAWN) {
155 for (int i = 0; i < m_state.board().size().y; i++) {
156 Piece other = m_state.board().get(Point(move.to().x, i));
157 if (other.type() == Piece::PAWN &&
158 other.color() == m_state.turn() &&
159 !other.promoted())
160 return false;
164 return true;
166 else {
167 Piece piece = m_state.board().get(move.from());
168 if (piece != Piece() && getMoveType(piece, move)) {
169 if (m_state.canPromote(piece) &&
170 (m_state.promotionZone(piece.color(), move.to()) ||
171 m_state.promotionZone(piece.color(), move.from())))
172 move.setType(Move::PROMOTION);
173 return true;
175 else {
176 //std::cerr << "CANNOT MOVE: piece type cannot go there";
177 return false;
183 template <typename GameState>
184 bool LegalityCheck<GameState>::canBeCaptured(const GameState& state, const Point& point) const {
185 for (int i = 0; i < m_state.board().size().x; i++) {
186 for (int j = 0; j < m_state.board().size().y; j++) {
187 Point p(i, j);
188 Piece piece = state.board().get(p);
189 LegalityCheck<GameState> check(state);
190 if (piece.color() == state.turn() && check.getMoveType(piece, Move(p, point))) {
191 std::cerr << state.board().get(point).name() << " can be captured";
192 return true;
196 return false;
199 template <typename GameState>
200 bool LegalityCheck<GameState>::legal(Move& move) const {
201 if (!pseudolegal(move))
202 return false;
204 GameState tmp(m_state);
205 tmp.move(move);
207 // find king position
208 Point king_pos = tmp.board().find(Piece(m_state.turn(), Piece::KING));
209 if (!king_pos.valid())
210 return false;
212 // check if the king can be captured
213 if (canBeCaptured(tmp, king_pos))
214 return false;
216 return true;
219 template <typename GameState>
220 bool LegalityCheck<GameState>::stuckPiece(const Piece& piece, const Point& p) const {
221 if (piece.type() == Piece::PAWN || piece.type() == Piece::LANCE) {
222 return p.y == m_state.startingRank(Piece::oppositeColor(piece.color()));
224 else if (piece.type() == Piece::KNIGHT) {
225 int rank = m_state.startingRank(Piece::oppositeColor(piece.color()));
226 return p.y == rank || p.y == rank - m_state.direction(piece.color()).y;
228 else {
229 return false;
233 template <typename GameState>
234 InteractionType LegalityCheck<GameState>::movable(const TurnTest& test, const Point& p) const {
235 Piece piece = m_state.board().get(p);
236 if (piece == Piece() || !test(piece.color()))
237 return NoAction;
239 return piece.color() == m_state.turn() ? Moving : Premoving;
242 template <typename GameState>
243 InteractionType LegalityCheck<GameState>::droppable(const TurnTest& test, int index) const {
244 if (!test(index))
245 return NoAction;
247 typename Piece::Color c = static_cast<typename Piece::Color>(index);
248 return c == m_state.turn() ? Moving : Premoving;
251 } // namespace Shogi
252 } // namespace HLVariant
254 #endif // HLVARIANT__SHOGI__LEGALITYCHECK_H