Remove debugging traces, now that PGN load/save works.
[tagua/yd.git] / src / hlvariant / shogi / serializer.h
blob9b2c7b53b0060ee5d0dd2b2b4f40c7afa02f4396
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>
17 namespace HLVariant {
18 namespace Shogi {
20 template <typename _LegalityCheck>
21 class Serializer {
22 static QRegExp pattern;
23 public:
24 typedef _LegalityCheck LegalityCheck;
25 typedef typename LegalityCheck::GameState GameState;
26 typedef typename GameState::Board Board;
27 typedef typename Board::Piece Piece;
28 typedef typename GameState::Move Move;
29 protected:
30 QString m_rep;
32 virtual bool isAmbiguous(const Move& move, const GameState& ref) const;
33 virtual QString square(const Point& p, const Point& size) const;
34 virtual QString symbol(const Piece& piece) const;
35 virtual typename Piece::Type getType(const QChar& letter) const;
36 public:
37 Serializer(const QString& rep);
38 virtual ~Serializer();
40 QString serialize(const Move&, const GameState& ref);
41 Move deserialize(const QString& str, const GameState& ref);
43 Move parse(const QString&, int& offset, int ysize, const GameState& ref);
44 Move parse(const QString&, int ysize, const GameState& ref);
47 // IMPLEMENTATION
49 template <typename LegalityCheck>
50 Serializer<LegalityCheck>::Serializer(const QString& rep)
51 : m_rep(rep) { }
54 template <typename LegalityCheck>
55 Serializer<LegalityCheck>::~Serializer() { }
57 template <typename LegalityCheck>
58 bool Serializer<LegalityCheck>::isAmbiguous(const Move& move, const GameState& ref) const {
59 Piece piece = move.drop();
60 if (piece == Piece())
61 piece = ref.board().get(move.from());
63 bool ambiguous = false;
64 if (move.drop() == Piece()) {
65 for (int i = 0; i < ref.board().size().x; i++) {
66 for (int j = 0; j < ref.board().size().x; j++) {
67 Point p(i, j);
68 if (p == move.from() || ref.board().get(p) != piece)
69 continue;
70 Move mv(p, move.to());
71 LegalityCheck check(ref);
72 if (check.legal(mv)) {
73 ambiguous = true;
74 break;
80 return ambiguous;
83 template <typename LegalityCheck>
84 QString Serializer<LegalityCheck>::square(const Point& p, const Point& size) const {
85 QString res = QString::number(size.x - p.x);
86 if (m_rep == "decorated") {
87 res += "{num_" + QString::number(p.y + 1) + "}";
89 else {
90 res += QString(p.y + 'a');
93 return res;
97 template <typename LegalityCheck>
98 QString Serializer<LegalityCheck>::serialize(const Move& move, const GameState& ref) {
99 Piece piece = move.drop();
100 if (piece == Piece())
101 piece = ref.board().get(move.from());
103 QString res;
105 if (m_rep == "simple") {
106 if (move.drop() != Piece()) {
107 res += symbol(piece);
108 res += '*';
109 } else
110 res += square(move.from(), ref.board().size());
111 res += square(move.to(), ref.board().size());
112 if (move.promoteTo() != -1)
113 res += "+";
114 return res;
116 else {
117 bool ambiguous = isAmbiguous(move, ref);
119 QString res;
120 if (piece.promoted())
121 res += "+";
123 res += symbol(piece);
125 if (ambiguous) {
126 res += square(move.from(), ref.board().size());
129 if (move.drop() != Piece())
130 res += "*";
131 else if (ref.board().get(move.to()) != Piece())
132 res += "x";
133 else
134 res += "-";
136 res += square(move.to(), ref.board().size());
138 // if it is a promotion
139 if (move.promoteTo() != -1)
140 res += "+";
141 // if it is a refused promotion
142 else if (ref.canPromote(piece) &&
143 move.drop() == Piece() &&
144 ref.promotionZone(ref.turn(), move.to())) {
145 res += "=";
148 return res;
152 template <typename LegalityCheck>
153 QString Serializer<LegalityCheck>::symbol(const Piece& piece) const {
154 if (m_rep == "decorated") {
155 QString res = "{";
156 if (piece.promoted())
157 res += "p_";
158 res += piece.typeName();
159 if (piece.type() == Piece::KING)
160 res += piece.color() == Piece::BLACK ? '1' : '2';
161 return res + "}";
163 else {
164 if (piece.type() == Piece::KNIGHT)
165 return "N";
166 else
167 return piece.typeName()[0].toUpper();
171 template <typename LegalityCheck>
172 typename Serializer<LegalityCheck>::Piece::Type
173 Serializer<LegalityCheck>::getType(const QChar& letter) const {
174 switch(letter.toLower().toAscii()) {
175 case 'p':
176 return Piece::PAWN;
177 case 'r':
178 return Piece::ROOK;
179 case 'b':
180 return Piece::BISHOP;
181 case 'l':
182 return Piece::LANCE;
183 case 'n':
184 return Piece::KNIGHT;
185 case 's':
186 return Piece::SILVER;
187 case 'g':
188 return Piece::GOLD;
189 case 'k':
190 return Piece::KING;
191 default:
192 return Piece::INVALID_TYPE;
196 template <typename LegalityCheck>
197 QRegExp Serializer<LegalityCheck>::
198 // 1 2 3 4 5 6 7
199 pattern("^(([+])?([PRBLNSGK]))?((\\d*)([a-wyzA-Z])?)([-x*])?"
200 // 8 9
201 "(\\d+[a-zA-Z])?([+=])?[\?!]*");
203 template <typename LegalityCheck>
204 typename Serializer<LegalityCheck>::Move
205 Serializer<LegalityCheck>::parse(const QString& str, int& offset,
206 int ysize, const GameState& ref) {
207 if (pattern.indexIn(str, offset, QRegExp::CaretAtOffset) != -1) {
208 Point from;
209 typename Serializer<LegalityCheck>::Piece::Type type;
210 bool promoted;
211 int promotion;
212 Move candidate;
214 type = getType(pattern.cap(3)[0]);
215 promoted = pattern.cap(2) == "+";
216 Point to(ref.board().size().x - pattern.cap(8)[0].digitValue(),
217 pattern.cap(8)[1].toAscii() - 'a');
218 promotion = (pattern.cap(9) == "+") ? 1 : -1;
220 if (pattern.cap(7) == "*") // is a drop ?
221 return Move(Piece(ref.turn(), type), to);
223 from = Point((pattern.cap(5).length() == 0) ? -1 :
224 ref.board().size().x - pattern.cap(5)[0].digitValue(),
225 (pattern.cap(6).length() == 0) ? -1 :
226 pattern.cap(6)[0].toAscii() - 'a');
228 if (from.valid()) { // explicit from ?
229 candidate = Move(from, to, static_cast<typename Piece::Type>(promotion));
231 else { // resolve implicit from
232 for (int i = 0; i < ref.board().size().x; i++) {
233 for (int j = 0; j < ref.board().size().y; j++) {
234 Point p(i, j);
235 Piece piece = ref.board().get(p);
237 Move mv(p, to, static_cast<typename Piece::Type>(promotion));
238 if (p.resembles(from) &&
239 piece.type() == type &&
240 piece.promoted() == promoted &&
241 piece.color() == ref.turn()) {
243 LegalityCheck check(ref);
244 if (check.legal(mv)) {
245 if (candidate.valid()) {
246 // ambiguous!
247 std::cerr << "ambiguous !" << std::endl;
248 return Move();
250 else {
251 // ok, we have found a candidate move
252 candidate = mv;
260 if (!candidate.valid())
261 std::cerr << "error - piece not found" << std::endl;
263 offset += pattern.matchedLength();
264 return candidate;
266 else {
267 std::cout << "error!!!! " << qPrintable(str.mid(offset)) << std::endl;
268 return Move(Point::invalid(),Point::invalid());
272 template <typename LegalityCheck>
273 typename Serializer<LegalityCheck>::Move
274 Serializer<LegalityCheck>::parse(const QString& str, int ysize,
275 const GameState& ref) {
276 int offset = 0;
277 return parse(str, offset, ysize, ref);
280 template <typename LegalityCheck>
281 typename Serializer<LegalityCheck>::Move
282 Serializer<LegalityCheck>::deserialize(const QString& str, const GameState& ref) {
283 if (str[0].isDigit()) {
284 // this is a move
285 Point orig(ref.board().size().x - str[0].digitValue(), str[1].toAscii() - 'a');
286 Point dest(ref.board().size().x - str[2].digitValue(), str[3].toAscii() - 'a');
287 return Move(orig, dest, ((str.size() > 4) && (str[4] == '+')) ? 1 : -1);
289 else
290 return parse(str, ref.board().size().y, ref);
293 } // namespace Shogi
294 } // namespace HLVariant
296 #endif // HLVARIANT__SHOGI__SERIALIZER_H