new 990aace9276b9b070a7fbae82fa73469c6d99ec2
[tagua/yd.git] / src / variants / chess / moveserializer.cpp
blob5c443c2293181398ffaa9125fb7a69c0659ecdc5
1 /*
2 Copyright (c) 2007 Paolo Capriotti <p.capriotti@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 */
10 #include "moveserializer.h"
12 #include <core/behaviour.h>
13 #include <core/board.h>
14 #include <core/move.h>
15 #include <core/point.h>
16 #include <core/state.h>
17 #include <core/validator.h>
19 #include "icsverbose.h"
20 #include "types.h"
21 #include "san.h"
23 namespace Chess {
25 MoveSerializer::MoveSerializer(const QString& rep, IValidator* validator)
26 : m_rep(rep)
27 , m_validator(validator)
28 , m_delegator(this) { }
30 QString MoveSerializer::san(const Move& move, const IState* ref) const {
31 QString res;
33 Point captureSquare = move.dst();
34 if (const IBehaviour* behaviour = ref->behaviour())
35 captureSquare = behaviour->captureSquare(ref, move);
37 Piece piece = ref->board()->get(move.src());
38 Piece captured = ref->board()->get(captureSquare);
40 if (piece == Piece())
41 return ""; // no piece in the initial square
43 if (move.type() == "king_side_castling") {
44 res = "O-O";
46 else if (move.type() == "queen_side_castling") {
47 res = "O-O-O";
49 else if (piece.type() == Pawn::self()) {
50 if (captured != Piece())
51 res = move.src().col() + "x";
53 res += move.dst().toString(ref->board()->size().y);
55 else {
56 if (piece.type() != Pawn::self())
57 res = symbol(piece.type()).toUpper();
59 SAN tmp;
60 tmp.src = move.src();
61 tmp.dst = move.dst();
62 tmp.type = piece.type();
63 tmp.castling = SAN::NoCastling;
64 minimal_notation(tmp, ref);
66 res += tmp.src.toString(ref->board()->size().y);
67 if (captured != Piece())
68 res += "x";
69 res += tmp.dst.toString(ref->board()->size().y);
72 if (move.promotion())
73 res += "=" + QString(symbol(move.promotion()).toUpper());
75 res += suffix(move, ref);
77 return res;
80 QString MoveSerializer::serialize(const Move& move, const IState* ref) const {
81 if (m_rep == "simple") {
82 int ysize = ref->board()->size().y;
83 QString res = move.src().toString(ysize) + move.dst().toString(ysize);
84 if (move.promotion())
85 res = res + "=" +
86 symbol(
87 move.promotion()
88 ).toUpper();
89 return res;
91 else if (m_rep == "compact") {
92 return san(move, ref);
94 else if (m_rep == "decorated") {
95 QString res = san(move, ref);
96 res.replace('K', "{king}");
97 res.replace('Q', "{queen}");
98 res.replace('R', "{rook}");
99 res.replace('N', "{knight}");
100 res.replace('B', "{bishop}");
101 res.replace('P', "{pawn}");
102 return res;
104 else {
105 return "";
109 QString MoveSerializer::suffix(const Move& /*move*/, const IState* /*ref*/) const {
110 // FIXME use a move generator to add a suffix
112 #if 0
113 std::auto_ptr<IState> tmp(ref->clone());
114 tmp->move(move);
117 MoveGenerator generator(tmp);
118 if (generator.check(Piece::oppositeColor(ref->turn()))) {
119 if (generator.stalled())
120 return "#";
121 else
122 return "+";
124 else {
125 return "";
127 #endif
128 return "";
131 Move MoveSerializer::get_san(const SAN& san, const IState* ref) const {
132 Move candidate;
134 if (san.invalid())
135 return candidate;
137 if (san.castling != SAN::NoCastling) {
138 // find king starting position
139 Point from(ref->board()->size().x / 2, ref->rank(0, ref->turn()));
140 Point to = from + (san.castling == SAN::KingSide? Point(2,0) : Point(-2,0));
141 Piece king = ref->board()->get(from);
142 if (king.type() != King::self())
143 return candidate;
144 else {
145 candidate = Move(from, to);
146 if (m_validator->legal(ref, candidate))
147 return candidate;
148 else
149 return Move();
153 if (san.src.valid()) {
154 candidate = Move(san.src, san.dst, san.promotion);
156 else {
157 for (int i = 0; i < ref->board()->size().x; i++) {
158 for (int j = 0; j < ref->board()->size().y; j++) {
159 Point p(i, j);
160 Piece piece = ref->board()->get(p);
162 Move mv(p, san.dst, san.promotion);
163 if (p.resembles(san.src) &&
164 piece.type() == san.type &&
165 piece.color() == ref->turn()) {
166 if (m_validator->legal(ref, mv)) {
167 if (candidate != Move()) {
168 // ambiguous!
169 return Move();
171 else {
172 // ok, we have found a candidate move
173 candidate = mv;
181 return candidate;
184 Move MoveSerializer::deserialize(const QString& str, const IState* ref) const {
185 if (m_rep == "compact") {
186 SAN tmp;
187 tmp.load(str, ref->board()->size().y);
188 return get_san(tmp, ref);
190 else if (m_rep == "ics-verbose") {
191 return parse_ics_verbose(str, ref);
193 else {
194 // no need to parse simple or decorated moves
195 return Move();
200 #define TRY(x) if(get_san(x, ref) != Move()) return;
201 void MoveSerializer::minimal_notation(SAN& san, const IState* ref) const {
202 Point from = san.src;
203 san.castling = SAN::NoCastling;
205 // try notation without starting point
206 san.src = Point::invalid();
207 TRY(san);
209 // add column indication
210 san.src = Point(from.x, -1);
211 TRY(san);
213 // add row indication
214 san.src = Point(-1, from.y);
215 TRY(san);
217 // add complete starting point
218 san.src = from;
220 #undef TRY
222 QString MoveSerializer::symbol(const IType* type) const {
223 if (!type) return "?";
225 if (type == Knight::self())
226 return "n";
227 else
228 return type->name().at(0);
231 Move MoveSerializer::parse_ics_verbose(const QString& str, const IState* ref) const {
232 // here ref is the position _after_ this move
233 ICSVerbose verbose;
234 verbose.load(str, ref->board()->size().y);
236 Point from;
237 Point to;
239 if (verbose.castling == SAN::NoCastling) {
240 from = verbose.src;
241 to = verbose.dst;
243 else {
244 const IColor* opponent = ref->turn();
245 if (const IBehaviour* behaviour = ref->behaviour())
246 opponent = behaviour->opponent(opponent);
247 from = Point(ref->board()->size().x / 2, ref->rank(0, opponent));
248 to = from + (verbose.castling == SAN::KingSide ? Point(2,0) : Point(-2, 0));
251 return Move(from, to, verbose.promotion);
254 QString MoveSerializer::type() const { return m_rep; }
256 void MoveSerializer::setDelegator(IMoveSerializer* delegator) {
257 m_delegator = delegator;
260 } // namespace Chess