Serializers use strings instead of integers to represent serialization types.
[tagua.git] / src / hlvariant / chess / serializer.h
blobe4d39fe77ffbe7068582a6aeb3dc07261df7d59b
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__CHESS__SERIALIZER_H
12 #define HLVARIANT__CHESS__SERIALIZER_H
14 #include <boost/function.hpp>
16 #include "legalitycheck.h"
17 #include "san.h"
18 #include "icsverbose.h"
20 namespace HLVariant {
21 namespace Chess {
23 template <typename MoveGenerator>
24 class Serializer {
25 protected:
26 typedef typename MoveGenerator::LegalityCheck LegalityCheck;
27 typedef typename LegalityCheck::GameState GameState;
28 typedef typename GameState::Move Move;
29 typedef typename GameState::Board::Piece Piece;
31 QString m_rep;
33 protected:
34 virtual QString suffix(const Move& move, const GameState& ref);
36 virtual QString san(const Move& move, const GameState& ref);
38 virtual void minimal_notation(SAN& san, const GameState& ref);
40 virtual Move get_san(const SAN& san, const GameState& ref);
42 virtual QChar symbol(typename Piece::Type type) const;
44 virtual Move parse_ics_verbose(const QString& str, const GameState& ref);
45 public:
46 /**
47 * Create a serializer to a given string representation for moves.
48 * \param rep A move representation type.
50 Serializer(const QString& rep);
52 virtual ~Serializer();
54 /**
55 * Serialize a move given a reference game state.
56 * We assume the move has already been tested against @a ref.
57 * Calling this function on an untested or illegal move is safe but its return
58 * value is undefined.
59 * Do not try to call this function on an invalid move.
60 * \param ref The position in which this move shall be executed.
61 * \return A string representation for this move.
63 virtual QString serialize(const Move& move, const GameState& ref);
65 /**
66 * Convert a string representation of a move back to a move object.
67 * \param ref The position in which this move shall be executed.
68 * \return A move corresponding to the given string representation.
70 virtual Move deserialize(const QString& str, const GameState& ref);
74 // IMPLEMENTATION
76 template <typename MoveGenerator>
77 Serializer<MoveGenerator>::Serializer(const QString& rep)
78 : m_rep(rep) { }
80 template <typename MoveGenerator>
81 Serializer<MoveGenerator>::~Serializer() { }
83 template <typename MoveGenerator>
84 QString Serializer<MoveGenerator>::san(const Move& move, const GameState& ref) {
85 if (!move.valid())
86 return "";
88 QString res;
90 Piece piece = ref.board().get(move.from());
91 Piece captured = ref.board().get(move.captureSquare());
93 if (piece == Piece())
94 return ""; // no piece in the initial square
96 if (move.kingSideCastling()) {
97 res = "O-O";
99 else if (move.queenSideCastling()) {
100 res = "O-O-O";
102 else if (piece.type() == Piece::PAWN) {
103 if (captured != Piece())
104 res = move.from().col() + "x";
106 res += move.to().toString(ref.board().size().y);
108 else {
109 if (piece.type() != Piece::PAWN)
110 res = symbol(piece.type()).toUpper();
112 SAN tmp;
113 tmp.from = move.from();
114 tmp.to = move.to();
115 tmp.type = piece.type();
116 tmp.castling = SAN::NoCastling;
117 minimal_notation(tmp, ref);
119 res += tmp.from.toString(ref.board().size().y);
120 if (captured != Piece())
121 res += "x";
122 res += tmp.to.toString(ref.board().size().y);
125 if (move.promoteTo() != -1)
126 res += "=" + QString(symbol(static_cast<typename Piece::Type>(move.promoteTo())).toUpper());
128 res += suffix(move, ref);
130 return res;
133 template <typename MoveGenerator>
134 QString Serializer<MoveGenerator>::serialize(const Move& move, const GameState& ref) {
135 if (m_rep == "simple") {
136 int ysize = ref.board().size().y;
137 QString res = move.from().toString(ysize) + move.to().toString(ysize);
138 if (move.promoteTo() != -1)
139 res = res + "=" +
140 symbol(
141 static_cast<typename Piece::Type>(move.promoteTo())
142 ).toUpper();
143 return res;
145 else if (m_rep == "compact") {
146 return san(move, ref);
148 else if (m_rep == "decorated") {
149 QString res = san(move, ref);
150 res.replace('K', "{king}");
151 res.replace('Q', "{queen}");
152 res.replace('R', "{rook}");
153 res.replace('N', "{knight}");
154 res.replace('B', "{bishop}");
155 res.replace('P', "{pawn}");
156 return res;
158 else {
159 return "";
163 template <typename MoveGenerator>
164 QString Serializer<MoveGenerator>::suffix(const Move& move, const GameState& ref) {
165 GameState tmp(ref);
166 tmp.move(move);
168 MoveGenerator generator(tmp);
169 if (generator.check(Piece::oppositeColor(ref.turn()))) {
170 if (generator.stalled())
171 return "#";
172 else
173 return "+";
175 else {
176 return "";
180 template <typename MoveGenerator>
181 typename Serializer<MoveGenerator>::Move
182 Serializer<MoveGenerator>::get_san(const SAN& san, const GameState& ref) {
183 Move candidate;
185 if (san.invalid())
186 return candidate;
188 if (san.castling != SAN::NoCastling) {
189 Point from = ref.kingStartingPosition(ref.turn());
190 Point to = from + (san.castling == SAN::KingSide? Point(2,0) : Point(-2,0));
191 Piece king = ref.board().get(from);
192 if (king.type() != Piece::KING)
193 return candidate;
194 else {
195 candidate = Move(from, to);
196 LegalityCheck check(ref);
197 if (check.legal(candidate))
198 return candidate;
199 else
200 return Move();
204 if (san.from.valid()) {
205 candidate = Move(san.from, san.to, static_cast<typename Piece::Type>(san.promotion));
207 else {
208 for (int i = 0; i < ref.board().size().x; i++) {
209 for (int j = 0; j < ref.board().size().y; j++) {
210 Point p(i, j);
211 Piece piece = ref.board().get(p);
213 Move mv(p, san.to, static_cast<typename Piece::Type>(san.promotion));
214 if (p.resembles(san.from) &&
215 piece.type() == san.type &&
216 piece.color() == ref.turn()) {
218 LegalityCheck check(ref);
219 if (check.legal(mv)) {
220 if (candidate.valid()) {
221 // ambiguous!
222 return Move();
224 else {
225 // ok, we have found a candidate move
226 candidate = mv;
234 return candidate;
237 template <typename MoveGenerator>
238 typename Serializer<MoveGenerator>::Move
239 Serializer<MoveGenerator>::deserialize(const QString& str, const GameState& ref) {
240 if (m_rep == "compact") {
241 SAN tmp;
242 tmp.load(str, ref.board().size().y);
243 return get_san(tmp, ref);
245 else if (m_rep == "ics-verbose") {
246 return parse_ics_verbose(str, ref);
248 else {
249 // no need to parse simple or decorated moves
250 return Move();
255 #define TRY(x) if(get_san(x, ref).valid()) return;
256 template <typename MoveGenerator>
257 void Serializer<MoveGenerator>::minimal_notation(SAN& san, const GameState& ref) {
258 Point from = san.from;
259 san.castling = SAN::NoCastling;
261 // try notation without starting point
262 san.from = Point::invalid();
263 TRY(san);
265 // add column indication
266 san.from = Point(from.x, -1);
267 TRY(san);
269 // add row indication
270 san.from = Point(-1, from.y);
271 TRY(san);
273 // add complete starting point
274 san.from = from;
276 #undef TRY
278 template <typename MoveGenerator>
279 QChar Serializer<MoveGenerator>::symbol(typename Piece::Type type) const {
280 if (type == Piece::KNIGHT)
281 return 'n';
282 else
283 return Piece::typeName(type)[0];
286 template <typename MoveGenerator>
287 typename Serializer<MoveGenerator>::Move
288 Serializer<MoveGenerator>::parse_ics_verbose(const QString& str, const GameState& ref) {
289 // here ref is the position _after_ this move
290 ICSVerbose verbose;
291 verbose.load(str, ref.board().size().y);
293 Point from;
294 Point to;
296 if (verbose.castling == SAN::NoCastling) {
297 from = verbose.from;
298 to = verbose.to;
300 else {
301 from = ref.kingStartingPosition(ref.previousTurn());
302 to = from + (verbose.castling == SAN::KingSide ? Point(2,0) : Point(-2, 0));
305 return Move(from, to, static_cast<typename Piece::Type>(verbose.promotion));
308 } // namespace Chess
309 } // namespace HLVariant
311 #endif // HLVARIANT__CHESS__SERIALIZER_H