new 4475edb243ed4627f4c5f2c470ca40b3def034d4
[tagua/yd.git] / src / variants / shogi / validator.cpp
blob42bcd1ac0d5f34530809540792bd4687e0aa7854
1 #include "validator.h"
2 #include <memory>
3 #include <core/behaviour.h>
4 #include <core/board.h>
5 #include <core/move.h>
6 #include <core/poolcollection.h>
7 #include <core/pool.h>
8 #include <core/state.h>
9 #include <core/type.h>
10 #include "colors.h"
11 #include "types.h"
13 namespace Shogi {
15 Validator::Validator() : m_delegator(this) { }
17 bool Validator::pseudolegal(const IState* state, Move& move) const {
18 // add drop information to move, if missing
19 if (move.drop() == Piece() &&
20 move.pool() && move.index() != -1) {
21 move.setDrop(state->pools()->pool(move.pool())->get(move.index()));
24 Piece dropped = move.drop();
25 if (dropped == Piece()) {
26 if (!state->board()->valid(move.src())) return false;
27 if (!state->board()->valid(move.dst())) return false;
29 const Piece* piece = state->board()->get(move.src());
30 if (piece == NULL || *piece == Piece()) return false;
32 const IBehaviour* behaviour = state->behaviour();
33 if (!behaviour) return false;
35 const IColor* thisTurn = piece->color();
36 if (state->turn() != thisTurn) return false;
38 const Piece* target = state->board()->get(move.dst());
39 if (target->color() == piece->color())
40 return false;
41 if (!piece->type()->canMove(*piece, *target, move, state))
42 return false;
44 #if 0
45 if (move.type() == "promotion") {
46 const IType* promotionType = move.promotion();
47 if (promotionType != Queen::self() &&
48 promotionType != Bishop::self() &&
49 promotionType != Rook::self() &&
50 promotionType != Knight::self()) return false;
52 #endif
53 } else {
54 // dropping on a valid square
55 if (!state->board()->valid(move.dst()))
56 return false;
58 // cannot drop on occupied squares
59 if (state->board()->get(move.dst()) != NULL &&
60 *state->board()->get(move.dst()) != Piece())
61 return false;
63 // cannot drop on a place where piece would be stuck
64 if (stuckPiece(state, dropped, move.dst()))
65 return false;
67 // cannot drop a pawn in a column with already a pawn of same color
68 if (dropped.type() == Pawn::self()) {
69 for (int i = 0; i < state->board()->size().y; i++) {
70 const Piece* other = state->board()->get(Point(move.dst().x, i));
71 if (other->type() == Pawn::self() &&
72 other->color() == state->turn() &&
73 !other->get("promoted").toBool())
74 return false;
79 return true;
82 bool Validator::legal(const IState* state, Move& move) const {
83 // do not check a move more than once
84 if (!move.type().isEmpty()) return true;
86 if (!m_delegator->pseudolegal(state, move))
87 return false;
89 const IBehaviour* behaviour = state->behaviour();
90 if (!behaviour) return false;
92 const IColor* turn = m_delegator->mover(state, move);
94 IState* tmp(state->clone());
95 tmp->move(move);
97 Point kingPos = tmp->board()->find(Piece(turn, King::self()));
99 if (kingPos == Point::invalid())
100 return false;
102 if (m_delegator->attacks(tmp, behaviour->opponent(turn), kingPos))
103 return false;
105 // set move type as normal, if not already set
106 if (move.type().isEmpty()) move.setType("normal");
107 return true;
110 // FIXME: move this logic into Piece classes ?
111 bool Validator::stuckPiece(const IState* state,
112 const Piece& piece, const Point& p) const {
113 const IBehaviour* behaviour = state->behaviour();
115 if (piece.type() == Pawn::self() || piece.type() == Lance::self()) {
116 return p.y == state->rank(0, behaviour->opponent(piece.color()));
118 else if (piece.type() == Knight::self()) {
119 int rank = state->rank(0, behaviour->opponent(piece.color()));
120 return p.y == rank || p.y == rank - behaviour->direction(piece.color()).y;
122 else {
123 return false;
127 bool Validator::attacks(const IState* state, const IColor* player,
128 const Point& square, const Piece& target_) const {
129 const Piece* target;
130 if (target_ != Piece())
131 target = &target_;
132 else
133 target = state->board()->get(square);
135 for (int i = 0; i < state->board()->size().x; i++) {
136 for (int j = 0; j < state->board()->size().y; j++) {
137 Point p(i, j);
138 const Piece* piece = state->board()->get(p);
139 Move move(p, square);
140 if (piece != NULL &&
141 *piece != Piece() &&
142 piece->color() == player &&
143 piece->type()->canMove(*piece, *target, move, state))
144 return true;
147 return false;
150 const IColor* Validator::mover(const IState* state, const Move& move) const {
151 return state->board()->get(move.src())->color();
154 void Validator::setDelegator(IValidator* delegator) {
155 m_delegator = delegator;