From 565c74ae815031522318e350a2501faa00bf133b Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Wed, 30 Jan 2008 01:19:34 +0100 Subject: [PATCH] Implement for shogi deserialization of the notation used for saving PGN --- TODO_shogi | 6 ++ src/hlvariant/shogi/serializer.h | 130 +++++++++++++++++++++++++++++++++++---- 2 files changed, 125 insertions(+), 11 deletions(-) diff --git a/TODO_shogi b/TODO_shogi index 38ce8ce..ad24c29 100644 --- a/TODO_shogi +++ b/TODO_shogi @@ -1,3 +1,9 @@ +- finalize deserialization breakages +- PGN save should write variant tag +- PGN load confused after returning from variations - gamestate issue ? +- save/load support for PalView continuations: (* 10. f5) + http://www.eurochess.org/games/games/kusadasi/palview4/manual/pgn.htm + tagua core: - gnushogi engine gets confused when moving through history => generic pb ? - tooltips for figurines, for people who can't read kanji diff --git a/src/hlvariant/shogi/serializer.h b/src/hlvariant/shogi/serializer.h index c5fa273..57d3fb0 100644 --- a/src/hlvariant/shogi/serializer.h +++ b/src/hlvariant/shogi/serializer.h @@ -12,12 +12,14 @@ #define HLVARIANT__SHOGI__SERIALIZER_H #include +#include namespace HLVariant { namespace Shogi { template class Serializer { + static QRegExp pattern; public: typedef _LegalityCheck LegalityCheck; typedef typename LegalityCheck::GameState GameState; @@ -37,6 +39,9 @@ public: QString serialize(const Move&, const GameState& ref); Move deserialize(const QString& str, const GameState& ref); + + Move parse(const QString&, int& offset, int ysize, const GameState& ref); + Move parse(const QString&, int ysize, const GameState& ref); }; // IMPLEMENTATION @@ -189,24 +194,127 @@ Serializer::getType(const QChar& letter) const { } template -typename Serializer::Move +QRegExp Serializer:: +// 1 2 3 4 5 6 7 + pattern("^(([+])?([PRBLNSGK]))?((\\d*)([a-wyzA-Z])?)([-x*])?" +// 8 9 + "(\\d+[a-zA-Z])?([+=])?[\?!]*"); + +template +typename Serializer::Move +Serializer::parse(const QString& str, int& offset, + int ysize, const GameState& ref) { + std::cerr << "Looking at " << qPrintable(str) << std::endl; + if (pattern.indexIn(str, offset, QRegExp::CaretAtOffset) != -1) { + Point from; + typename Serializer::Piece::Type type; + bool promoted; + int promotion; + Move candidate; + + type = getType(pattern.cap(3)[0]); + promoted = pattern.cap(2) == "+"; + Point to(ref.board().size().x - pattern.cap(8)[0].digitValue(), + pattern.cap(8)[1].toAscii() - 'a'); + promotion = (pattern.cap(9) == "+") ? 1 : -1; + + if (pattern.cap(7) == "*") // is a drop ? + return Move(Piece(ref.turn(), type), to); + + from = Point((pattern.cap(5).length() == 0) ? -1 : + ref.board().size().x - pattern.cap(5)[0].digitValue(), + (pattern.cap(6).length() == 0) ? -1 : + pattern.cap(6)[0].toAscii() - 'a'); + + if (from.valid()) { // explicit from ? + candidate = Move(from, to, static_cast(promotion)); + std::cerr << "from " << from.x << "," << from.y + << " already valid, to" << to.x << "," << to.y + << std::endl; + } + else { // resolve implicit from + std::cerr << "Pattern is " << qPrintable(pattern.cap(8)) + << ", type is " << type << (promoted ? "+" : "") + << ", from is " << from.x << "," << from.y + << ", target is " << to.x << "," << to.y + << std::endl; + + for (int i = 0; i < ref.board().size().x; i++) { + for (int j = 0; j < ref.board().size().y; j++) { + Point p(i, j); + Piece piece = ref.board().get(p); + std::cerr << "looking at " << i << "," << j + << ", piece is " << piece.type() + << (piece.promoted() ? "+" : "") + << std::endl; + + Move mv(p, to, static_cast(promotion)); + if (p.resembles(from) && + piece.type() == type && + piece.promoted() == promoted && + piece.color() == ref.turn()) { + + LegalityCheck check(ref); + if (check.legal(mv)) { + if (candidate.valid()) { + // ambiguous! + std::cerr << "ambiguous !" << std::endl; + return Move(); + } + else { + // ok, we have found a candidate move + std::cerr << "candidate moved from " + << mv.from().x << "," << mv.from().y + << std::endl; + candidate = mv; + } + } + else std::cerr << "piece at " << i << "," << j + << " cannot move to " << to.toString(ref.board().size().y) + << " aka " << to.x << "," << to.y + << std::endl; + } + else std::cerr << "skipping" << std::endl; + } + } + } + + if (!candidate.valid()) + std::cerr << "error - piece not found" << std::endl; + else + std::cerr << "move is " << serialize(candidate, ref) + << " from " << candidate.from().x << "," << candidate.from().y + << std::endl; + + offset += pattern.matchedLength(); + return candidate; + } + else { + std::cout << "error!!!! " << qPrintable(str.mid(offset)) << std::endl; + return Move(Point::invalid(),Point::invalid()); + } +} + +template +typename Serializer::Move +Serializer::parse(const QString& str, int ysize, + const GameState& ref) { + int offset = 0; + return parse(str, offset, ysize, ref); +} + +template +typename Serializer::Move Serializer::deserialize(const QString& str, const GameState& ref) { + std::cerr << "shogi deserializing a " << qPrintable(m_rep) << " move" << std::endl; if (str[0].isDigit()) { // this is a move Point orig(ref.board().size().x - str[0].digitValue(), str[1].toAscii() - 'a'); Point dest(ref.board().size().x - str[2].digitValue(), str[3].toAscii() - 'a'); return Move(orig, dest, ((str.size() > 4) && (str[4] == '+')) ? 1 : -1); } - else { - if (str[1] != '*') { - std::cerr << "Expected a star, got a '" << str[1].toAscii() << "'" << std::endl; - return Move(); - } - typename Piece::Type t = getType(str[0]); - Point to(ref.board().size().x - str[2].digitValue(), str[3].toAscii() - 'a'); - return Move(Piece(ref.turn(), t), to); - } - + else + return parse(str, ref.board().size().y, ref); } } // namespace Shogi -- 2.11.4.GIT