Replaced all std::cout with kDebug.
[tagua/yd.git] / src / hlvariant / shogi / serializer.h
blobf3f394eba4a29c847323083a35f0240a27047346
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__SHOGI__SERIALIZER_H
12 #define HLVARIANT__SHOGI__SERIALIZER_H
14 #include <QString>
15 #include <QRegExp>
16 #include <KDebug>
18 namespace HLVariant {
19 namespace Shogi {
21 template <typename _LegalityCheck>
22 class Serializer {
23 static QRegExp pattern;
24 public:
25 typedef _LegalityCheck LegalityCheck;
26 typedef typename LegalityCheck::GameState GameState;
27 typedef typename GameState::Board Board;
28 typedef typename Board::Piece Piece;
29 typedef typename GameState::Move Move;
30 protected:
31 QString m_rep;
33 virtual bool isAmbiguous(const Move& move, const GameState& ref) const;
34 virtual QString square(const Point& p, const Point& size) const;
35 virtual QString symbol(const Piece& piece) const;
36 virtual typename Piece::Type getType(const QChar& letter) const;
37 public:
38 Serializer(const QString& rep);
39 virtual ~Serializer();
41 QString serialize(const Move&, const GameState& ref);
42 Move deserialize(const QString& str, const GameState& ref);
44 Move parse(const QString&, int& offset, int ysize, const GameState& ref);
45 Move parse(const QString&, int ysize, const GameState& ref);
48 // IMPLEMENTATION
50 template <typename LegalityCheck>
51 Serializer<LegalityCheck>::Serializer(const QString& rep)
52 : m_rep(rep) { }
55 template <typename LegalityCheck>
56 Serializer<LegalityCheck>::~Serializer() { }
58 template <typename LegalityCheck>
59 bool Serializer<LegalityCheck>::isAmbiguous(const Move& move, const GameState& ref) const {
60 Piece piece = move.drop();
61 if (piece == Piece())
62 piece = ref.board().get(move.from());
64 bool ambiguous = false;
65 if (move.drop() == Piece()) {
66 for (int i = 0; i < ref.board().size().x; i++) {
67 for (int j = 0; j < ref.board().size().x; j++) {
68 Point p(i, j);
69 if (p == move.from() || ref.board().get(p) != piece)
70 continue;
71 Move mv(p, move.to());
72 LegalityCheck check(ref);
73 if (check.legal(mv)) {
74 ambiguous = true;
75 break;
81 return ambiguous;
84 template <typename LegalityCheck>
85 QString Serializer<LegalityCheck>::square(const Point& p, const Point& size) const {
86 QString res = QString::number(size.x - p.x);
87 if (m_rep == "decorated") {
88 res += "{num_" + QString::number(p.y + 1) + "}";
90 else {
91 res += QString(p.y + 'a');
94 return res;
98 template <typename LegalityCheck>
99 QString Serializer<LegalityCheck>::serialize(const Move& move, const GameState& ref) {
100 Piece piece = move.drop();
101 if (piece == Piece())
102 piece = ref.board().get(move.from());
104 QString res;
106 if (m_rep == "simple") {
107 if (move.drop() != Piece()) {
108 res += symbol(piece);
109 res += '*';
110 } else
111 res += square(move.from(), ref.board().size());
112 res += square(move.to(), ref.board().size());
113 if (move.promoteTo() != -1)
114 res += "+";
115 return res;
117 else {
118 bool ambiguous = isAmbiguous(move, ref);
120 QString res;
121 if (piece.promoted())
122 res += "+";
124 res += symbol(piece);
126 if (ambiguous) {
127 res += square(move.from(), ref.board().size());
130 if (move.drop() != Piece())
131 res += "*";
132 else if (ref.board().get(move.to()) != Piece())
133 res += "x";
134 else
135 res += "-";
137 res += square(move.to(), ref.board().size());
139 // if it is a promotion
140 if (move.promoteTo() != -1)
141 res += "+";
142 // if it is a refused promotion
143 else if (ref.canPromote(piece) &&
144 move.drop() == Piece() &&
145 ref.promotionZone(ref.turn(), move.to())) {
146 res += "=";
149 return res;
153 template <typename LegalityCheck>
154 QString Serializer<LegalityCheck>::symbol(const Piece& piece) const {
155 if (m_rep == "decorated") {
156 QString res = "{";
157 if (piece.promoted())
158 res += "p_";
159 res += piece.typeName();
160 if (piece.type() == Piece::KING)
161 res += piece.color() == Piece::BLACK ? '1' : '2';
162 return res + "}";
164 else {
165 if (piece.type() == Piece::KNIGHT)
166 return "N";
167 else
168 return piece.typeName()[0].toUpper();
172 template <typename LegalityCheck>
173 typename Serializer<LegalityCheck>::Piece::Type
174 Serializer<LegalityCheck>::getType(const QChar& letter) const {
175 switch(letter.toLower().toAscii()) {
176 case 'p':
177 return Piece::PAWN;
178 case 'r':
179 return Piece::ROOK;
180 case 'b':
181 return Piece::BISHOP;
182 case 'l':
183 return Piece::LANCE;
184 case 'n':
185 return Piece::KNIGHT;
186 case 's':
187 return Piece::SILVER;
188 case 'g':
189 return Piece::GOLD;
190 case 'k':
191 return Piece::KING;
192 default:
193 return Piece::INVALID_TYPE;
197 template <typename LegalityCheck>
198 QRegExp Serializer<LegalityCheck>::
199 // 1 2 3 4 5 6 7
200 pattern("^(([+])?([PRBLNSGK]))?((\\d*)([a-wyzA-Z])?)([-x*])?"
201 // 8 9
202 "(\\d+[a-zA-Z])?([+=])?[\?!]*");
204 template <typename LegalityCheck>
205 typename Serializer<LegalityCheck>::Move
206 Serializer<LegalityCheck>::parse(const QString& str, int& offset,
207 int ysize, const GameState& ref) {
208 if (pattern.indexIn(str, offset, QRegExp::CaretAtOffset) != -1) {
209 Point from;
210 typename Serializer<LegalityCheck>::Piece::Type type;
211 bool promoted;
212 int promotion;
213 Move candidate;
215 type = getType(pattern.cap(3)[0]);
216 promoted = pattern.cap(2) == "+";
217 Point to(ref.board().size().x - pattern.cap(8)[0].digitValue(),
218 pattern.cap(8)[1].toAscii() - 'a');
219 promotion = (pattern.cap(9) == "+") ? 1 : -1;
221 if (pattern.cap(7) == "*") // is a drop ?
222 return Move(Piece(ref.turn(), type), to);
224 from = Point((pattern.cap(5).length() == 0) ? -1 :
225 ref.board().size().x - pattern.cap(5)[0].digitValue(),
226 (pattern.cap(6).length() == 0) ? -1 :
227 pattern.cap(6)[0].toAscii() - 'a');
229 if (from.valid()) { // explicit from ?
230 candidate = Move(from, to, static_cast<typename Piece::Type>(promotion));
232 else { // resolve implicit from
233 for (int i = 0; i < ref.board().size().x; i++) {
234 for (int j = 0; j < ref.board().size().y; j++) {
235 Point p(i, j);
236 Piece piece = ref.board().get(p);
238 Move mv(p, to, static_cast<typename Piece::Type>(promotion));
239 if (p.resembles(from) &&
240 piece.type() == type &&
241 piece.promoted() == promoted &&
242 piece.color() == ref.turn()) {
244 LegalityCheck check(ref);
245 if (check.legal(mv)) {
246 if (candidate.valid()) {
247 // ambiguous!
248 std::cerr << "ambiguous !";
249 return Move();
251 else {
252 // ok, we have found a candidate move
253 candidate = mv;
261 if (!candidate.valid())
262 std::cerr << "error - piece not found";
264 offset += pattern.matchedLength();
265 return candidate;
267 else {
268 kDebug() << "error!!!! " << qPrintable(str.mid(offset));
269 return Move(Point::invalid(),Point::invalid());
273 template <typename LegalityCheck>
274 typename Serializer<LegalityCheck>::Move
275 Serializer<LegalityCheck>::parse(const QString& str, int ysize,
276 const GameState& ref) {
277 int offset = 0;
278 return parse(str, offset, ysize, ref);
281 template <typename LegalityCheck>
282 typename Serializer<LegalityCheck>::Move
283 Serializer<LegalityCheck>::deserialize(const QString& str, const GameState& ref) {
284 if (str[0].isDigit()) {
285 // this is a move
286 Point orig(ref.board().size().x - str[0].digitValue(), str[1].toAscii() - 'a');
287 Point dest(ref.board().size().x - str[2].digitValue(), str[3].toAscii() - 'a');
288 return Move(orig, dest, ((str.size() > 4) && (str[4] == '+')) ? 1 : -1);
290 else
291 return parse(str, ref.board().size().y, ref);
294 } // namespace Shogi
295 } // namespace HLVariant
297 #endif // HLVARIANT__SHOGI__SERIALIZER_H