2 #include "xchess/animator.impl.h"
3 #include "xchess/piece.h"
4 #include "xchess/move.h"
6 #include "moveserializer.impl.h"
7 #include "crazyhouse_p.h"
26 typedef bool PromotionType
;
33 : m_color(INVALID_COLOR
)
34 , m_type(INVALID_TYPE
)
35 , m_promoted(false) { }
36 XiangQiPiece(XiangQiPiece::Color color
, XiangQiPiece::Type type
, bool promoted
= false);
37 XiangQiPiece(const XiangQiPiece
& other
);
39 bool inPalace(const Point
& p
) const;
41 void promote() { m_promoted
= true; }
42 bool promoted() { return m_promoted
; }
44 bool operator<(const XiangQiPiece
& p
) const {
45 if (m_promoted
== p
.m_promoted
)
46 if (m_color
== p
.m_color
)
47 return m_type
< p
.m_type
;
49 return m_color
< p
.m_color
;
51 return m_promoted
< p
.m_promoted
;
55 static QString
typeName(XiangQiPiece::Type t
);
56 bool valid() const { return m_color
!= INVALID_COLOR
&& m_type
!= INVALID_TYPE
; }
57 operator bool() const { return valid(); }
58 bool operator!() const { return !valid(); }
60 bool equals(const XiangQiPiece
* p
) const {
63 return (*this) == (*p
);
71 bool operator==(const XiangQiPiece
& p
) const {
72 return m_promoted
== p
.m_promoted
&&
73 m_color
== p
.m_color
&&
77 bool operator!=(const XiangQiPiece
& p
) const {
78 return !(operator==(p
));
81 static Type
getType(const QString
& t
);
82 static QString
typeSymbol(XiangQiPiece::Type t
);
84 bool canMove(const class XiangQiPosition
&, const Point
&, const Point
&) const;
85 Color
color() const { return m_color
; }
86 Type
type() const { return m_type
; }
88 static Color
oppositeColor(Color c
) { return c
== RED
? BLACK
: BLACK
? RED
: INVALID_COLOR
; }
89 Point
direction() const { return Point(0, m_color
== RED
? -1 : 1); }
92 XiangQiPiece::XiangQiPiece(XiangQiPiece::Color color
, XiangQiPiece::Type type
, bool promoted
)
95 , m_promoted(promoted
) { }
97 XiangQiPiece::XiangQiPiece(const XiangQiPiece
& other
)
98 : m_color(other
.m_color
)
99 , m_type(other
.m_type
)
100 , m_promoted(other
.m_promoted
) { }
102 bool XiangQiPiece::inPalace(const Point
& p
) const {
104 return p
.x
> 2 && p
.x
< 6 && p
.y
> 6;
106 return p
.x
> 2 && p
.x
< 6 && p
.y
< 3;
109 QString
XiangQiPiece::name() const {
110 QString res
= m_color
== RED
? "red_" : "black_";
113 res
+= typeName(m_type
);
117 QString
XiangQiPiece::typeName(XiangQiPiece::Type t
) {
138 XiangQiPiece::Type
XiangQiPiece::getType(const QString
&) {
139 return GENERAL
; // FIXME
142 QString
XiangQiPiece::typeSymbol(XiangQiPiece::Type t
) {
163 // ------------------------------
166 XiangQiPiece m_dropped
;
168 template<typename T
> friend class MoveSerializer
;
174 XiangQiMove(const Point
& from
, const Point
& to
, bool promote
);
175 XiangQiMove(const XiangQiPiece
& piece
, const Point
& to
);
177 static XiangQiMove
createDropMove(const XiangQiPiece
& piece
, const Point
& to
);
178 QString
toString(int) const;
180 bool operator==(const XiangQiMove
& other
) const;
182 const XiangQiPiece
& dropped() const { return m_dropped
; }
183 bool promote() const { return m_promote
; }
184 bool valid() const { return to
.valid(); }
187 XiangQiMove::XiangQiMove()
189 , from(Point::invalid())
190 , to(Point::invalid()) { }
192 XiangQiMove::XiangQiMove(const Point
& from
, const Point
& to
, bool promote
)
197 XiangQiMove::XiangQiMove(const XiangQiPiece
& piece
, const Point
& to
)
200 , from(Point::invalid())
203 XiangQiMove
XiangQiMove::createDropMove(const XiangQiPiece
& piece
, const Point
& to
) {
204 return XiangQiMove(piece
, to
);
207 QString
XiangQiMove::toString(int) const {
211 bool XiangQiMove::operator==(const XiangQiMove
& other
) const {
213 return m_dropped
== other
.m_dropped
216 return m_promote
== other
.m_promote
218 && from
== other
.from
;
221 // ------------------------------
223 class XiangQiPosition
{
225 typedef XiangQiPiece Piece
;
226 typedef XiangQiMove Move
;
227 typedef std::map
<XiangQiPiece
, int> Pool
;
233 template<typename T
> friend class MoveSerializer
;
235 XiangQiPosition(const XiangQiPosition
&);
236 XiangQiPosition(Piece::Color turn
, bool wk
, bool wq
,
237 bool bk
, bool bq
, const Point
& ep
);
238 XiangQiPosition(const QList
<boost::shared_ptr
<BaseOpt
> >& opts
);
239 virtual XiangQiPosition
* clone() const { return new XiangQiPosition(*this); }
240 virtual ~XiangQiPosition() { }
242 virtual void setup();
244 bool testMove(Move
&) const;
245 bool pseudolegal(Move
& m
) const;
247 virtual void addToPool(const Piece
&, int) { }
248 virtual void removeFromPool(const Piece
&, int) { }
249 Pool
& pool() { return m_pool
; }
250 const Pool
& pool() const { return m_pool
; }
252 const XiangQiPiece
* get(const Point
& p
) const;
253 XiangQiPiece
* get(const Point
& p
);
254 void set(const Point
& p
, Piece
* piece
);
256 XiangQiPiece
operator[](const Point
& p
) const { return m_board
[p
]; }
258 Piece::Color
turn() const { return m_turn
; }
259 void setTurn(Piece::Color turn
) { m_turn
= turn
; }
260 Piece::Color
previousTurn() const { return Piece::oppositeColor(m_turn
); }
261 void switchTurn() { m_turn
= Piece::oppositeColor(m_turn
); }
263 void move(const XiangQiMove
& m
);
265 void fromFEN(const QString
&, bool& ok
) { ok
= false; }
266 QString
fen(int, int) const { return ""; }
267 bool operator==(const XiangQiPosition
& p
) const;
269 static Move
getVerboseMove(Piece::Color turn
, const VerboseNotation
& m
);
270 Move
getMove(const AlgebraicNotation
&, bool& ok
) const;
271 boost::shared_ptr
<XiangQiPiece
> moveHint(const XiangQiMove
& m
) const;
273 Point
size() const { return Point(9,10); }
274 void dump() const { }
276 PathInfo
path(const Point
& from
, const Point
& to
) const { return m_board
.path(from
, to
); }
278 QStringList
borderCoords() const;
281 XiangQiPosition::XiangQiPosition()
282 : m_turn(XiangQiPiece::BLACK
)
285 XiangQiPosition::XiangQiPosition(const XiangQiPosition
& other
)
286 : m_turn(other
.m_turn
)
287 , m_board(other
.m_board
)
288 , m_pool(other
.m_pool
) { }
290 XiangQiPosition::XiangQiPosition(Piece::Color turn
, bool, bool, bool, bool, const Point
&)
294 XiangQiPosition::XiangQiPosition(const QList
<boost::shared_ptr
<BaseOpt
> >&)
295 : m_turn(XiangQiPiece::BLACK
)
298 QStringList
XiangQiPosition::borderCoords() const
301 for(int i
=1; i
<=9; i
++)
302 retv
+= QString::number(i
);
303 for(int i
=0; i
<10; i
++)
305 retv
<< QChar(0x4e5d) << QChar(0x516b) << QChar(0x4e03) << QChar(0x516d)
306 << QChar(0x4e94) << QChar(0x56db) << QChar(0x4e09) << QChar(0x4e8c) << QChar(0x4e00);
307 for(int i
=0; i
<10; i
++)
312 bool XiangQiPiece::canMove(const XiangQiPosition
& pos
,
313 const Point
& from
, const Point
& to
) const {
314 if (!from
.valid()) return false;
315 if (!to
.valid()) return false;
316 if (from
== to
) return false;
317 if (pos
[to
].color() == m_color
) return false;
318 Point delta
= to
- from
;
322 return (abs(delta
.x
) + abs(delta
.y
) == 1)
325 return (abs(delta
.x
) == 1) && (abs(delta
.y
) == 1)
328 return (abs(delta
.x
) == 2) && (abs(delta
.y
) == 2)
329 && !pos
[Point((to
.x
+from
.x
)/2, (to
.y
+from
.y
)/2)]
330 && (m_color
== RED
? to
.y
> 4 : to
.y
< 5);
332 return (delta
.x
*delta
.x
+ delta
.y
*delta
.y
) == 5
333 && !pos
[Point((to
.x
+from
.x
*2+1)/3, (to
.y
+from
.y
*2+1)/3)];
336 PathInfo path
= pos
.path(from
, to
);
337 return path
.parallel() && path
.clear();
341 PathInfo path
= pos
.path(from
, to
);
342 return path
.parallel() &&
343 (pos
[to
] ? path
.numObstacles() == 1 : path
.clear());
346 return (delta
.x
== 0 && delta
.y
== direction().y
)
347 || (abs(delta
.x
) == 1 && delta
.y
== 0 &&
348 (m_color
== RED
? to
.y
< 5 : to
.y
> 4));
355 XiangQiPosition::Move
XiangQiPosition::getVerboseMove(Piece::Color
, const VerboseNotation
&) {
359 XiangQiPosition::Move
XiangQiPosition::getMove(const AlgebraicNotation
&, bool& ok
) const {
364 const XiangQiPiece
* XiangQiPosition::get(const Point
& p
) const {
365 return m_board
.valid(p
) && m_board
[p
] ? &m_board
[p
] : 0;
368 XiangQiPiece
* XiangQiPosition::get(const Point
& p
) {
369 return m_board
.valid(p
) && m_board
[p
] ? &m_board
[p
] : 0;
372 void XiangQiPosition::set(const Point
& p
, XiangQiPiece
* piece
) {
373 if (!m_board
.valid(p
)) return;
377 m_board
[p
] = Piece();
380 bool XiangQiPosition::operator==(const XiangQiPosition
& p
) const {
381 return m_turn
== p
.m_turn
382 && m_board
== p
.m_board
;
385 boost::shared_ptr
<XiangQiPiece
> XiangQiPosition::moveHint(const XiangQiMove
& m
) const {
386 if (m
.dropped()) return boost::shared_ptr
<XiangQiPiece
>(new XiangQiPiece(m
.dropped()));
387 else return boost::shared_ptr
<XiangQiPiece
>();
390 #define SET_PIECE(i,j, color, type) m_board[Point(i,j)] = Piece(XiangQiPiece::color, XiangQiPiece::type)
391 void XiangQiPosition::setup() {
392 SET_PIECE(0,0, BLACK
, CHARIOT
);
393 SET_PIECE(1,0, BLACK
, HORSE
);
394 SET_PIECE(2,0, BLACK
, ELEPHANT
);
395 SET_PIECE(3,0, BLACK
, ADVISOR
);
396 SET_PIECE(4,0, BLACK
, GENERAL
);
397 SET_PIECE(5,0, BLACK
, ADVISOR
);
398 SET_PIECE(6,0, BLACK
, ELEPHANT
);
399 SET_PIECE(7,0, BLACK
, HORSE
);
400 SET_PIECE(8,0, BLACK
, CHARIOT
);
401 SET_PIECE(1,2, BLACK
, CANNON
);
402 SET_PIECE(7,2, BLACK
, CANNON
);
403 for(int i
=0;i
<=8;i
+=2)
404 SET_PIECE(i
, 3, BLACK
, SOLDIER
);
406 SET_PIECE(0,9, RED
, CHARIOT
);
407 SET_PIECE(1,9, RED
, HORSE
);
408 SET_PIECE(2,9, RED
, ELEPHANT
);
409 SET_PIECE(3,9, RED
, ADVISOR
);
410 SET_PIECE(4,9, RED
, GENERAL
);
411 SET_PIECE(5,9, RED
, ADVISOR
);
412 SET_PIECE(6,9, RED
, ELEPHANT
);
413 SET_PIECE(7,9, RED
, HORSE
);
414 SET_PIECE(8,9, RED
, CHARIOT
);
415 SET_PIECE(1,7, RED
, CANNON
);
416 SET_PIECE(7,7, RED
, CANNON
);
417 for(int i
=0;i
<=8;i
+=2)
418 SET_PIECE(i
, 6, RED
, SOLDIER
);
420 m_turn
= XiangQiPiece::RED
;
424 bool XiangQiPosition::testMove(Move
& m
) const {
425 return pseudolegal(m
);
428 bool XiangQiPosition::pseudolegal(Move
& m
) const {
429 const Piece
& p
= m_board
[m
.from
];
430 return p
.canMove(*this, m
.from
, m
.to
);
433 void XiangQiPosition::move(const XiangQiMove
& m
) {
434 if (Piece captured
= m_board
[m
.to
]) {
435 addToPool(Piece(Piece::oppositeColor(captured
.color()),
436 captured
.type(), false), 1);
439 m_board
[m
.to
] = m_board
[m
.from
];
440 m_board
[m
.from
] = Piece();
446 class MoveSerializer
<XiangQiPosition
> {
447 const XiangQiMove
& m_move
;
448 const XiangQiPosition
& m_ref
;
450 MoveSerializer(const XiangQiMove
& m
, const XiangQiPosition
& r
)
451 : m_move(m
), m_ref(r
) { }
452 QString
SAN() const {
453 XiangQiPiece p
= m_ref
[m_move
.from
];
456 for(int i
=0;i
<10;i
++) {
457 Point
f(m_move
.from
.x
, i
);
458 Point
t(m_move
.to
-m_move
.from
+f
);
459 if(f
!= m_move
.from
&& m_ref
[f
] == p
&& m_ref
.m_board
.valid(t
)) {
460 XiangQiMove
m(f
, m_move
.to
-m_move
.from
+f
, false);
461 if(m_ref
.testMove(m
)) {
462 order
= ((i
< m_move
.to
.y
) != (p
.color() == XiangQiPiece::RED
)) ? -1 : 1;
469 if(num
>= 4 && (order
== 0 || order
== num
-1)) //4/5 pawns case
470 retv
+= (order
==0) ? "-" : "+";
472 retv
+= XiangQiPiece::typeSymbol(p
.type());
474 if(num
==1 || (num
==3 && order
==1) || (num
==5 && order
==2))
475 retv
+= QString::number((p
.color() == XiangQiPiece::RED
) ? 9-m_move
.from
.x
: m_move
.from
.x
+1);
477 retv
+= (order
<num
/2) ? "-" : "+";
479 if(m_move
.from
.x
== m_move
.to
.x
) {
480 retv
+= ((m_move
.to
.y
>m_move
.from
.y
) != (p
.color() == XiangQiPiece::RED
)) ? "+" : "-";
481 retv
+= QString::number(abs(m_move
.to
.y
-m_move
.from
.y
));
484 retv
+= (m_move
.to
.y
== m_move
.from
.y
) ? "." :
485 ((m_move
.to
.y
>m_move
.from
.y
) != (p
.color() == XiangQiPiece::RED
)) ? "+" : "-";
486 retv
+= QString::number((p
.color() == XiangQiPiece::RED
) ? 9-m_move
.to
.x
: m_move
.to
.x
+1);
491 DecoratedMove
toDecoratedMove() const {
492 XiangQiPiece p
= m_ref
[m_move
.from
];
495 for(int i
=0;i
<10;i
++) {
496 Point
f(m_move
.from
.x
, i
);
497 Point
t(m_move
.to
-m_move
.from
+f
);
498 if(f
!= m_move
.from
&& m_ref
[f
] == p
&& m_ref
.m_board
.valid(t
)) {
499 XiangQiMove
m(f
, m_move
.to
-m_move
.from
+f
, false);
500 if(m_ref
.testMove(m
)) {
501 order
= ((i
< m_move
.to
.y
) != (p
.color() == XiangQiPiece::RED
)) ? -1 : 1;
508 MovePart piece
= QString();
510 std::cout
<< "num = " << num
<< " order = " << order
<< std::endl
;
511 if(num
>= 4 && (order
== 0 || order
== num
-1)) //4/5 pawns case
512 piece
= MovePart((order
==0) ? "front" : "rear", MovePart::Figurine
);
514 piece
= MovePart(p
.name(), MovePart::Figurine
);
516 if(num
==1 || (num
==3 && order
==1) || (num
==5 && order
==2)) {
518 retv
+= MovePart(((p
.color() == XiangQiPiece::RED
) ? "rn_" : "bn_")
519 + QString::number((p
.color() == XiangQiPiece::RED
) ?
520 9-m_move
.from
.x
: m_move
.from
.x
+1),
524 retv
+= MovePart((order
<num
/2) ? "front" : "rear", MovePart::Figurine
);
528 if(m_move
.from
.x
== m_move
.to
.x
) {
529 retv
+= MovePart(((m_move
.to
.y
>m_move
.from
.y
) != (p
.color() == XiangQiPiece::RED
))
530 ? "advances" : "retreats", MovePart::Figurine
);
531 retv
+= MovePart(((p
.color() == XiangQiPiece::RED
) ? "rn_" : "bn_")
532 + QString::number(abs(m_move
.to
.y
-m_move
.from
.y
)), MovePart::Figurine
);
535 retv
+= MovePart((m_move
.to
.y
== m_move
.from
.y
) ? "traverses" :
536 ((m_move
.to
.y
>m_move
.from
.y
) != (p
.color() == XiangQiPiece::RED
)) ? "advances" :
537 "retreats", MovePart::Figurine
);
538 retv
+= MovePart(((p
.color() == XiangQiPiece::RED
) ? "rn_" : "bn_")
539 + QString::number((p
.color() == XiangQiPiece::RED
) ? 9-m_move
.to
.x
: m_move
.to
.x
+1),
547 class XiangQiAnimator
: protected CrazyhouseAnimator
{
549 typedef boost::shared_ptr
<AnimationGroup
> AnimationPtr
;
550 virtual boost::shared_ptr
<MovementAnimation
>
551 createMovementAnimation(const Element
& element
, const QPoint
& destination
);
553 XiangQiAnimator(PointConverter
* converter
, GraphicalPosition
* position
);
554 virtual ~XiangQiAnimator(){}
555 virtual AnimationPtr
warp(AbstractPosition::Ptr
);
556 virtual AnimationPtr
forward(AbstractPosition::Ptr
, const XiangQiMove
& move
);
557 virtual AnimationPtr
back(AbstractPosition::Ptr
, const XiangQiMove
& move
);
560 boost::shared_ptr
<MovementAnimation
>
561 XiangQiAnimator::createMovementAnimation(const Element
& element
, const QPoint
& destination
) {
562 if (element
.piece()->type() == static_cast<int>(XiangQiPiece::HORSE
))
563 return boost::shared_ptr
<MovementAnimation
>(new KnightMovementAnimation(element
.sprite(),
564 destination
, m_anim_rotate
, 1.0));
566 return boost::shared_ptr
<MovementAnimation
>(new MovementAnimation(element
.sprite(),
570 XiangQiAnimator::XiangQiAnimator(PointConverter
* converter
, GraphicalPosition
* position
)
571 : CrazyhouseAnimator(converter
, position
) { }
573 XiangQiAnimator::AnimationPtr
XiangQiAnimator::warp(AbstractPosition::Ptr pos
) {
574 return CrazyhouseAnimator::warp(pos
);
577 XiangQiAnimator::AnimationPtr
XiangQiAnimator::forward(AbstractPosition::Ptr pos
, const XiangQiMove
& move
) {
579 return CrazyhouseAnimator::forward(pos
, CrazyhouseMove(CrazyhousePiece(WHITE
, KING
), move
.to
));
581 return CrazyhouseAnimator::forward(pos
, CrazyhouseMove(move
.from
, move
.to
));
584 XiangQiAnimator::AnimationPtr
XiangQiAnimator::back(AbstractPosition::Ptr pos
, const XiangQiMove
& move
) {
586 return CrazyhouseAnimator::back(pos
, CrazyhouseMove(CrazyhousePiece(WHITE
, KING
), move
.to
));
588 return CrazyhouseAnimator::back(pos
, CrazyhouseMove(move
.from
, move
.to
));
593 class XiangQiVariantInfo
{
595 typedef XiangQiPosition Position
;
596 typedef Position::Move Move
;
597 typedef Position::Piece Piece
;
598 typedef SimpleAnimator
<XiangQiVariantInfo
> Animator
;
599 static const bool m_simple_moves
= false;
600 static void forallPieces(PieceFunction
& f
);
601 static QStringList
borderCoords(){
602 return QStringList() << "i" << "h" << "g" << "f" << "e" << "d" << "c" << "b" << "a"
603 << "10" << "9" << "8" << "7" << "6" << "5" << "4" << "3" << "2" << "1";
605 static int moveListLayout() { return 0; }
606 static OptList
positionOptions() { return OptList(); }
607 static const char *m_name
;
608 static const char *m_theme_proxy
;
611 const char *XiangQiVariantInfo::m_name
= "XiangQi";
612 const char *XiangQiVariantInfo::m_theme_proxy
= "XiangQi";
615 void XiangQiVariantInfo::forallPieces(PieceFunction
& f
) {
616 ChessVariant::forallPieces(f
);
619 VariantInfo
* XiangQiVariant::static_xiangqi_variant
= 0;
621 VariantInfo
* XiangQiVariant::info() {
622 if (!static_xiangqi_variant
)
623 static_xiangqi_variant
= new WrappedVariantInfo
<XiangQiVariantInfo
>;
624 return static_xiangqi_variant
;
629 struct MoveFactory
<XiangQiVariantInfo
> {
630 static XiangQiMove
createNormalMove(const NormalUserMove
& move
) {
631 return XiangQiMove(move
.from
, move
.to
, move
.promotionType
>= 0);
633 static XiangQiMove
createDropMove(const XiangQiPiece
& dropped
, const Point
& to
) {
634 return XiangQiMove(dropped
, to
);
637 static NormalUserMove
toNormal(const XiangQiMove
& move
) {
638 return NormalUserMove(move
.from
, move
.to
);