Changed my email in the copyright statements.
[tagua/yd.git] / src / hlvariant / shogi / legalitycheck.h
blob4fa249a1ff9677e8957793664d91579eee88a7ee
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;
39 virtual InteractionType movable(const TurnTest&, const Point& x) const;
40 virtual InteractionType droppable(const TurnTest&, int index) const;
43 // IMPLEMENTATION
45 template <typename GameState>
46 LegalityCheck<GameState>::LegalityCheck(const GameState& state)
47 : m_state(state) { }
49 template <typename GameState>
50 LegalityCheck<GameState>::~LegalityCheck() { }
52 template <typename GameState>
53 bool LegalityCheck<GameState>::getMoveType(const Piece& piece, const Move& move) const {
54 if (!move.valid())
55 return false;
57 if (move.from() == move.to())
58 return false;
60 if (m_state.board().get(move.to()).color() == piece.color())
61 return false;
62 Point delta = move.to() - move.from();
64 if (!piece.promoted()) {
65 switch (piece.type()) {
66 case Piece::KING:
67 return abs(delta.x) <= 1 && abs(delta.y) <= 1;
68 case Piece::GOLD:
69 return (delta.x == 0 && abs(delta.y) == 1)
70 || (delta.y == 0 && abs(delta.x) == 1)
71 || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1);
72 case Piece::SILVER:
73 return (abs(delta.x) == abs(delta.y) && abs(delta.x) == 1)
74 || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1);
75 case Piece::ROOK:
77 PathInfo path = m_state.board().path(move.from(), move.to());
78 return path.parallel() && path.clear();
80 case Piece::BISHOP:
82 PathInfo path = m_state.board().path(move.from(), move.to());
83 return path.diagonal() && path.clear();
85 case Piece::KNIGHT:
87 return abs(delta.x) == 1 && delta.y == m_state.direction(piece.color()).y * 2;
89 case Piece::LANCE:
91 PathInfo path = m_state.board().path(move.from(), move.to());
92 return delta.x == 0 &&
93 path.clear() &&
94 (delta.y * m_state.direction(piece.color()).y > 0);
96 case Piece::PAWN:
97 return delta == m_state.direction(piece.color());
98 default:
99 return false;
102 else {
103 switch (piece.type()) {
104 case Piece::SILVER:
105 case Piece::PAWN:
106 case Piece::LANCE:
107 case Piece::KNIGHT:
108 return (delta.x == 0 && abs(delta.y) == 1)
109 || (delta.y == 0 && abs(delta.x) == 1)
110 || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1);
111 case Piece::ROOK:
113 if (abs(delta.x) <= 1 && abs(delta.y) <= 1) return true;
114 PathInfo path = m_state.board().path(move.from(), move.to());
115 return path.parallel() && path.clear();
117 case Piece::BISHOP:
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.diagonal() && path.clear();
123 default:
124 return false;
129 template <typename GameState>
130 bool LegalityCheck<GameState>::pseudolegal(Move& move) const {
131 if (move.drop() == Piece() &&
132 move.pool() != -1 &&
133 move.index() != -1) {
134 move.setDrop(m_state.pools().pool(move.pool()).get(move.index()));
137 Piece dropped = move.drop();
138 if (dropped != Piece()) {
139 if (m_state.board().get(move.to()) != Piece())
140 return false;
142 if (stuckPiece(dropped, move.to()))
143 return false;
145 if (dropped.type() == Piece::PAWN) {
146 for (int i = 0; i < m_state.board().size().y; i++) {
147 Piece other = m_state.board().get(Point(move.to().x, i));
148 if (other.type() == Piece::PAWN &&
149 other.color() == m_state.turn() &&
150 !other.promoted())
151 return false;
155 return true;
157 else {
158 Piece piece = m_state.board().get(move.from());
159 if (piece != Piece() && getMoveType(piece, move)) {
160 if (m_state.canPromote(piece) &&
161 (m_state.promotionZone(piece.color(), move.to()) ||
162 m_state.promotionZone(piece.color(), move.from())))
163 move.setType(Move::PROMOTION);
164 return true;
166 else {
167 //std::cerr << "CANNOT MOVE: piece type cannot go there" << std::endl;
168 return false;
173 template <typename GameState>
174 bool LegalityCheck<GameState>::legal(Move& move) const {
175 if (!pseudolegal(move))
176 return false;
178 GameState tmp(m_state);
179 tmp.move(move);
181 // find king position
182 Point king_pos = tmp.board().find(Piece(m_state.turn(), Piece::KING));
183 if (!king_pos.valid())
184 return false;
186 // check if the king can be captured
187 for (int i = 0; i < m_state.board().size().x; i++) {
188 for (int j = 0; j < m_state.board().size().y; j++) {
189 Point p(i, j);
190 Piece piece = tmp.board().get(p);
191 LegalityCheck<GameState> check(tmp);
192 if (piece.color() == tmp.turn() && check.getMoveType(piece, Move(p, king_pos))) {
193 return false;
198 return true;
201 template <typename GameState>
202 bool LegalityCheck<GameState>::stuckPiece(const Piece& piece, const Point& p) const {
203 if (piece.type() == Piece::PAWN || piece.type() == Piece::LANCE) {
204 return p.y == m_state.startingRank(Piece::oppositeColor(piece.color()));
206 else if (piece.type() == Piece::KNIGHT) {
207 int rank = m_state.startingRank(Piece::oppositeColor(piece.color()));
208 return p.y == rank || p.y == rank - m_state.direction(piece.color()).y;
210 else {
211 return false;
215 template <typename GameState>
216 InteractionType LegalityCheck<GameState>::movable(const TurnTest& test, const Point& p) const {
217 Piece piece = m_state.board().get(p);
218 if (piece == Piece() || !test(piece.color()))
219 return NoAction;
221 return piece.color() == m_state.turn() ? Moving : Premoving;
224 template <typename GameState>
225 InteractionType LegalityCheck<GameState>::droppable(const TurnTest& test, int index) const {
226 if (!test(index))
227 return NoAction;
229 typename Piece::Color c = static_cast<typename Piece::Color>(index);
230 return c == m_state.turn() ? Moving : Premoving;
233 } // namespace Shogi
234 } // namespace HLVariant
236 #endif // HLVARIANT__SHOGI__LEGALITYCHECK_H