GNUShogi engine.
[tagua/yd.git] / src / variants / shogi.cpp
blob435d0701145de5425d2096b0ed3513063032a57a
1 /*
2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@sns.it>
3 (c) 2006 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 #include "shogi.h"
12 #include "xchess/animator.h"
13 #include "xchess/piece.h"
14 #include "xchess/move.h"
15 #include "moveserializer.impl.h"
16 #include "xchess/dropanimator.impl.h"
17 #include "crazyhouse_p.h"
18 #include "interactiontype.h"
19 #include "turnpolicy.h"
20 #include "tagua_wrapped.h"
21 #include "icsapi.impl.h"
23 class ShogiPiece {
24 public:
25 enum Type {
26 KING,
27 GOLD,
28 SILVER,
29 KNIGHT,
30 LANCE,
31 ROOK,
32 BISHOP,
33 PAWN,
34 INVALID_TYPE
36 enum Color {
37 BLACK,
38 WHITE,
39 INVALID_COLOR
41 typedef bool PromotionType;
42 private:
43 Color m_color;
44 Type m_type;
45 bool m_promoted;
46 public:
47 ShogiPiece()
48 : m_color(INVALID_COLOR)
49 , m_type(INVALID_TYPE)
50 , m_promoted(false) { }
51 ShogiPiece(ShogiPiece::Color color, ShogiPiece::Type type, bool promoted = false);
52 ShogiPiece(const ShogiPiece& other);
54 void promote() { m_promoted = true; }
55 bool promoted() { return m_promoted; }
57 bool operator<(const ShogiPiece& p) const {
58 if (m_promoted == p.m_promoted)
59 if (m_color == p.m_color)
60 return m_type < p.m_type;
61 else
62 return m_color < p.m_color;
63 else
64 return m_promoted < p.m_promoted;
67 QString name() const;
68 static QString typeName(ShogiPiece::Type t);
69 bool valid() const { return m_color != INVALID_COLOR && m_type != INVALID_TYPE; }
70 operator bool() const { return valid(); }
71 bool operator!() const { return !valid(); }
73 bool equals(const ShogiPiece* p) const {
74 if (valid()) {
75 if (p)
76 return (*this) == (*p);
77 else
78 return false;
80 else
81 return !p;
84 bool operator==(const ShogiPiece& p) const {
85 return m_promoted == p.m_promoted &&
86 m_color == p.m_color &&
87 m_type == p.m_type;
90 bool operator!=(const ShogiPiece& p) const {
91 return !(operator==(p));
94 static Type getType(const QString& t);
95 static QString typeSymbol(ShogiPiece::Type t);
97 bool canMove(const class ShogiPosition&, const Point&, const Point&) const;
98 Color color() const { return m_color; }
99 Type type() const { return m_type; }
101 static Color oppositeColor(Color c) { return c == WHITE ? BLACK : WHITE; }
102 Point direction() const { return Point(0, m_color == WHITE ? 1 : -1); }
105 ShogiPiece::ShogiPiece(ShogiPiece::Color color, ShogiPiece::Type type, bool promoted)
106 : m_color(color)
107 , m_type(type)
108 , m_promoted(promoted) { }
110 ShogiPiece::ShogiPiece(const ShogiPiece& other)
111 : m_color(other.m_color)
112 , m_type(other.m_type)
113 , m_promoted(other.m_promoted) { }
115 QString ShogiPiece::name() const {
116 QString res = m_color == WHITE ? "white_" : "black_";
117 if (m_promoted)
118 res += "p_";
119 res += typeName(m_type);
120 return res;
123 QString ShogiPiece::typeName(ShogiPiece::Type t) {
124 switch (t) {
125 case KING:
126 return "king";
127 case GOLD:
128 return "gold";
129 case SILVER:
130 return "silver";
131 case KNIGHT:
132 return "knight";
133 case LANCE:
134 return "lance";
135 case ROOK:
136 return "rook";
137 case BISHOP:
138 return "bishop";
139 case PAWN:
140 return "pawn";
141 default:
142 return "unknown";
146 ShogiPiece::Type ShogiPiece::getType(const QString&) {
147 return KING; // FIXME
150 QString ShogiPiece::typeSymbol(ShogiPiece::Type t) {
151 switch (t) {
152 case KING:
153 return "K";
154 case GOLD:
155 return "G";
156 case SILVER:
157 return "S";
158 case KNIGHT:
159 return "N";
160 case LANCE:
161 return "L";
162 case ROOK:
163 return "R";
164 case BISHOP:
165 return "B";
166 case PAWN:
167 return "P";
168 default:
169 return "?";
173 // ------------------------------
175 class ShogiMove {
176 ShogiPiece m_drop;
178 int m_pool;
179 int m_pool_index;
181 bool m_promote;
182 template<typename T> friend class MoveSerializer;
183 public:
184 Point from;
185 Point to;
187 ShogiMove();
188 ShogiMove(const Point& from, const Point& to, bool promote);
189 ShogiMove(int pool, int pool_index, const Point& to);
191 QString toString(int, int) const;
193 bool operator==(const ShogiMove& other) const;
195 const ShogiPiece& drop() const { return m_drop; }
196 void setDrop(const ShogiPiece& piece) { m_drop = piece; }
197 int pool() const { return m_pool; }
198 int poolIndex() const { return m_pool_index; }
200 bool promote() const { return m_promote; }
201 bool valid() const { return to.valid(); }
204 ShogiMove::ShogiMove()
205 : m_pool(-1)
206 , m_pool_index(-1)
207 , m_promote(true)
208 , from(Point::invalid())
209 , to(Point::invalid()) { }
211 ShogiMove::ShogiMove(const Point& from, const Point& to, bool promote)
212 : m_pool(-1)
213 , m_pool_index(-1)
214 , m_promote(promote)
215 , from(from)
216 , to(to) { }
218 ShogiMove::ShogiMove(int pool, int pool_index, const Point& to)
219 : m_pool(pool)
220 , m_pool_index(pool_index)
221 , m_promote(false)
222 , from(Point::invalid())
223 , to(to) { }
225 QString ShogiMove::toString(int xsize, int ysize) const {
226 QString res = from.numcol(xsize) + from.alpharow()
227 + to.numcol(xsize) + to.alpharow();
228 //if (m_promote) res = res + "+";
230 return res;
233 bool ShogiMove::operator==(const ShogiMove& other) const {
234 if (m_drop)
235 return m_drop == other.m_drop
236 && to == other.to;
237 else
238 return m_promote == other.m_promote
239 && to == other.to
240 && from == other.from;
243 // ------------------------------
245 class ShogiPosition {
246 public:
247 typedef ShogiPiece Piece;
248 typedef ShogiMove Move;
250 typedef PoolReference<ShogiPosition> PoolReference;
251 typedef PoolConstReference<ShogiPosition> PoolConstReference;
252 typedef PoolReference::Pool Pool;
253 typedef PoolReference::PlayerPool PlayerPool;
254 private:
255 Piece::Color m_turn;
256 Grid<Piece> m_board;
257 Pool m_pool;
258 public:
259 template<typename T> friend class MoveSerializer;
260 ShogiPosition();
261 ShogiPosition(const ShogiPosition&);
262 ShogiPosition(Piece::Color turn, bool wk, bool wq,
263 bool bk, bool bq, const Point& ep);
264 ShogiPosition(const QList<boost::shared_ptr<BaseOpt> >& opts);
265 virtual ShogiPosition* clone() const { return new ShogiPosition(*this); }
266 virtual ~ShogiPosition() { }
268 virtual void setup();
270 bool testMove(Move&) const;
271 bool pseudolegal(Move& m) const;
273 PoolReference pool(int);
274 PoolConstReference pool(int) const;
276 PlayerPool& rawPool(Piece::Color color) { return m_pool[color]; }
277 const PlayerPool& rawPool(Piece::Color color) const { return const_cast<Pool&>(m_pool)[color]; }
279 virtual const Point first() const { return m_board.first(); }
280 virtual const Point last() const { return m_board.last(); }
281 virtual Point next(const Point& p) const { return m_board.next(p); }
282 inline bool valid(const Point& p) const { return m_board.valid(p); }
284 ShogiPiece get(const Point& p) const;
285 void set(const Point& p, const Piece& piece);
287 ShogiPiece operator[](const Point& p) const { return m_board[p]; }
289 Piece::Color turn() const { return m_turn; }
290 void setTurn(Piece::Color turn) { m_turn = turn; }
291 Piece::Color previousTurn() const { return Piece::oppositeColor(m_turn); }
292 void switchTurn() { m_turn = Piece::oppositeColor(m_turn); }
294 InteractionType movable(const TurnTest& test, const Point& p) const {
295 if (!valid(p) || !m_board[p] || !test(m_board[p].color()))
296 return NoAction;
297 return m_board[p].color() == m_turn ? Moving : Premoving;
299 InteractionType droppable(const TurnTest& test, int p) const {
300 if (!test(m_turn))
301 return NoAction;
302 ShogiPiece::Color c = static_cast<ShogiPiece::Color>(p);
303 return c == m_turn ? Moving : Premoving;
305 void move(const ShogiMove& m);
307 void fromFEN(const QString&, bool& ok) { ok = false; }
308 QString fen(int, int) const { return ""; }
309 bool operator==(const ShogiPosition& p) const;
311 static Move getVerboseMove(Piece::Color turn, const VerboseNotation& m);
312 Move getMove(const AlgebraicNotation&, bool& ok) const;
313 boost::shared_ptr<ShogiPiece> moveHint(const ShogiMove& m) const;
315 Point size() const { return Point(9,9); }
316 void dump() const { }
318 static bool promotionZone(Piece::Color color, const Point& p);
319 static bool stuckPiece(const Piece& piece, const Point& to);
320 PathInfo path(const Point& from, const Point& to) const { return m_board.path(from, to); }
321 QStringList borderCoords() const;
324 ShogiPosition::ShogiPosition()
325 : m_turn(ShogiPiece::BLACK)
326 , m_board(9,9) { }
328 ShogiPosition::ShogiPosition(const ShogiPosition& other)
329 : m_turn(other.m_turn)
330 , m_board(other.m_board)
331 , m_pool(other.m_pool) { }
333 ShogiPosition::ShogiPosition(Piece::Color turn, bool, bool, bool, bool, const Point&)
334 : m_turn(turn)
335 , m_board(9, 9) { }
337 ShogiPosition::ShogiPosition(const QList<boost::shared_ptr<BaseOpt> >&)
338 : m_turn(ShogiPiece::BLACK)
339 , m_board(9,9) { }
341 QStringList ShogiPosition::borderCoords() const
343 QStringList retv;
344 for(int i=m_board.getSize().y; i>0; i--)
345 retv += QString::number(i);
346 retv << QChar(0x4e5d) << QChar(0x516b) << QChar(0x4e03) << QChar(0x516d)
347 << QChar(0x4e94) << QChar(0x56db) << QChar(0x4e09) << QChar(0x4e8c) << QChar(0x4e00);
348 return retv + retv;
351 bool ShogiPiece::canMove(const ShogiPosition& pos,
352 const Point& from, const Point& to) const {
353 if (!from.valid()) return false;
354 if (!to.valid()) return false;
355 if (from == to) return false;
356 if (pos[to].color() == m_color) return false;
357 Point delta = to - from;
359 if (!m_promoted) {
360 switch (m_type) {
361 case KING:
362 return abs(delta.x) <= 1 && abs(delta.y) <= 1;
363 case GOLD:
364 return (delta.x == 0 && abs(delta.y) == 1)
365 || (delta.y == 0 && abs(delta.x) == 1)
366 || (delta.y == direction().y && abs(delta.x) <= 1);
367 case SILVER:
368 return (abs(delta.x) == abs(delta.y) && abs(delta.x) == 1)
369 || (delta.y == direction().y && abs(delta.x) <= 1);
370 case ROOK:
372 PathInfo path = pos.path(from, to);
373 return path.parallel() && path.clear();
375 case BISHOP:
377 PathInfo path = pos.path(from, to);
378 return path.diagonal() && path.clear();
380 case KNIGHT:
382 return abs(delta.x) == 1 && delta.y == direction().y * 2;
384 case LANCE:
386 PathInfo path = pos.path(from, to);
387 return delta.x == 0 && path.clear() && (delta.y * direction().y > 0);
389 case PAWN:
390 return delta.x == 0 && delta.y == direction().y;
391 default:
392 return false;
395 else {
396 switch (m_type) {
397 case SILVER:
398 case PAWN:
399 case LANCE:
400 case KNIGHT:
401 return (delta.x == 0 && abs(delta.y) == 1)
402 || (delta.y == 0 && abs(delta.x) == 1)
403 || (delta.y == direction().y && abs(delta.x) <= 1);
404 case ROOK:
406 if (abs(delta.x) <= 1 && abs(delta.y) <= 1) return true;
407 PathInfo path = pos.path(from, to);
408 return path.parallel() && path.clear();
410 case BISHOP:
412 if (abs(delta.x) <= 1 && abs(delta.y) <= 1) return true;
413 PathInfo path = pos.path(from, to);
414 return path.diagonal() && path.clear();
416 default:
417 return false;
423 ShogiPosition::Move ShogiPosition::getVerboseMove(Piece::Color, const VerboseNotation&) {
424 return Move();
427 ShogiPosition::Move ShogiPosition::getMove(const AlgebraicNotation&, bool& ok) const {
428 ok = false;
429 return Move();
432 ShogiPiece ShogiPosition::get(const Point& p) const {
433 if (m_board.valid(p)) {
434 return m_board[p];
436 else {
437 return ShogiPiece();
441 void ShogiPosition::set(const Point& p, const ShogiPiece& piece) {
442 if (m_board.valid(p)) {
443 m_board[p] = piece;
447 ShogiPosition::PoolReference ShogiPosition::pool(int index) {
448 ShogiPiece::Color color = static_cast<ShogiPiece::Color>(index);
449 return PoolReference(&m_pool[color], color);
452 ShogiPosition::PoolConstReference ShogiPosition::pool(int index) const {
453 ShogiPiece::Color color = static_cast<ShogiPiece::Color>(index);
454 return PoolConstReference(&m_pool[color], color);
457 bool ShogiPosition::operator==(const ShogiPosition& p) const {
458 return m_turn == p.m_turn
459 && m_board == p.m_board;
462 boost::shared_ptr<ShogiPiece> ShogiPosition::moveHint(const ShogiMove& m) const {
463 if (m.drop()) return boost::shared_ptr<ShogiPiece>(new ShogiPiece(m.drop()));
464 else return boost::shared_ptr<ShogiPiece>();
467 bool ShogiPosition::promotionZone(Piece::Color color, const Point& p) {
468 return color == ShogiPiece::WHITE ? p.y >= 6 : p.y <= 2;
471 #define SET_PIECE(i,j, color, type) m_board[Point(i,j)] = Piece(ShogiPiece::color, ShogiPiece::type)
472 void ShogiPosition::setup() {
473 for (int i = 0; i < m_board.getSize().x; i++) {
474 SET_PIECE(i, 2, WHITE, PAWN);
475 SET_PIECE(i, 6, BLACK, PAWN);
478 SET_PIECE(0,0, WHITE, LANCE);
479 SET_PIECE(1,0, WHITE, KNIGHT);
480 SET_PIECE(2,0, WHITE, SILVER);
481 SET_PIECE(3,0, WHITE, GOLD);
482 SET_PIECE(4,0, WHITE, KING);
483 SET_PIECE(5,0, WHITE, GOLD);
484 SET_PIECE(6,0, WHITE, SILVER);
485 SET_PIECE(7,0, WHITE, KNIGHT);
486 SET_PIECE(8,0, WHITE, LANCE);
487 SET_PIECE(1,1, WHITE, ROOK);
488 SET_PIECE(7,1, WHITE, BISHOP);
490 SET_PIECE(0,8, BLACK, LANCE);
491 SET_PIECE(1,8, BLACK, KNIGHT);
492 SET_PIECE(2,8, BLACK, SILVER);
493 SET_PIECE(3,8, BLACK, GOLD);
494 SET_PIECE(4,8, BLACK, KING);
495 SET_PIECE(5,8, BLACK, GOLD);
496 SET_PIECE(6,8, BLACK, SILVER);
497 SET_PIECE(7,8, BLACK, KNIGHT);
498 SET_PIECE(8,8, BLACK, LANCE);
499 SET_PIECE(1,7, BLACK, BISHOP);
500 SET_PIECE(7,7, BLACK, ROOK);
503 m_turn = ShogiPiece::BLACK;
505 #undef SET_PIECE
507 bool ShogiPosition::testMove(Move& m) const {
508 if (!pseudolegal(m))
509 return false;
511 ShogiPosition tmp(*this);
512 tmp.move(m);
514 // find king position
515 Point king_pos = Point::invalid();
516 ShogiPiece king(m_turn, ShogiPiece::KING);
517 for (Point i = tmp.m_board.first(); i <= tmp.m_board.last(); i = tmp.m_board.next(i)) {
518 if (ShogiPiece p = tmp[i])
519 if (p == king) {
520 king_pos = i;
521 break;
524 if (!king_pos.valid()) return false;
526 // check if the king can be captured
527 for (Point i = tmp.m_board.first(); i <= tmp.m_board.last(); i = tmp.m_board.next(i)) {
528 if (ShogiPiece p = tmp[i])
529 if (p.color() == tmp.turn() && p.canMove(tmp, i, king_pos)) return false;
532 return true;
535 bool ShogiPosition::stuckPiece(const ShogiPiece& piece, const Point& p) {
536 if (piece.type() == Piece::PAWN) {
537 if (p.y == (piece.color() == Piece::WHITE ? 8 : 0))
538 return true;
540 else if (piece.type() == Piece::KNIGHT) {
541 if (piece.color() == Piece::WHITE) {
542 if (p.y >= 7)
543 return true;
545 else {
546 if (p.y <= 1)
547 return true;
550 return false;
553 bool ShogiPosition::pseudolegal(Move& m) const {
554 if (!m.drop() && m.pool() != -1 && m.poolIndex() != -1) {
555 m.setDrop(pool(m.pool()).get(m.poolIndex()));
558 if (ShogiPiece dropped = m.drop()) {
559 if (m_board[m.to]) return false;
560 if (stuckPiece(dropped, m.to)) return false;
561 if (dropped.type() == Piece::PAWN) {
562 for (int i = 0; i < m_board.getSize().y; i++)
563 if (ShogiPiece other = m_board[Point(m.to.x, i)])
564 if (other.color() == m_turn && other.type() == Piece::PAWN && !other.promoted()) return false;
566 return true;
568 else {
569 const Piece& p = m_board[m.from];
570 return p && p.canMove(*this, m.from, m.to);
574 void ShogiPosition::move(const ShogiMove& m) {
575 if (Piece dropped = m.drop()) {
576 m_board[m.to] = dropped;
577 if (!--rawPool(dropped.color())[dropped.type()])
578 rawPool(dropped.color()).erase(dropped.type());
580 else {
581 if (Piece captured = m_board[m.to]) {
582 rawPool(Piece::oppositeColor(captured.color()))[captured.type()]++;
585 m_board[m.to] = m_board[m.from];
586 m_board[m.from] = Piece();
589 if (promotionZone(m_turn, m.to) || promotionZone(m_turn, m.from)) {
590 if (m.promote() || stuckPiece(m_board[m.to], m.to)) {
591 Piece::Type type = m_board[m.to].type();
592 if (type != ShogiPiece::KING && type != ShogiPiece::GOLD)
593 m_board[m.to].promote();
597 switchTurn();
600 class ShogiAnimatorBase;
602 class ShogiVariantInfo {
603 public:
604 static QStringList getNumbers() {
605 return QStringList() << QChar(0x4e5d) << QChar(0x516b) << QChar(0x4e03)
606 << QChar(0x516d) << QChar(0x4e94) << QChar(0x56db)
607 << QChar(0x4e09) << QChar(0x4e8c) << QChar(0x4e00);
610 typedef ShogiPosition Position;
611 typedef Position::Move Move;
612 typedef Position::Piece Piece;
613 typedef DropAnimatorMixin<ShogiAnimatorBase> Animator;
614 typedef NoPool Pool;
616 static const bool hasICS = false;
617 static const bool m_simple_moves = false;
618 static void forallPieces(PieceFunction& f);
619 static int moveListLayout() { return 0; }
620 static OptList positionOptions() { return OptList(); }
621 static const char *m_name;
622 static const char *m_theme_proxy;
625 const char *ShogiVariantInfo::m_name = "Shogi_OLD";
626 const char *ShogiVariantInfo::m_theme_proxy = "Shogi";
629 void ShogiVariantInfo::forallPieces(PieceFunction& f) {
630 ChessVariant::forallPieces(f);
633 VariantInfo* ShogiVariant::static_shogi_variant = 0;
635 VariantInfo* ShogiVariant::info() {
636 if (!static_shogi_variant)
637 static_shogi_variant = new WrappedVariantInfo<ShogiVariantInfo>;
638 return static_shogi_variant;
641 class ShogiAnimatorBase : public BaseAnimator<ShogiVariantInfo> {
642 public:
643 typedef ShogiVariantInfo Variant;
644 protected:
645 typedef BaseAnimator<ShogiVariantInfo> Base;
646 typedef Base::API API;
647 public:
648 ShogiAnimatorBase(API cinterface)
649 : Base(cinterface) { }
651 virtual AnimationGroupPtr forward(const ShogiPosition& final, const ShogiMove& move) {
652 AnimationFactory res(m_cinterface->inner());
654 NamedSprite piece = m_cinterface->takeSprite(move.from);
655 NamedSprite captured = m_cinterface->takeSprite(move.to);
656 m_cinterface->setSprite(move.to, piece);
658 if (piece)
659 res.addPreAnimation(Animate::move(piece, move.to));
661 if (captured)
662 res.addPostAnimation(Animate::destroy(captured));
664 if (final.get(move.to) != m_cinterface->position()->get(move.from)) {
665 Piece promoted = final.get(move.to);
667 if (promoted) {
668 QPoint real = m_cinterface->converter()->toReal(move.to);
669 NamedSprite old_sprite = m_cinterface->getSprite(move.to);
670 NamedSprite new_sprite = m_cinterface->setPiece(move.to, promoted, false);
672 res.addPostAnimation(Animate::morph(old_sprite, new_sprite));
676 return res;
679 virtual AnimationGroupPtr back(const ShogiPosition& final, const ShogiMove& move) {
680 AnimationFactory res(m_cinterface->inner());
682 NamedSprite piece = m_cinterface->takeSprite(move.to);
683 NamedSprite captured;
684 if (Piece captured_piece = final.get(move.to)) {
685 captured = m_cinterface->setPiece(move.to, captured_piece, false);
686 res.addPreAnimation(Animate::appear(captured));
689 if (!piece) {
690 piece = m_cinterface->createPiece(move.to, final.get(move.from), false);
691 res.addPreAnimation(Animate::appear(piece));
694 m_cinterface->setSprite(move.from, piece);
696 if (final.get(move.from) != m_cinterface->position()->get(move.to)) {
697 Piece old_piece = final.get(move.from);
698 if (old_piece) {
699 NamedSprite old = m_cinterface->createPiece(move.to, old_piece, false);
700 res.addPreAnimation(Animate::morph(piece, old));
702 // replace piece with pawn
703 m_cinterface->setSprite(move.from, old);
704 piece = old;
708 res.addPreAnimation(Animate::move(piece, move.from));
710 return res;
715 template <>
716 class MoveSerializer<ShogiPosition> {
717 const ShogiMove& m_move;
718 const ShogiPosition& m_ref;
719 bool isAmbiguous() const {
720 ShogiPiece p = m_move.drop() ? m_move.drop() : m_ref.m_board[m_move.from];
721 bool ambiguous = false;
722 if (!m_move.drop())
723 for (Point i = m_ref.m_board.first(); i <= m_ref.m_board.last(); i = m_ref.m_board.next(i) ) {
724 if (i==m_move.from || m_ref.m_board[i] != p)
725 continue;
726 ShogiMove mv(i, m_move.to, false);
727 if (m_ref.testMove(mv)) {
728 ambiguous = true;
729 break;
732 return ambiguous;
734 public:
735 MoveSerializer(const ShogiMove& m, const ShogiPosition& r)
736 : m_move(m), m_ref(r) { }
738 QString SAN() const {
739 ShogiPiece p = m_move.drop() ? m_move.drop() : m_ref.m_board[m_move.from];
740 bool ambiguous = isAmbiguous();
741 QString retv;
742 if (p.promoted())
743 retv += "+";
744 retv += ShogiPiece::typeSymbol(p.type());
745 if (ambiguous) {
746 retv += QString::number(m_ref.m_board.getSize().x-m_move.from.x);
747 retv += QString(m_move.from.y+'a');
749 if (m_move.drop())
750 retv += "*";
751 else if (m_ref.m_board[m_move.to])
752 retv += "x";
753 else
754 retv += "-";
755 retv += QString::number(m_ref.m_board.getSize().x-m_move.to.x);
756 retv += QString(m_move.to.y+'a');
757 if (!p.promoted() && !m_move.drop() &&
758 ShogiPosition::promotionZone(m_ref.turn(), m_move.to)) {
759 if (m_move.m_promote)
760 retv += "+";
761 else
762 retv += "=";
764 return retv;
767 DecoratedMove toDecoratedMove() const {
768 ShogiPiece p = m_move.drop() ? m_move.drop() : m_ref.m_board[m_move.from];
769 bool ambiguous = isAmbiguous();
770 DecoratedMove retv;
771 if(p.type() == ShogiPiece::KING)
772 retv.push_back(MovePart(p.color() == ShogiPiece::BLACK?"king1":"king2", MovePart::Figurine));
773 else
774 retv.push_back(MovePart((p.promoted() ? "p_" : "") + ShogiPiece::typeName(p.type()), MovePart::Figurine));
775 if (ambiguous) {
776 retv.push_back(MovePart(QString::number(m_ref.m_board.getSize().x-m_move.from.x)));
777 retv.push_back(MovePart("num_"+QString::number(m_move.from.y+1), MovePart::Figurine));
779 QString mmm;
780 if (m_move.drop())
781 mmm += "*";
782 else if (m_ref.m_board[m_move.to])
783 mmm += "x";
784 else
785 mmm += "-";
786 mmm += QString::number(m_ref.m_board.getSize().x-m_move.to.x);
787 retv.push_back(mmm);
788 retv.push_back(MovePart("num_"+QString::number(m_move.to.y+1), MovePart::Figurine));
789 if (!p.promoted() && !m_move.drop() &&
790 ShogiPosition::promotionZone(m_ref.turn(), m_move.to)) {
791 if (m_move.m_promote)
792 retv.push_back(MovePart("+"));
793 else
794 retv.push_back(MovePart("="));
796 return retv;
801 template <>
802 struct MoveFactory<ShogiVariantInfo> {
803 static ShogiMove createNormalMove(const NormalUserMove& move) {
804 return ShogiMove(move.from, move.to, move.promotionType >= 0);
806 static ShogiMove createDropMove(const DropUserMove& move) {
807 return ShogiMove(move.m_pool, move.m_piece_index, move.m_to);
810 static NormalUserMove toNormal(const ShogiMove& move) {
811 return NormalUserMove(move.from, move.to);