2 Copyright (c) 2007 Paolo Capriotti <p.capriotti@sns.it>
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.
11 #ifndef HLVARIANT__CHESS__SERIALIZER_H
12 #define HLVARIANT__CHESS__SERIALIZER_H
14 #include "legalitycheck.h"
16 #include "icsverbose.h"
21 template <typename MoveGenerator
>
25 * Possible string representations for moves.
28 SIMPLE
= 0, /// The most direct way of representing a move.
29 COMPACT
= 1, /// Compact notation. This corresponds to SAN notation for games that support it.
30 DECORATED
= 2, /// Symbolic figurine notation. Figurine names are enclosed in braces.
31 ICS_VERBOSE
= 3 /// Verbose notation as defined by ICS.
34 typedef typename
MoveGenerator::LegalityCheck LegalityCheck
;
35 typedef typename
LegalityCheck::GameState GameState
;
36 typedef typename
GameState::Move Move
;
37 typedef typename
GameState::Board::Piece Piece
;
42 virtual QString
suffix(const Move
& move
, const GameState
& ref
);
44 virtual QString
san(const Move
& move
, const GameState
& ref
);
46 virtual void minimal_notation(SAN
& san
, const GameState
& ref
);
48 virtual Move
get_san(const SAN
& san
, const GameState
& ref
);
50 virtual QChar
symbol(typename
Piece::Type type
) const;
52 virtual Move
parse_ics_verbose(const QString
& str
, const GameState
& ref
);
55 * Create a serializer to a given string representation for moves.
56 * \param rep A move representation.
57 * \sa MoveRepresentation.
61 virtual ~Serializer();
64 * Serialize a move given a reference game state.
65 * We assume the move has already been tested against @a ref.
66 * Calling this function on an untested or illegal move is safe but its return
68 * Do not try to call this function on an invalid move.
69 * \param ref The position in which this move shall be executed.
70 * \return A string representation for this move.
72 virtual QString
serialize(const Move
& move
, const GameState
& ref
);
75 * Convert a string representation of a move back to a move object.
76 * \param ref The position in which this move shall be executed.
77 * \return A move corresponding to the given string representation.
79 virtual Move
deserialize(const QString
& str
, const GameState
& ref
);
85 template <typename MoveGenerator
>
86 Serializer
<MoveGenerator
>::Serializer(int rep
)
89 template <typename MoveGenerator
>
90 Serializer
<MoveGenerator
>::~Serializer() { }
92 template <typename MoveGenerator
>
93 QString Serializer
<MoveGenerator
>::san(const Move
& move
, const GameState
& ref
) {
99 Piece piece
= ref
.board().get(move
.from());
100 Piece captured
= ref
.board().get(move
.captureSquare());
102 if (piece
== Piece())
103 return ""; // no piece in the initial square
105 if (move
.kingSideCastling()) {
108 else if (move
.queenSideCastling()) {
111 else if (piece
.type() == Piece::PAWN
) {
112 if (captured
!= Piece())
113 res
= move
.from().col() + "x";
115 res
+= move
.to().toString(ref
.board().size().y
);
118 if (piece
.type() != Piece::PAWN
)
119 res
= symbol(piece
.type()).toUpper();
122 tmp
.from
= move
.from();
124 tmp
.type
= piece
.type();
125 tmp
.castling
= SAN::NoCastling
;
126 minimal_notation(tmp
, ref
);
128 res
+= tmp
.from
.toString(ref
.board().size().y
);
129 if (captured
!= Piece())
131 res
+= tmp
.to
.toString(ref
.board().size().y
);
134 if (move
.promoteTo() != -1)
135 res
+= "=" + QString(symbol(static_cast<typename
Piece::Type
>(move
.promoteTo())).toUpper());
137 res
+= suffix(move
, ref
);
142 template <typename MoveGenerator
>
143 QString Serializer
<MoveGenerator
>::serialize(const Move
& move
, const GameState
& ref
) {
147 int ysize
= ref
.board().size().y
;
148 QString res
= move
.from().toString(ysize
) + move
.to().toString(ysize
);
149 if (move
.promoteTo() != -1)
152 static_cast<typename
Piece::Type
>(move
.promoteTo())
157 return san(move
, ref
);
160 QString res
= san(move
, ref
);
161 res
.replace('K', "{king}");
162 res
.replace('Q', "{queen}");
163 res
.replace('R', "{rook}");
164 res
.replace('N', "{knight}");
165 res
.replace('B', "{bishop}");
166 res
.replace('P', "{pawn}");
175 template <typename MoveGenerator
>
176 QString Serializer
<MoveGenerator
>::suffix(const Move
& move
, const GameState
& ref
) {
180 MoveGenerator
generator(tmp
);
181 if (generator
.check(Piece::oppositeColor(ref
.turn()))) {
182 if (generator
.stalled())
192 template <typename MoveGenerator
>
193 typename Serializer
<MoveGenerator
>::Move
194 Serializer
<MoveGenerator
>::get_san(const SAN
& san
, const GameState
& ref
) {
200 if (san
.castling
!= SAN::NoCastling
) {
201 Point from
= ref
.kingStartingPosition(ref
.turn());
202 Point to
= from
+ (san
.castling
== SAN::KingSide
? Point(2,0) : Point(-2,0));
203 Piece king
= ref
.board().get(from
);
204 if (king
.type() != Piece::KING
)
207 candidate
= Move(from
, to
);
208 LegalityCheck
check(ref
);
209 if (check
.legal(candidate
))
216 if (san
.from
.valid()) {
217 candidate
= Move(san
.from
, san
.to
, static_cast<typename
Piece::Type
>(san
.promotion
));
220 for (int i
= 0; i
< ref
.board().size().x
; i
++) {
221 for (int j
= 0; j
< ref
.board().size().y
; j
++) {
223 Piece piece
= ref
.board().get(p
);
225 Move
mv(p
, san
.to
, static_cast<typename
Piece::Type
>(san
.promotion
));
226 if (p
.resembles(san
.from
) &&
227 piece
.type() == san
.type
&&
228 piece
.color() == ref
.turn()) {
230 LegalityCheck
check(ref
);
231 if (check
.legal(mv
)) {
232 if (candidate
.valid()) {
237 // ok, we have found a candidate move
249 template <typename MoveGenerator
>
250 typename Serializer
<MoveGenerator
>::Move
251 Serializer
<MoveGenerator
>::deserialize(const QString
& str
, const GameState
& ref
) {
256 tmp
.load(str
, ref
.board().size().y
);
257 return get_san(tmp
, ref
);
260 return parse_ics_verbose(str
, ref
);
264 // no need to parse decorated moves
270 #define TRY(x) if(get_san(x, ref).valid()) return;
271 template <typename MoveGenerator
>
272 void Serializer
<MoveGenerator
>::minimal_notation(SAN
& san
, const GameState
& ref
) {
273 Point from
= san
.from
;
274 san
.castling
= SAN::NoCastling
;
276 // try notation without starting point
277 san
.from
= Point::invalid();
280 // add column indication
281 san
.from
= Point(from
.x
, -1);
284 // add row indication
285 san
.from
= Point(-1, from
.y
);
288 // add complete starting point
293 template <typename MoveGenerator
>
294 QChar Serializer
<MoveGenerator
>::symbol(typename
Piece::Type type
) const {
295 if (type
== Piece::KNIGHT
)
298 return Piece::typeName(type
)[0];
301 template <typename MoveGenerator
>
302 typename Serializer
<MoveGenerator
>::Move
303 Serializer
<MoveGenerator
>::parse_ics_verbose(const QString
& str
, const GameState
& ref
) {
305 verbose
.load(str
, ref
.board().size().y
);
310 if (verbose
.castling
== SAN::NoCastling
) {
315 from
= ref
.kingStartingPosition(ref
.turn());
316 to
= from
+ (verbose
.castling
== SAN::KingSide
? Point(2,0) : Point(-2, 0));
319 return Move(from
, to
, static_cast<typename
Piece::Type
>(verbose
.promotion
));
323 } // namespace HLVariant
325 #endif // HLVARIANT__CHESS__SERIALIZER_H