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.
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"
25 MoveSerializer::MoveSerializer(const QString
& rep
, IValidator
* validator
)
27 , m_validator(validator
)
28 , m_delegator(this) { }
30 QString
MoveSerializer::san(const Move
& move
, const IState
* ref
) const {
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
);
41 return ""; // no piece in the initial square
43 if (move
.type() == "king_side_castling") {
46 else if (move
.type() == "queen_side_castling") {
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
);
56 if (piece
.type() != Pawn::self())
57 res
= symbol(piece
.type()).toUpper();
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())
69 res
+= tmp
.dst
.toString(ref
->board()->size().y
);
73 res
+= "=" + QString(symbol(move
.promotion()).toUpper());
75 res
+= suffix(move
, ref
);
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
);
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}");
109 QString
MoveSerializer::suffix(const Move
& /*move*/, const IState
* /*ref*/) const {
110 // FIXME use a move generator to add a suffix
113 std::auto_ptr
<IState
> tmp(ref
->clone());
117 MoveGenerator
generator(tmp
);
118 if (generator
.check(Piece::oppositeColor(ref
->turn()))) {
119 if (generator
.stalled())
131 Move
MoveSerializer::get_san(const SAN
& san
, const IState
* ref
) const {
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())
145 candidate
= Move(from
, to
);
146 if (m_validator
->legal(ref
, candidate
))
153 if (san
.src
.valid()) {
154 candidate
= Move(san
.src
, san
.dst
, san
.promotion
);
157 for (int i
= 0; i
< ref
->board()->size().x
; i
++) {
158 for (int j
= 0; j
< ref
->board()->size().y
; 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()) {
172 // ok, we have found a candidate move
184 Move
MoveSerializer::deserialize(const QString
& str
, const IState
* ref
) const {
185 if (m_rep
== "compact") {
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
);
194 // no need to parse simple or decorated moves
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();
209 // add column indication
210 san
.src
= Point(from
.x
, -1);
213 // add row indication
214 san
.src
= Point(-1, from
.y
);
217 // add complete starting point
222 QString
MoveSerializer::symbol(const IType
* type
) const {
223 if (!type
) return "?";
225 if (type
== Knight::self())
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
234 verbose
.load(str
, ref
->board()->size().y
);
239 if (verbose
.castling
== SAN::NoCastling
) {
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
;