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.
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"
41 typedef bool PromotionType
;
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
;
62 return m_color
< p
.m_color
;
64 return m_promoted
< p
.m_promoted
;
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 {
76 return (*this) == (*p
);
84 bool operator==(const ShogiPiece
& p
) const {
85 return m_promoted
== p
.m_promoted
&&
86 m_color
== p
.m_color
&&
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
)
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_";
119 res
+= typeName(m_type
);
123 QString
ShogiPiece::typeName(ShogiPiece::Type t
) {
146 ShogiPiece::Type
ShogiPiece::getType(const QString
&) {
147 return KING
; // FIXME
150 QString
ShogiPiece::typeSymbol(ShogiPiece::Type t
) {
173 // ------------------------------
182 template<typename T
> friend class MoveSerializer
;
188 ShogiMove(const Point
& from
, const Point
& to
, bool promote
);
189 ShogiMove(int pool
, int pool_index
, const Point
& to
);
191 QString
toString(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()
208 , from(Point::invalid())
209 , to(Point::invalid()) { }
211 ShogiMove::ShogiMove(const Point
& from
, const Point
& to
, bool promote
)
218 ShogiMove::ShogiMove(int pool
, int pool_index
, const Point
& to
)
220 , m_pool_index(pool_index
)
222 , from(Point::invalid())
225 QString
ShogiMove::toString(int) const {
229 bool ShogiMove::operator==(const ShogiMove
& other
) const {
231 return m_drop
== other
.m_drop
234 return m_promote
== other
.m_promote
236 && from
== other
.from
;
239 // ------------------------------
241 class ShogiPosition
{
243 typedef ShogiPiece Piece
;
244 typedef ShogiMove Move
;
246 typedef PoolReference
<ShogiPosition
> PoolReference
;
247 typedef PoolConstReference
<ShogiPosition
> PoolConstReference
;
248 typedef PoolReference::Pool Pool
;
249 typedef PoolReference::PlayerPool PlayerPool
;
255 template<typename T
> friend class MoveSerializer
;
257 ShogiPosition(const ShogiPosition
&);
258 ShogiPosition(Piece::Color turn
, bool wk
, bool wq
,
259 bool bk
, bool bq
, const Point
& ep
);
260 ShogiPosition(const QList
<boost::shared_ptr
<BaseOpt
> >& opts
);
261 virtual ShogiPosition
* clone() const { return new ShogiPosition(*this); }
262 virtual ~ShogiPosition() { }
264 virtual void setup();
266 bool testMove(Move
&) const;
267 bool pseudolegal(Move
& m
) const;
269 PoolReference
pool(int);
270 PoolConstReference
pool(int) const;
272 PlayerPool
& rawPool(Piece::Color color
) { return m_pool
[color
]; }
273 const PlayerPool
& rawPool(Piece::Color color
) const { return const_cast<Pool
&>(m_pool
)[color
]; }
275 virtual const Point
first() const { return m_board
.first(); }
276 virtual const Point
last() const { return m_board
.last(); }
277 virtual Point
next(const Point
& p
) const { return m_board
.next(p
); }
278 inline bool valid(const Point
& p
) const { return m_board
.valid(p
); }
280 ShogiPiece
get(const Point
& p
) const;
281 void set(const Point
& p
, const Piece
& piece
);
283 ShogiPiece
operator[](const Point
& p
) const { return m_board
[p
]; }
285 Piece::Color
turn() const { return m_turn
; }
286 void setTurn(Piece::Color turn
) { m_turn
= turn
; }
287 Piece::Color
previousTurn() const { return Piece::oppositeColor(m_turn
); }
288 void switchTurn() { m_turn
= Piece::oppositeColor(m_turn
); }
290 InteractionType
movable(const TurnTest
& test
, const Point
& p
) const {
291 if (!valid(p
) || !m_board
[p
] || !test(m_board
[p
].color()))
293 return m_board
[p
].color() == m_turn
? Moving
: Premoving
;
295 InteractionType
droppable(const TurnTest
& test
, int p
) const {
298 ShogiPiece::Color c
= static_cast<ShogiPiece::Color
>(p
);
299 return c
== m_turn
? Moving
: Premoving
;
301 void move(const ShogiMove
& m
);
303 void fromFEN(const QString
&, bool& ok
) { ok
= false; }
304 QString
fen(int, int) const { return ""; }
305 bool operator==(const ShogiPosition
& p
) const;
307 static Move
getVerboseMove(Piece::Color turn
, const VerboseNotation
& m
);
308 Move
getMove(const AlgebraicNotation
&, bool& ok
) const;
309 boost::shared_ptr
<ShogiPiece
> moveHint(const ShogiMove
& m
) const;
311 Point
size() const { return Point(9,9); }
312 void dump() const { }
314 static bool promotionZone(Piece::Color color
, const Point
& p
);
315 static bool stuckPiece(const Piece
& piece
, const Point
& to
);
316 PathInfo
path(const Point
& from
, const Point
& to
) const { return m_board
.path(from
, to
); }
317 QStringList
borderCoords() const;
320 ShogiPosition::ShogiPosition()
321 : m_turn(ShogiPiece::BLACK
)
324 ShogiPosition::ShogiPosition(const ShogiPosition
& other
)
325 : m_turn(other
.m_turn
)
326 , m_board(other
.m_board
)
327 , m_pool(other
.m_pool
) { }
329 ShogiPosition::ShogiPosition(Piece::Color turn
, bool, bool, bool, bool, const Point
&)
333 ShogiPosition::ShogiPosition(const QList
<boost::shared_ptr
<BaseOpt
> >&)
334 : m_turn(ShogiPiece::BLACK
)
337 QStringList
ShogiPosition::borderCoords() const
340 for(int i
=m_board
.getSize().y
; i
>0; i
--)
341 retv
+= QString::number(i
);
342 retv
<< QChar(0x4e5d) << QChar(0x516b) << QChar(0x4e03) << QChar(0x516d)
343 << QChar(0x4e94) << QChar(0x56db) << QChar(0x4e09) << QChar(0x4e8c) << QChar(0x4e00);
347 bool ShogiPiece::canMove(const ShogiPosition
& pos
,
348 const Point
& from
, const Point
& to
) const {
349 if (!from
.valid()) return false;
350 if (!to
.valid()) return false;
351 if (from
== to
) return false;
352 if (pos
[to
].color() == m_color
) return false;
353 Point delta
= to
- from
;
358 return abs(delta
.x
) <= 1 && abs(delta
.y
) <= 1;
360 return (delta
.x
== 0 && abs(delta
.y
) == 1)
361 || (delta
.y
== 0 && abs(delta
.x
) == 1)
362 || (delta
.y
== direction().y
&& abs(delta
.x
) <= 1);
364 return (abs(delta
.x
) == abs(delta
.y
) && abs(delta
.x
) == 1)
365 || (delta
.y
== direction().y
&& abs(delta
.x
) <= 1);
368 PathInfo path
= pos
.path(from
, to
);
369 return path
.parallel() && path
.clear();
373 PathInfo path
= pos
.path(from
, to
);
374 return path
.diagonal() && path
.clear();
378 return abs(delta
.x
) == 1 && delta
.y
== direction().y
* 2;
382 PathInfo path
= pos
.path(from
, to
);
383 return delta
.x
== 0 && path
.clear() && (delta
.y
* direction().y
> 0);
386 return delta
.x
== 0 && delta
.y
== direction().y
;
397 return (delta
.x
== 0 && abs(delta
.y
) == 1)
398 || (delta
.y
== 0 && abs(delta
.x
) == 1)
399 || (delta
.y
== direction().y
&& abs(delta
.x
) <= 1);
402 if (abs(delta
.x
) <= 1 && abs(delta
.y
) <= 1) return true;
403 PathInfo path
= pos
.path(from
, to
);
404 return path
.parallel() && path
.clear();
408 if (abs(delta
.x
) <= 1 && abs(delta
.y
) <= 1) return true;
409 PathInfo path
= pos
.path(from
, to
);
410 return path
.diagonal() && path
.clear();
419 ShogiPosition::Move
ShogiPosition::getVerboseMove(Piece::Color
, const VerboseNotation
&) {
423 ShogiPosition::Move
ShogiPosition::getMove(const AlgebraicNotation
&, bool& ok
) const {
428 ShogiPiece
ShogiPosition::get(const Point
& p
) const {
429 if (m_board
.valid(p
)) {
437 void ShogiPosition::set(const Point
& p
, const ShogiPiece
& piece
) {
438 if (m_board
.valid(p
)) {
443 ShogiPosition::PoolReference
ShogiPosition::pool(int index
) {
444 ShogiPiece::Color color
= static_cast<ShogiPiece::Color
>(index
);
445 return PoolReference(&m_pool
[color
], color
);
448 ShogiPosition::PoolConstReference
ShogiPosition::pool(int index
) const {
449 ShogiPiece::Color color
= static_cast<ShogiPiece::Color
>(index
);
450 return PoolConstReference(&m_pool
[color
], color
);
453 bool ShogiPosition::operator==(const ShogiPosition
& p
) const {
454 return m_turn
== p
.m_turn
455 && m_board
== p
.m_board
;
458 boost::shared_ptr
<ShogiPiece
> ShogiPosition::moveHint(const ShogiMove
& m
) const {
459 if (m
.drop()) return boost::shared_ptr
<ShogiPiece
>(new ShogiPiece(m
.drop()));
460 else return boost::shared_ptr
<ShogiPiece
>();
463 bool ShogiPosition::promotionZone(Piece::Color color
, const Point
& p
) {
464 return color
== ShogiPiece::WHITE
? p
.y
>= 6 : p
.y
<= 2;
467 #define SET_PIECE(i,j, color, type) m_board[Point(i,j)] = Piece(ShogiPiece::color, ShogiPiece::type)
468 void ShogiPosition::setup() {
469 for (int i
= 0; i
< m_board
.getSize().x
; i
++) {
470 SET_PIECE(i
, 2, WHITE
, PAWN
);
471 SET_PIECE(i
, 6, BLACK
, PAWN
);
474 SET_PIECE(0,0, WHITE
, LANCE
);
475 SET_PIECE(1,0, WHITE
, KNIGHT
);
476 SET_PIECE(2,0, WHITE
, SILVER
);
477 SET_PIECE(3,0, WHITE
, GOLD
);
478 SET_PIECE(4,0, WHITE
, KING
);
479 SET_PIECE(5,0, WHITE
, GOLD
);
480 SET_PIECE(6,0, WHITE
, SILVER
);
481 SET_PIECE(7,0, WHITE
, KNIGHT
);
482 SET_PIECE(8,0, WHITE
, LANCE
);
483 SET_PIECE(1,1, WHITE
, ROOK
);
484 SET_PIECE(7,1, WHITE
, BISHOP
);
486 SET_PIECE(0,8, BLACK
, LANCE
);
487 SET_PIECE(1,8, BLACK
, KNIGHT
);
488 SET_PIECE(2,8, BLACK
, SILVER
);
489 SET_PIECE(3,8, BLACK
, GOLD
);
490 SET_PIECE(4,8, BLACK
, KING
);
491 SET_PIECE(5,8, BLACK
, GOLD
);
492 SET_PIECE(6,8, BLACK
, SILVER
);
493 SET_PIECE(7,8, BLACK
, KNIGHT
);
494 SET_PIECE(8,8, BLACK
, LANCE
);
495 SET_PIECE(1,7, BLACK
, BISHOP
);
496 SET_PIECE(7,7, BLACK
, ROOK
);
499 m_turn
= ShogiPiece::BLACK
;
503 bool ShogiPosition::testMove(Move
& m
) const {
507 ShogiPosition
tmp(*this);
510 // find king position
511 Point king_pos
= Point::invalid();
512 ShogiPiece
king(m_turn
, ShogiPiece::KING
);
513 for (Point i
= tmp
.m_board
.first(); i
<= tmp
.m_board
.last(); i
= tmp
.m_board
.next(i
)) {
514 if (ShogiPiece p
= tmp
[i
])
520 if (!king_pos
.valid()) return false;
522 // check if the king can be captured
523 for (Point i
= tmp
.m_board
.first(); i
<= tmp
.m_board
.last(); i
= tmp
.m_board
.next(i
)) {
524 if (ShogiPiece p
= tmp
[i
])
525 if (p
.color() == tmp
.turn() && p
.canMove(tmp
, i
, king_pos
)) return false;
531 bool ShogiPosition::stuckPiece(const ShogiPiece
& piece
, const Point
& p
) {
532 if (piece
.type() == Piece::PAWN
) {
533 if (p
.y
== (piece
.color() == Piece::WHITE
? 8 : 0))
536 else if (piece
.type() == Piece::KNIGHT
) {
537 if (piece
.color() == Piece::WHITE
) {
549 bool ShogiPosition::pseudolegal(Move
& m
) const {
550 if (!m
.drop() && m
.pool() != -1 && m
.poolIndex() != -1) {
551 m
.setDrop(pool(m
.pool()).get(m
.poolIndex()));
554 if (ShogiPiece dropped
= m
.drop()) {
555 if (m_board
[m
.to
]) return false;
556 if (stuckPiece(dropped
, m
.to
)) return false;
557 if (dropped
.type() == Piece::PAWN
) {
558 for (int i
= 0; i
< m_board
.getSize().y
; i
++)
559 if (ShogiPiece other
= m_board
[Point(m
.to
.x
, i
)])
560 if (other
.color() == m_turn
&& other
.type() == Piece::PAWN
&& !other
.promoted()) return false;
565 const Piece
& p
= m_board
[m
.from
];
566 return p
&& p
.canMove(*this, m
.from
, m
.to
);
570 void ShogiPosition::move(const ShogiMove
& m
) {
571 if (Piece dropped
= m
.drop()) {
572 m_board
[m
.to
] = dropped
;
573 if (!--rawPool(dropped
.color())[dropped
.type()])
574 rawPool(dropped
.color()).erase(dropped
.type());
577 if (Piece captured
= m_board
[m
.to
]) {
578 rawPool(Piece::oppositeColor(captured
.color()))[captured
.type()]++;
581 m_board
[m
.to
] = m_board
[m
.from
];
582 m_board
[m
.from
] = Piece();
585 if (promotionZone(m_turn
, m
.to
) || promotionZone(m_turn
, m
.from
)) {
586 if (m
.promote() || stuckPiece(m_board
[m
.to
], m
.to
)) {
587 Piece::Type type
= m_board
[m
.to
].type();
588 if (type
!= ShogiPiece::KING
&& type
!= ShogiPiece::GOLD
)
589 m_board
[m
.to
].promote();
596 class ShogiAnimatorBase
;
598 class ShogiVariantInfo
{
600 static QStringList
getNumbers() {
601 return QStringList() << QChar(0x4e5d) << QChar(0x516b) << QChar(0x4e03)
602 << QChar(0x516d) << QChar(0x4e94) << QChar(0x56db)
603 << QChar(0x4e09) << QChar(0x4e8c) << QChar(0x4e00);
606 typedef ShogiPosition Position
;
607 typedef Position::Move Move
;
608 typedef Position::Piece Piece
;
609 typedef DropAnimatorMixin
<ShogiAnimatorBase
> Animator
;
612 static const bool hasICS
= false;
613 static const bool m_simple_moves
= false;
614 static void forallPieces(PieceFunction
& f
);
615 static int moveListLayout() { return 0; }
616 static OptList
positionOptions() { return OptList(); }
617 static const char *m_name
;
618 static const char *m_theme_proxy
;
621 const char *ShogiVariantInfo::m_name
= "Shogi_OLD";
622 const char *ShogiVariantInfo::m_theme_proxy
= "Shogi";
625 void ShogiVariantInfo::forallPieces(PieceFunction
& f
) {
626 ChessVariant::forallPieces(f
);
629 VariantInfo
* ShogiVariant::static_shogi_variant
= 0;
631 VariantInfo
* ShogiVariant::info() {
632 if (!static_shogi_variant
)
633 static_shogi_variant
= new WrappedVariantInfo
<ShogiVariantInfo
>;
634 return static_shogi_variant
;
637 class ShogiAnimatorBase
: public BaseAnimator
<ShogiVariantInfo
> {
639 typedef ShogiVariantInfo Variant
;
641 typedef BaseAnimator
<ShogiVariantInfo
> Base
;
642 typedef Base::API API
;
644 ShogiAnimatorBase(API cinterface
)
645 : Base(cinterface
) { }
647 virtual AnimationGroupPtr
forward(const ShogiPosition
& final
, const ShogiMove
& move
) {
648 AnimationFactory
res(m_cinterface
->inner());
650 NamedSprite piece
= m_cinterface
->takeSprite(move
.from
);
651 NamedSprite captured
= m_cinterface
->takeSprite(move
.to
);
652 m_cinterface
->setSprite(move
.to
, piece
);
655 res
.addPreAnimation(Animate::move(piece
, move
.to
));
658 res
.addPostAnimation(Animate::destroy(captured
));
660 if (final
.get(move
.to
) != m_cinterface
->position()->get(move
.from
)) {
661 Piece promoted
= final
.get(move
.to
);
664 QPoint real
= m_cinterface
->converter()->toReal(move
.to
);
665 NamedSprite old_sprite
= m_cinterface
->getSprite(move
.to
);
666 NamedSprite new_sprite
= m_cinterface
->setPiece(move
.to
, promoted
, false);
668 res
.addPostAnimation(Animate::morph(old_sprite
, new_sprite
));
675 virtual AnimationGroupPtr
back(const ShogiPosition
& final
, const ShogiMove
& move
) {
676 AnimationFactory
res(m_cinterface
->inner());
678 NamedSprite piece
= m_cinterface
->takeSprite(move
.to
);
679 NamedSprite captured
;
680 if (Piece captured_piece
= final
.get(move
.to
)) {
681 captured
= m_cinterface
->setPiece(move
.to
, captured_piece
, false);
682 res
.addPreAnimation(Animate::appear(captured
));
686 piece
= m_cinterface
->createPiece(move
.to
, final
.get(move
.from
), false);
687 res
.addPreAnimation(Animate::appear(piece
));
690 m_cinterface
->setSprite(move
.from
, piece
);
692 if (final
.get(move
.from
) != m_cinterface
->position()->get(move
.to
)) {
693 Piece old_piece
= final
.get(move
.from
);
695 NamedSprite old
= m_cinterface
->createPiece(move
.to
, old_piece
, false);
696 res
.addPreAnimation(Animate::morph(piece
, old
));
698 // replace piece with pawn
699 m_cinterface
->setSprite(move
.from
, old
);
704 res
.addPreAnimation(Animate::move(piece
, move
.from
));
712 class MoveSerializer
<ShogiPosition
> {
713 const ShogiMove
& m_move
;
714 const ShogiPosition
& m_ref
;
715 bool isAmbiguous() const {
716 ShogiPiece p
= m_move
.drop() ? m_move
.drop() : m_ref
.m_board
[m_move
.from
];
717 bool ambiguous
= false;
719 for (Point i
= m_ref
.m_board
.first(); i
<= m_ref
.m_board
.last(); i
= m_ref
.m_board
.next(i
) ) {
720 if (i
==m_move
.from
|| m_ref
.m_board
[i
] != p
)
722 ShogiMove
mv(i
, m_move
.to
, false);
723 if (m_ref
.testMove(mv
)) {
731 MoveSerializer(const ShogiMove
& m
, const ShogiPosition
& r
)
732 : m_move(m
), m_ref(r
) { }
734 QString
SAN() const {
735 ShogiPiece p
= m_move
.drop() ? m_move
.drop() : m_ref
.m_board
[m_move
.from
];
736 bool ambiguous
= isAmbiguous();
740 retv
+= ShogiPiece::typeSymbol(p
.type());
742 retv
+= QString::number(m_ref
.m_board
.getSize().x
-m_move
.from
.x
);
743 retv
+= QString(m_move
.from
.y
+'a');
747 else if (m_ref
.m_board
[m_move
.to
])
751 retv
+= QString::number(m_ref
.m_board
.getSize().x
-m_move
.to
.x
);
752 retv
+= QString(m_move
.to
.y
+'a');
753 if (!p
.promoted() && !m_move
.drop() &&
754 ShogiPosition::promotionZone(m_ref
.turn(), m_move
.to
)) {
755 if (m_move
.m_promote
)
763 DecoratedMove
toDecoratedMove() const {
764 ShogiPiece p
= m_move
.drop() ? m_move
.drop() : m_ref
.m_board
[m_move
.from
];
765 bool ambiguous
= isAmbiguous();
767 if(p
.type() == ShogiPiece::KING
)
768 retv
.push_back(MovePart(p
.color() == ShogiPiece::BLACK
?"king1":"king2", MovePart::Figurine
));
770 retv
.push_back(MovePart((p
.promoted() ? "p_" : "") + ShogiPiece::typeName(p
.type()), MovePart::Figurine
));
772 retv
.push_back(MovePart(QString::number(m_ref
.m_board
.getSize().x
-m_move
.from
.x
)));
773 retv
.push_back(MovePart("num_"+QString::number(m_move
.from
.y
+1), MovePart::Figurine
));
778 else if (m_ref
.m_board
[m_move
.to
])
782 mmm
+= QString::number(m_ref
.m_board
.getSize().x
-m_move
.to
.x
);
784 retv
.push_back(MovePart("num_"+QString::number(m_move
.to
.y
+1), MovePart::Figurine
));
785 if (!p
.promoted() && !m_move
.drop() &&
786 ShogiPosition::promotionZone(m_ref
.turn(), m_move
.to
)) {
787 if (m_move
.m_promote
)
788 retv
.push_back(MovePart("+"));
790 retv
.push_back(MovePart("="));
798 struct MoveFactory
<ShogiVariantInfo
> {
799 static ShogiMove
createNormalMove(const NormalUserMove
& move
) {
800 return ShogiMove(move
.from
, move
.to
, move
.promotionType
>= 0);
802 static ShogiMove
createDropMove(const DropUserMove
& move
) {
803 return ShogiMove(move
.m_pool
, move
.m_piece_index
, move
.m_to
);
806 static NormalUserMove
toNormal(const ShogiMove
& move
) {
807 return NormalUserMove(move
.from
, move
.to
);