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.
11 #ifndef HLVARIANT__CHESS__SERIALIZER_H
12 #define HLVARIANT__CHESS__SERIALIZER_H
14 #include <boost/function.hpp>
16 #include "legalitycheck.h"
18 #include "icsverbose.h"
23 template <typename MoveGenerator
>
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
;
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
);
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();
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
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
);
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
);
76 template <typename MoveGenerator
>
77 Serializer
<MoveGenerator
>::Serializer(const QString
& rep
)
80 template <typename MoveGenerator
>
81 Serializer
<MoveGenerator
>::~Serializer() { }
83 template <typename MoveGenerator
>
84 QString Serializer
<MoveGenerator
>::san(const Move
& move
, const GameState
& ref
) {
90 Piece piece
= ref
.board().get(move
.from());
91 Piece captured
= ref
.board().get(move
.captureSquare());
94 return ""; // no piece in the initial square
96 if (move
.kingSideCastling()) {
99 else if (move
.queenSideCastling()) {
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
);
109 if (piece
.type() != Piece::PAWN
)
110 res
= symbol(piece
.type()).toUpper();
113 tmp
.from
= move
.from();
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())
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
);
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)
141 static_cast<typename
Piece::Type
>(move
.promoteTo())
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}");
163 template <typename MoveGenerator
>
164 QString Serializer
<MoveGenerator
>::suffix(const Move
& move
, const GameState
& ref
) {
168 MoveGenerator
generator(tmp
);
169 if (generator
.check(Piece::oppositeColor(ref
.turn()))) {
170 if (generator
.stalled())
180 template <typename MoveGenerator
>
181 typename Serializer
<MoveGenerator
>::Move
182 Serializer
<MoveGenerator
>::get_san(const SAN
& san
, const GameState
& ref
) {
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
)
195 candidate
= Move(from
, to
);
196 LegalityCheck
check(ref
);
197 if (check
.legal(candidate
))
204 if (san
.from
.valid()) {
205 candidate
= Move(san
.from
, san
.to
, static_cast<typename
Piece::Type
>(san
.promotion
));
208 for (int i
= 0; i
< ref
.board().size().x
; i
++) {
209 for (int j
= 0; j
< ref
.board().size().y
; 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()) {
225 // ok, we have found a candidate move
237 template <typename MoveGenerator
>
238 typename Serializer
<MoveGenerator
>::Move
239 Serializer
<MoveGenerator
>::deserialize(const QString
& str
, const GameState
& ref
) {
240 if (m_rep
== "compact") {
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
);
249 // no need to parse simple or decorated moves
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();
265 // add column indication
266 san
.from
= Point(from
.x
, -1);
269 // add row indication
270 san
.from
= Point(-1, from
.y
);
273 // add complete starting point
278 template <typename MoveGenerator
>
279 QChar Serializer
<MoveGenerator
>::symbol(typename
Piece::Type type
) const {
280 if (type
== Piece::KNIGHT
)
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
291 verbose
.load(str
, ref
.board().size().y
);
296 if (verbose
.castling
== SAN::NoCastling
) {
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
));
309 } // namespace HLVariant
311 #endif // HLVARIANT__CHESS__SERIALIZER_H