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.
11 #include "crazyhouse_p.h"
12 #include "crazyhouse.h"
13 #include "kboard_wrapped.h"
14 #include "animation.h"
15 #include "moveserializer.impl.h"
17 class CrazyhouseVariantInfo
{
19 typedef CrazyhousePosition Position
;
20 typedef Position::Move Move
;
21 typedef Position::Piece Piece
;
22 typedef Position::PoolReference Pool
;
24 typedef class CrazyhouseAnimator Animator
;
25 static const bool m_simple_moves
= false;
26 static void forallPieces(PieceFunction
& f
);
27 static int moveListLayout(){ return 0; }
28 static const char *m_name
;
29 static const char *m_theme_proxy
;
30 static OptList
positionOptions() { return OptList(); }
33 //BEGIN CrazyhousePiece
35 CrazyhousePiece::CrazyhousePiece(ChessPiece::Color color
, ChessPiece::Type type
, bool promoted
)
36 : ChessPiece(color
, type
)
37 , m_promoted(promoted
) { }
39 CrazyhousePiece::CrazyhousePiece(const CrazyhousePiece
& other
)
41 , m_promoted(other
.m_promoted
) { }
43 CrazyhousePiece::CrazyhousePiece(const ChessPiece
& other
)
45 , m_promoted(false) { }
49 //BEGIN CrazyhouseMove
51 CrazyhouseMove::CrazyhouseMove(const ChessMove
& m
)
53 , m_drop(INVALID_COLOR
, INVALID_TYPE
)
55 , m_pool_index(-1) { }
57 CrazyhouseMove::CrazyhouseMove(const Point
& from
, const Point
& to
, PieceType promotionType
)
58 : ChessMove(from
, to
, promotionType
)
59 , m_drop(INVALID_COLOR
, INVALID_TYPE
)
61 , m_pool_index(-1) { }
63 CrazyhouseMove::CrazyhouseMove(const CrazyhouseMove
& other
)
65 , m_drop(other
.m_drop
)
66 , m_pool(other
.m_pool
)
67 , m_pool_index(other
.m_pool_index
) { }
69 CrazyhouseMove::CrazyhouseMove(const CrazyhousePiece
& pc
, const Point
& to
)
70 : ChessMove(Point::invalid(), to
)
73 , m_pool_index(-1) { }
75 CrazyhouseMove::CrazyhouseMove(int pool
, int pool_index
, const Point
& to
)
76 : ChessMove(Point::invalid(), to
)
77 , m_drop(INVALID_COLOR
, INVALID_TYPE
)
79 , m_pool_index(pool_index
) { }
83 //BEGIN CrazyhousePosition
85 CrazyhousePosition::CrazyhousePosition() {
88 CrazyhousePosition::CrazyhousePosition(const OptList
&) {
91 CrazyhousePosition::CrazyhousePosition(const CrazyhousePosition
& other
)
95 CrazyhousePosition::CrazyhousePosition(const ChessPosition
& other
)
99 CrazyhousePosition::CrazyhousePosition(CrazyhousePiece::Color turn
, bool wk
, bool wq
,
100 bool bk
, bool bq
, const Point
& ep
)
101 : Base(turn
, wk
, wq
, bk
, bq
, ep
) {
104 CrazyhousePosition
* CrazyhousePosition::clone() const {
105 return new CrazyhousePosition(*this);
108 CrazyhousePiece::Color
CrazyhousePosition::moveTurn(const Move
& move
) const {
109 if (move
.m_drop
.valid() )
110 return move
.m_drop
.color();
112 return Base::moveTurn(move
);
115 boost::shared_ptr
<AbstractGenerator
<CrazyhouseMove
> >
116 CrazyhousePosition::createLegalGenerator() const {
117 return boost::shared_ptr
<AbstractGenerator
<CrazyhouseMove
> >(
118 new MoveGenerator
<CrazyhousePosition
,
119 LegalMove
<CrazyhousePosition
> >(*this));
122 bool CrazyhousePosition::pseudolegal(Move
& move
) const {
124 if(!move
.m_drop
.valid() && move
.m_pool
!= -1 && move
.m_pool_index
!= -1) {
125 move
.m_drop
= const_cast<CrazyhousePosition
*>(this)->pool(move
.m_pool
).get(move
.m_pool_index
);
126 std::cout
<< move
.m_drop
<< " " << move
.m_pool
<< " " << move
.m_pool_index
<< std::endl
;
129 if (move
.m_drop
.valid()) {
130 Q_ASSERT(valid(move
.to
));
132 // cannot drop on occupied squares
133 if (m_board
[move
.to
]) return false;
135 // cannot drop pawns in first or eighth rank
136 if (move
.m_drop
.type() == PAWN
&&
137 (move
.to
.y
== 0 || move
.to
.y
== 7))
144 return Base::pseudolegal(move
);
147 void CrazyhousePosition::move(const Move
& move
) {
149 if (move
.m_drop
.valid()) {
150 Q_ASSERT(m_pool
[move
.m_drop
.color()].count(move
.m_drop
.type()));
151 Q_ASSERT(!m_board
[move
.to
]);
153 basicDropPiece(new Piece(move
.m_drop
), move
.to
);
154 if(!--m_pool
[move
.m_drop
.color()][move
.m_drop
.type()])
155 m_pool
[move
.m_drop
.color()].erase(move
.m_drop
.type());
162 if (move
.type() == Move::Promotion
) {
163 m_board
[move
.to
].setPromoted(true);
168 for(Pool::iterator i
= m_pool
.begin(); i
!= m_pool
.end(); ++i
)
169 std::cout
<< i
->first
.color() << "." << i
->first
.type() << " " << i
->second
<<std::endl
;
173 void CrazyhousePosition::executeCaptureOn(const Point
& point
) {
174 Piece piece
= m_board
[point
];
176 Piece
downgraded( Piece::oppositeColor(piece
.color()),
177 piece
.promoted() ? PAWN
: piece
.type());
178 m_pool
[downgraded
.color()][downgraded
.type()]++;
180 Base::executeCaptureOn(point
);
183 CrazyhouseMove
CrazyhousePosition::getMove(const AlgebraicNotation
& san
, bool& ok
) const {
186 Piece
piece(m_turn
, (PieceType
)san
.type
);
188 if ( !m_pool
.count(piece
.color()) || !m_pool
.find(piece
.color())->second
.count(piece
.type()) ) {
190 return CrazyhouseMove::invalid();
194 return CrazyhouseMove( piece
, san
.to
);
198 return Base::getMove(san
, ok
);
201 void CrazyhousePosition::dump() const {
204 for(Pool::const_iterator j
= m_pool
.begin(); j
!= m_pool
.end(); ++j
)
205 for(PlayerPool::const_iterator i
= j
->second
.begin(); i
!= j
->second
.end(); ++i
)
206 std::cout
<< j
->first
<< "." << i
->first
<< " " << i
->second
<<std::endl
;
209 bool CrazyhousePosition::operator==(const CrazyhousePosition
& pos
) const {
210 return m_pool
== pos
.m_pool
&& Base::operator==(pos
);
213 //END CrazyhousePosition
219 typedef UnwrappedGraphicalAPI
<CrazyhouseVariantInfo
> CrazyhouseGraphicalAPI
;
221 class CrazyhouseAnimator
{
222 CrazyhouseGraphicalAPI::Ptr m_cinterface
;
224 CrazyhouseAnimator(CrazyhouseGraphicalAPI::Ptr cinterface
)
225 : m_cinterface(cinterface
) {
228 void updatePool(const CrazyhousePosition
& final
) {
231 for(int color
= 0; color
< 2; color
++) {
232 CrazyhousePosition::Color c
= static_cast<CrazyhousePosition::Color
>(color
);
233 const CrazyhousePosition::PlayerPool
& before
= const_cast<CrazyhousePosition
*>(
234 m_cinterface
->position())->rawPool()[c
];
235 const CrazyhousePosition::PlayerPool
& after
= const_cast<CrazyhousePosition
*>(
236 &final
)->rawPool()[c
];
237 CrazyhousePosition::PlayerPool::const_iterator before_it
= before
.begin();
238 CrazyhousePosition::PlayerPool::const_iterator after_it
= after
.begin();
242 //oh, a nice bunch of write-only magic shit
243 while(before_it
!= before
.end() || after_it
!= after
.end()) {
244 if(after_it
== after
.end() || (before_it
!= before
.end()
245 && before_it
->first
< after_it
->first
)) {
246 for(int i
=0;i
<before_it
->second
;i
++)
247 m_cinterface
->takePoolSprite(color
, pos
);
250 else if (before_it
== before
.end() || (after_it
!= after
.end()
251 && after_it
->first
< before_it
->first
)) {
252 for(int i
=0;i
<after_it
->second
;i
++)
253 m_cinterface
->insertPoolPiece(color
, pos
, CrazyhousePiece(c
, after_it
->first
) );
254 pos
+= after_it
->second
;
258 Q_ASSERT(after_it
->first
== before_it
->first
);
259 if(before_it
->second
< after_it
->second
)
260 for(int i
=0;i
<after_it
->second
- before_it
->second
;i
++)
261 m_cinterface
->insertPoolPiece(color
, pos
, CrazyhousePiece(c
, after_it
->first
) );
262 else if(before_it
->second
> after_it
->second
)
263 for(int i
=0;i
<before_it
->second
- after_it
->second
;i
++)
264 m_cinterface
->takePoolSprite(color
, pos
);
265 pos
+= after_it
->second
;
271 while(oldit
!= curr
->end() || newit
!= pool
->end()) {
272 if(newit
== pool
->end() || (oldit
!= curr
->end()
273 && oldit
->first
->less(newit
->first
) )) {
274 removeFromPool(oldit
->first
, oldit
->second
);
277 else if (oldit
== curr
->end() || (newit
!= pool
->end()
278 && newit
->first
->less(oldit
->first
) )) {
279 addToPool(newit
->first
, newit
->second
);
283 Q_ASSERT(newit
->first
->equals(oldit
->first
));
284 if(oldit
->second
< newit
->second
)
285 addToPool(newit
->first
, newit
->second
- oldit
->second
);
286 else if(oldit
->second
> newit
->second
)
287 removeFromPool(newit
->first
, oldit
->second
- newit
->second
);
296 AnimationGroupPtr
warp(const CrazyhousePosition
& final
) {
297 const CrazyhousePosition
* current
= m_cinterface
->position();
298 AnimationGroupPtr
res(new AnimationGroup
);
300 for (Point i
= current
->first(); i
<= current
->last(); i
= current
->next(i
)) {
301 CrazyhousePiece c
= current
->get(i
);
302 CrazyhousePiece f
= final
.get(i
);
305 NamedSprite sprite
= m_cinterface
->setPiece(i
, f
, false);
306 res
->addPreAnimation(m_cinterface
->appearAnimation(sprite
, GraphicalAPI::Instant
));
309 NamedSprite old_sprite
= m_cinterface
->takeSprite(i
);
310 res
->addPreAnimation(m_cinterface
->disappearAnimation(old_sprite
, GraphicalAPI::Instant
));
312 else if(c
&& f
&& !(c
== f
) ) {
313 NamedSprite old_sprite
= m_cinterface
->takeSprite(i
);
314 NamedSprite sprite
= m_cinterface
->setPiece(i
, f
, false);
315 res
->addPreAnimation(m_cinterface
->morphAnimation(old_sprite
, sprite
, GraphicalAPI::Instant
));
323 boost::shared_ptr
<AnimationGroup
> forward(const CrazyhousePosition
& final
, const CrazyhouseMove
& move
) {
324 AnimationGroupPtr
res(new AnimationGroup
);
326 NamedSprite piece
= m_cinterface
->takeSprite(move
.from
);
327 NamedSprite captured
= m_cinterface
->takeSprite(move
.to
);
328 m_cinterface
->setSprite(move
.to
, piece
);
331 res
->addPreAnimation(m_cinterface
->moveAnimation(piece
, move
.to
));
336 res
->addPostAnimation(m_cinterface
->destroyAnimation(captured
));
338 if (move
.type() == CrazyhouseMove::EnPassantCapture
) {
339 Point
phantom(move
.to
.x
, move
.from
.y
);
340 NamedSprite capturedPawn
= m_cinterface
->takeSprite(phantom
);
343 QPoint real
= m_cinterface
->converter()->toReal(phantom
);
344 res
->addPostAnimation(m_cinterface
->disappearAnimation(capturedPawn
));
349 else if (move
.type() == CrazyhouseMove::Promotion
) {
350 CrazyhousePiece promoted
= final
.get(move
.to
);
353 QPoint real
= m_cinterface
->converter()->toReal(move
.to
);
354 NamedSprite old_sprite
= m_cinterface
->getSprite(move
.to
);
355 NamedSprite new_sprite
= m_cinterface
->setPiece(move
.to
, promoted
, /*false,*/ false);
357 res
->addPostAnimation(m_cinterface
->morphAnimation(old_sprite
, new_sprite
));
362 else if (move
.type() == CrazyhouseMove::KingSideCastling
) {
363 Point rookSquare
= move
.to
+ Point(1,0);
364 Point rookDestination
= move
.from
+ Point(1,0);
366 NamedSprite rook
= m_cinterface
->takeSprite(rookSquare
);
367 m_cinterface
->setSprite(rookDestination
, rook
);
368 res
->addPreAnimation(m_cinterface
->moveAnimation(rook
, rookDestination
));
370 else if (move
.type() == CrazyhouseMove::QueenSideCastling
) {
371 Point rookSquare
= move
.to
+ Point(-2,0);
372 Point rookDestination
= move
.from
+ Point(-1,0);
374 NamedSprite rook
= m_cinterface
->takeSprite(rookSquare
);
375 m_cinterface
->setSprite(rookDestination
, rook
);
376 res
->addPreAnimation(m_cinterface
->moveAnimation(rook
, rookDestination
));
383 boost::shared_ptr
<AnimationGroup
> back(const CrazyhousePosition
& final
, const CrazyhouseMove
& move
) {
384 AnimationGroupPtr
res(new AnimationGroup
);
386 NamedSprite piece
= m_cinterface
->takeSprite(move
.to
);
387 NamedSprite captured
;
388 if (CrazyhousePiece captured_piece
= final
.get(move
.to
)) {
389 captured
= m_cinterface
->setPiece(move
.to
, captured_piece
, false);
390 res
->addPreAnimation(m_cinterface
->appearAnimation(captured
));
394 piece
= m_cinterface
->createPiece(move
.to
, final
.get(move
.from
), false);
395 res
->addPreAnimation(m_cinterface
->appearAnimation(piece
));
396 res
->addPreAnimation(FadeAnimationPtr(new FadeAnimation(piece
.sprite(),
397 m_cinterface
->converter()->toReal(move
.to
), 0, 255)));
400 m_cinterface
->setSprite(move
.from
, piece
);
403 if (move
.type() == CrazyhouseMove::EnPassantCapture
) {
404 Point
phantom(move
.to
.x
, move
.from
.y
);
406 if (CrazyhousePiece pawn_piece
= final
.get(phantom
)) {
407 NamedSprite captured_pawn
= m_cinterface
->setPiece(phantom
, pawn_piece
, false);
408 res
->addPreAnimation(m_cinterface
->appearAnimation(captured_pawn
));
411 else if (move
.type() == CrazyhouseMove::Promotion
) {
412 CrazyhousePiece pawn_piece
= final
.get(move
.from
);
414 NamedSprite pawn
= m_cinterface
->createPiece(move
.to
, pawn_piece
, false);
415 res
->addPreAnimation(m_cinterface
->morphAnimation(piece
, pawn
));
417 // replace piece with pawn
418 m_cinterface
->setSprite(move
.from
, pawn
);
422 else if (move
.type() == CrazyhouseMove::KingSideCastling
) {
423 Point rookSquare
= move
.to
+ Point(1,0);
424 Point rookDestination
= move
.from
+ Point(1,0);
426 NamedSprite rook
= m_cinterface
->takeSprite(rookDestination
);
427 m_cinterface
->setSprite(rookSquare
, rook
);
429 res
->addPreAnimation(m_cinterface
->moveAnimation(rook
, rookSquare
));
431 else if (move
.type() == CrazyhouseMove::QueenSideCastling
) {
432 Point rookSquare
= move
.to
+ Point(-2,0);
433 Point rookDestination
= move
.from
+ Point(-1,0);
435 NamedSprite rook
= m_cinterface
->takeSprite(rookDestination
);
436 m_cinterface
->setSprite(rookSquare
, rook
);
438 res
->addPreAnimation(m_cinterface
->moveAnimation(rook
, rookSquare
));
441 res
->addPreAnimation(m_cinterface
->moveAnimation(piece
, move
.from
));
451 //BEGIN CrazyhouseVariant
454 const char *CrazyhouseVariantInfo::m_name
= "Crazyhouse";
455 const char *CrazyhouseVariantInfo::m_theme_proxy
= "Chess";
457 VariantInfo
* CrazyhouseVariant::static_crazyhouse_variant
= 0;
459 void CrazyhouseVariantInfo::forallPieces(PieceFunction
& f
) {
460 return ChessVariant::forallPieces(f
);
463 VariantInfo
* CrazyhouseVariant::info() {
464 if (!static_crazyhouse_variant
)
465 static_crazyhouse_variant
= new WrappedVariantInfo
<CrazyhouseVariantInfo
>;
466 return static_crazyhouse_variant
;
469 //END CrazyhouseVariant