Switch to manual memory management in legal().
[tagua/yd.git] / src / variants / chess / validator.cpp
blobf76950d3292c8c223b1045fd739f9b0948dbefc3
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/state.h>
7 #include <core/type.h>
8 #include "colors.h"
9 #include "types.h"
11 namespace Chess {
13 Validator::Validator() : m_delegator(this) { }
15 bool Validator::pseudolegal(const IState* state, Move& move) const {
16 if (!state->board()->valid(move.src())) return false;
17 if (!state->board()->valid(move.dst())) return false;
19 Piece piece = state->board()->get(move.src());
20 if (piece == Piece()) return false;
22 const IBehaviour* behaviour = state->behaviour();
23 if (!behaviour) return false;
25 const IColor* thisTurn = piece.color();
26 const IColor* otherTurn = behaviour->opponent(thisTurn);
28 if (state->turn() != thisTurn) return false;
30 Piece target = state->board()->get(move.dst());
31 if (target.color() == piece.color())
32 return false;
33 if (!piece.type()->canMove(piece, target, move, state))
34 return false;
36 if (move.type() == "promotion") {
37 const IType* promotionType = move.promotion();
38 if (promotionType != Queen::self() &&
39 promotionType != Bishop::self() &&
40 promotionType != Rook::self() &&
41 promotionType != Knight::self()) return false;
44 if (move.type() == "king_side_castling") {
45 if (m_delegator->attacks(state, otherTurn, move.src()) ||
46 m_delegator->attacks(state, otherTurn, move.src() + Point(1, 0), piece))
47 return false;
49 if (move.type() == "queen_side_castling") {
50 if (m_delegator->attacks(state, otherTurn, move.src()) ||
51 m_delegator->attacks(state, otherTurn, move.src() + Point(-1, 0), piece))
52 return false;
55 return true;
58 bool Validator::legal(const IState* state, Move& move) const {
59 // do not check a move more than once
60 if (!move.type().isEmpty()) return true;
62 if (!m_delegator->pseudolegal(state, move))
63 return false;
65 const IBehaviour* behaviour = state->behaviour();
66 if (!behaviour) return false;
68 const IColor* turn = m_delegator->mover(state, move);
70 IState* tmp = state->clone();
71 Q_ASSERT(tmp);
72 tmp->move(move);
74 Point kingPos = tmp->board()->find(Piece(turn, King::self()));
76 if (kingPos == Point::invalid()) {
77 delete tmp;
78 return false;
81 if (m_delegator->attacks(tmp, behaviour->opponent(turn), kingPos)) {
82 delete tmp;
83 return false;
86 delete tmp;
88 // set move type as normal, if not already set
89 if (move.type().isEmpty()) move.setType("normal");
90 return true;
93 bool Validator::attacks(const IState* state, const IColor* player,
94 const Point& square, const Piece& target_) const {
95 Piece target;
96 if (target_ != Piece())
97 target = target_;
98 else
99 target = state->board()->get(square);
101 for (int i = 0; i < state->board()->size().x; i++) {
102 for (int j = 0; j < state->board()->size().y; j++) {
103 const Point p(i, j);
104 const Piece piece = state->board()->get(p);
105 Move move(p, square);
106 if (piece != Piece() &&
107 piece.color() == player &&
108 piece.type()->canMove(piece, target, move, state))
109 return true;
112 return false;
115 const IColor* Validator::mover(const IState* state, const Move& move) const {
116 return state->board()->get(move.src()).color();
119 void Validator::setDelegator(IValidator* delegator) {
120 m_delegator = delegator;