Added a simple SAN test.
[tagua/yd.git] / tests / hlvariants / prototype / chess / serializer.h
blob0b9c786b38beb45077116faa168f18de70cf0d74
1 /*
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.
9 */
11 #ifndef HLVARIANT__CHESS__SERIALIZER_H
12 #define HLVARIANT__CHESS__SERIALIZER_H
14 #include "legalitycheck.h"
15 #include "san.h"
17 namespace HLVariant {
18 namespace Chess {
20 template <typename MoveGenerator>
21 class Serializer {
22 public:
23 /**
24 * Possible string representations for moves.
26 enum {
27 SIMPLE = 0, /// The most direct way of representing a move.
28 COMPACT = 1, /// Compact notation. This corresponds to SAN notation for games that support it.
29 DECORATED = 2 /// Symbolic figurine notation. Figurine names are enclosed in braces.
30 } MoveRepresentation;
31 private:
32 typedef typename MoveGenerator::LegalityCheck LegalityCheck;
33 typedef typename LegalityCheck::GameState GameState;
34 typedef typename GameState::Move Move;
35 typedef typename GameState::Board::Piece Piece;
37 int m_rep;
39 protected:
40 virtual QString suffix(const Move& move, const GameState& ref);
42 virtual QString san(const Move& move, const GameState& ref);
44 virtual void minimal_notation(SAN& san, const GameState& ref);
46 virtual Move get_san(const SAN& san, const GameState& ref);
47 public:
48 /**
49 * Create a serializer to a given string representation for moves.
50 * \param rep A move representation.
51 * \sa MoveRepresentation.
53 Serializer(int rep);
55 virtual ~Serializer();
57 /**
58 * Serialize a move given a reference game state.
59 * We assume the move has already been tested against @a ref.
60 * Calling this function on an untested or illegal move is safe but its return
61 * value is undefined.
62 * Do not try to call this function on an invalid move.
63 * \param ref The position in which this move shall be executed.
64 * \return A string representation for this move.
66 virtual QString serialize(const Move& move, const GameState& ref);
68 /**
69 * Convert a string representation of a move back to a move object.
70 * \param ref The position in which this move shall be executed.
71 * \return A move corresponding to the given string representation.
73 virtual Move deserialize(const QString& str, const GameState& ref);
77 // IMPLEMENTATION
79 template <typename MoveGenerator>
80 Serializer<MoveGenerator>::Serializer(int rep)
81 : m_rep(rep) { }
83 template <typename MoveGenerator>
84 Serializer<MoveGenerator>::~Serializer() { }
86 template <typename MoveGenerator>
87 QString Serializer<MoveGenerator>::san(const Move& move, const GameState& ref) {
88 if (!move.valid())
89 return "";
91 QString res;
93 Piece piece = ref.board().get(move.from());
94 Piece captured = ref.board().get(move.captureSquare());
96 if (piece == Piece())
97 return ""; // no piece in the initial square
99 if (move.kingSideCastling()) {
100 res = "O-O";
102 else if (move.queenSideCastling()) {
103 res = "O-O-O";
105 else {
106 if (piece.type() != Piece::PAWN)
107 res = piece.typeName()[0].toUpper();
109 SAN tmp;
110 tmp.from = move.from();
111 tmp.to = move.to();
112 tmp.type = piece.type();
113 tmp.castling = SAN::NoCastling;
114 minimal_notation(tmp, ref);
116 res += tmp.from.toString(ref.board().size().y);
117 if (captured != Piece())
118 res += "x";
119 res += tmp.to.toString(ref.board().size().y);
122 if (move.promoteTo() != -1)
123 res += "=" + QString(Piece::typeName(
124 static_cast<typename Piece::Type>(move.promoteTo())
125 )[0].toUpper());
127 res += suffix(move, ref);
129 return res;
132 template <typename MoveGenerator>
133 QString Serializer<MoveGenerator>::serialize(const Move& move, const GameState& ref) {
134 switch (m_rep) {
135 case SIMPLE:
136 case COMPACT:
137 return san(move, ref);
138 case DECORATED:
140 QString res = san(move, ref);
141 res.replace('K', "{king}");
142 res.replace('Q', "{queen}");
143 res.replace('R', "{rook}");
144 res.replace('N', "{knight}");
145 res.replace('B', "{bishop}");
146 res.replace('P', "{pawn}");
147 return res;
149 default:
150 return "";
154 template <typename MoveGenerator>
155 QString Serializer<MoveGenerator>::suffix(const Move& move, const GameState& ref) {
156 GameState tmp(ref);
157 tmp.move(move);
159 MoveGenerator generator(tmp);
160 if (generator.check(ref.turn())) {
161 if (generator.stalled())
162 return "#";
163 else
164 return "+";
166 else {
167 return "";
171 template <typename MoveGenerator>
172 typename Serializer<MoveGenerator>::Move
173 Serializer<MoveGenerator>::get_san(const SAN& san, const GameState& ref) {
174 Move candidate;
176 if (san.invalid())
177 return candidate;
179 if (san.castling != SAN::NoCastling) {
180 Point from = ref.kingStartingPosition(ref.turn());
181 Point to = from + (san.castling == SAN::KingSide? Point(2,0) : Point(-2,0));
182 Piece king = ref.board().get(from);
183 if (king.type() != Piece::KING)
184 return candidate;
185 else
186 return Move(from, to);
189 if (san.from.valid()) {
190 candidate = Move(san.from, san.to, static_cast<typename Piece::Type>(san.promotion));
192 else {
193 for (int i = 0; i < ref.board().size().x; i++) {
194 for (int j = 0; j < ref.board().size().y; j++) {
195 Point p(i, j);
196 Piece piece = ref.board().get(p);
198 Move mv(p, san.to, static_cast<typename Piece::Type>(san.promotion));
199 if (p.resembles(san.from) &&
200 piece.type() == san.type &&
201 piece.color() == ref.turn()) {
203 LegalityCheck check(ref);
204 if (check.legal(mv)) {
205 if (candidate.valid()) {
206 // ambiguous!
207 return Move();
209 else {
210 // ok, we have found a candidate move
211 candidate = mv;
219 return candidate;
222 template <typename MoveGenerator>
223 typename Serializer<MoveGenerator>::Move
224 Serializer<MoveGenerator>::deserialize(const QString& str, const GameState& ref) {
225 switch (m_rep) {
226 case SIMPLE:
227 return Move(); // BROKEN
228 case COMPACT:
230 SAN tmp;
231 tmp.load(str, ref.board().size().y);
232 return get_san(tmp, ref);
234 case DECORATED:
235 default:
236 // no need to parse decorated moves
237 return Move();
242 #define TRY(x) if(get_san(x, ref).valid()) return;
243 template <typename MoveGenerator>
244 void Serializer<MoveGenerator>::minimal_notation(SAN& san, const GameState& ref) {
245 Point from = san.from;
246 san.castling = SAN::NoCastling;
248 // try notation without starting point
249 san.from = Point::invalid();
250 TRY(san);
252 // add column indication
253 san.from = Point(from.x, -1);
254 TRY(san);
256 // add row indication
257 san.from = Point(-1, from.y);
258 TRY(san);
260 // add complete starting point
261 san.from = from;
263 #undef TRY
265 } // namespace Chess
266 } // namespace HLVariant
268 #endif // HLVARIANT__CHESS__SERIALIZER_H