Preliminary port of Shogi to the component API.
[tagua/yd.git] / src / variants / shogi / validator.cpp
blobba6267a71ea13c7c6bc99eebea6fb805284e1bc1
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 == 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()) != Piece())
60 return false;
62 // cannot drop on a place where piece would be stuck
63 if (stuckPiece(state, dropped, move.dst()))
64 return false;
66 // cannot drop a pawn in a column with already a pawn of same color
67 if (dropped.type() == Pawn::self()) {
68 for (int i = 0; i < state->board()->size().y; i++) {
69 const Piece other = state->board()->get(Point(move.dst().x, i));
70 if (other.type() == Pawn::self() &&
71 other.color() == state->turn() &&
72 !other.get("promoted").toBool())
73 return false;
78 return true;
81 bool Validator::legal(const IState* state, Move& move) const {
82 // do not check a move more than once
83 if (!move.type().isEmpty()) return true;
85 if (!m_delegator->pseudolegal(state, move))
86 return false;
88 const IBehaviour* behaviour = state->behaviour();
89 if (!behaviour) return false;
91 const IColor* turn = m_delegator->mover(state, move);
93 std::auto_ptr<IState> tmp(state->clone());
94 tmp->move(move);
96 Point kingPos = tmp->board()->find(Piece(turn, King::self()));
98 if (kingPos == Point::invalid())
99 return false;
101 if (m_delegator->attacks(tmp.get(), behaviour->opponent(turn), kingPos))
102 return false;
104 // set move type as normal, if not already set
105 if (move.type().isEmpty()) move.setType("normal");
106 return true;
109 // FIXME: move this logic into Piece classes ?
110 bool Validator::stuckPiece(const IState* state,
111 const Piece& piece, const Point& p) const {
112 const IBehaviour* behaviour = state->behaviour();
114 if (piece.type() == Pawn::self() || piece.type() == Lance::self()) {
115 return p.y == state->rank(0, behaviour->opponent(piece.color()));
117 else if (piece.type() == Knight::self()) {
118 int rank = state->rank(0, behaviour->opponent(piece.color()));
119 return p.y == rank || p.y == rank - behaviour->direction(piece.color()).y;
121 else {
122 return false;
126 bool Validator::attacks(const IState* state, const IColor* player,
127 const Point& square, const Piece& target_) const {
128 Piece target;
129 if (target_ != Piece())
130 target = target_;
131 else
132 target = state->board()->get(square);
134 for (int i = 0; i < state->board()->size().x; i++) {
135 for (int j = 0; j < state->board()->size().y; j++) {
136 const Point p(i, j);
137 const Piece piece = state->board()->get(p);
138 Move move(p, square);
139 if (piece != Piece() &&
140 piece.color() == player &&
141 piece.type()->canMove(piece, target, move, state))
142 return true;
145 return false;
148 const IColor* Validator::mover(const IState* state, const Move& move) const {
149 return state->board()->get(move.src()).color();
152 void Validator::setDelegator(IValidator* delegator) {
153 m_delegator = delegator;