push 3d4e9e0832507dc01d09c79a6b95c4d44c86028c
[tagua/yd.git] / src / hlvariant / shogi / legalitycheck.h
blobc42e6e64f6d3180503e95fe7501d6826984dc939
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 <KDebug>
16 #include "turnpolicy.h"
18 namespace HLVariant {
19 namespace Shogi {
21 template <typename _GameState>
22 class LegalityCheck {
23 public:
24 typedef _GameState GameState;
25 typedef typename GameState::Board Board;
26 typedef typename Board::Piece Piece;
27 typedef typename GameState::Move Move;
28 protected:
29 const GameState& m_state;
31 virtual bool stuckPiece(const Piece& piece, const Point& p) const;
32 public:
33 LegalityCheck(const GameState& state);
34 virtual ~LegalityCheck();
36 virtual bool getMoveType(const Piece& piece, const Move& move) const;
37 bool legal(Move& move) const;
38 bool pseudolegal(Move& move) const;
39 bool canBeCaptured(const GameState& state, const Point& point) const;
41 virtual InteractionType movable(const TurnTest&, const Point& x) const;
42 virtual InteractionType droppable(const TurnTest&, int index) const;
45 // IMPLEMENTATION
47 template <typename GameState>
48 LegalityCheck<GameState>::LegalityCheck(const GameState& state)
49 : m_state(state) { }
51 template <typename GameState>
52 LegalityCheck<GameState>::~LegalityCheck() { }
54 template <typename GameState>
55 bool LegalityCheck<GameState>::getMoveType(const Piece& piece, const Move& move) const {
56 if (!move.valid())
57 return false;
59 if (move.from() == move.to())
60 return false;
62 if (m_state.board().get(move.to()).color() == piece.color())
63 return false;
64 Point delta = move.to() - move.from();
66 if (!piece.promoted()) {
67 switch (piece.type()) {
68 case Piece::KING:
69 return abs(delta.x) <= 1 && abs(delta.y) <= 1;
70 case Piece::GOLD:
71 return (delta.x == 0 && abs(delta.y) == 1)
72 || (delta.y == 0 && abs(delta.x) == 1)
73 || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1);
74 case Piece::SILVER:
75 return (abs(delta.x) == abs(delta.y) && abs(delta.x) == 1)
76 || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1);
77 case Piece::ROOK:
79 PathInfo path = m_state.board().path(move.from(), move.to());
80 return path.parallel() && path.clear();
82 case Piece::BISHOP:
84 PathInfo path = m_state.board().path(move.from(), move.to());
85 return path.diagonal() && path.clear();
87 case Piece::KNIGHT:
89 return abs(delta.x) == 1 && delta.y == m_state.direction(piece.color()).y * 2;
91 case Piece::LANCE:
93 PathInfo path = m_state.board().path(move.from(), move.to());
94 return delta.x == 0 &&
95 path.clear() &&
96 (delta.y * m_state.direction(piece.color()).y > 0);
98 case Piece::PAWN:
99 return delta == m_state.direction(piece.color());
101 case Piece::DRUNKEN_ELEPHANT:
102 return (abs(delta.x) == 1 && abs(delta.y) <= 1)
103 || (delta.x == 0 && delta.y == m_state.direction(piece.color()).y);
104 default:
105 return false;
108 else {
109 switch (piece.type()) {
110 case Piece::SILVER:
111 case Piece::PAWN:
112 case Piece::LANCE:
113 case Piece::KNIGHT:
114 return (delta.x == 0 && abs(delta.y) == 1)
115 || (delta.y == 0 && abs(delta.x) == 1)
116 || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1);
117 case Piece::ROOK:
119 if (abs(delta.x) <= 1 && abs(delta.y) <= 1) return true;
120 PathInfo path = m_state.board().path(move.from(), move.to());
121 return path.parallel() && path.clear();
123 case Piece::BISHOP:
125 if (abs(delta.x) <= 1 && abs(delta.y) <= 1) return true;
126 PathInfo path = m_state.board().path(move.from(), move.to());
127 return path.diagonal() && path.clear();
130 case Piece::DRUNKEN_ELEPHANT: // Crown Prince
131 return abs(delta.x) <= 1 && abs(delta.y) <= 1;
133 default:
134 return false;
139 template <typename GameState>
140 bool LegalityCheck<GameState>::pseudolegal(Move& move) const {
141 if (move.drop() == Piece() &&
142 move.pool() != -1 &&
143 move.index() != -1) {
144 move.setDrop(m_state.pools().pool(move.pool()).get(move.index()));
147 Piece dropped = move.drop();
148 if (dropped != Piece()) {
149 if (m_state.board().get(move.to()) != Piece())
150 return false;
152 if (stuckPiece(dropped, move.to()))
153 return false;
155 if (dropped.type() == Piece::PAWN) {
156 for (int i = 0; i < m_state.board().size().y; i++) {
157 Piece other = m_state.board().get(Point(move.to().x, i));
158 if (other.type() == Piece::PAWN &&
159 other.color() == m_state.turn() &&
160 !other.promoted())
161 return false;
165 return true;
167 else {
168 Piece piece = m_state.board().get(move.from());
169 if (piece != Piece() && getMoveType(piece, move)) {
170 if (m_state.canPromote(piece) &&
171 (m_state.promotionZone(piece.color(), move.to()) ||
172 m_state.promotionZone(piece.color(), move.from())))
173 move.setType(Move::PROMOTION);
174 return true;
176 else {
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 kDebug() << 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