Fixed move testing for moves with a reference to the pool.
[tagua/yd.git] / src / variants / crazyhouse.cpp
blobf2cb79526d405dd44e12bb52cf6693bd6c9998ec
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 "crazyhouse_p.h"
12 #include "crazyhouse.h"
13 #include "kboard_wrapped.h"
14 #include "animation.h"
15 #include "moveserializer.impl.h"
17 class CrazyhouseVariantInfo {
18 public:
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)
40 : ChessPiece(other)
41 , m_promoted(other.m_promoted) { }
43 CrazyhousePiece::CrazyhousePiece(const ChessPiece& other)
44 : ChessPiece(other)
45 , m_promoted(false) { }
47 //END CrazyhousePiece
49 //BEGIN CrazyhouseMove
51 CrazyhouseMove::CrazyhouseMove(const ChessMove& m)
52 : ChessMove(m)
53 , m_drop(INVALID_COLOR, INVALID_TYPE)
54 , m_pool(-1)
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)
60 , m_pool(-1)
61 , m_pool_index(-1) { }
63 CrazyhouseMove::CrazyhouseMove(const CrazyhouseMove& other)
64 : ChessMove(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)
71 , m_drop(pc)
72 , m_pool(-1)
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)
78 , m_pool(pool)
79 , m_pool_index(pool_index) { }
81 //END CrazyhouseMove
83 //BEGIN CrazyhousePosition
85 CrazyhousePosition::CrazyhousePosition() {
88 CrazyhousePosition::CrazyhousePosition(const OptList&) {
91 CrazyhousePosition::CrazyhousePosition(const CrazyhousePosition& other)
92 : Base(other) {
95 CrazyhousePosition::CrazyhousePosition(const ChessPosition& other)
96 : Base(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();
111 else
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))
138 return false;
140 return true;
142 // normal move
143 else
144 return Base::pseudolegal(move);
147 void CrazyhousePosition::move(const Move& move) {
148 // drop
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());
157 else {
158 // normal move
159 Base::move(move);
161 // set promoted flag
162 if (move.type() == Move::Promotion) {
163 m_board[move.to].setPromoted(true);
167 #if 0
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;
170 #endif
173 void CrazyhousePosition::executeCaptureOn(const Point& point) {
174 Piece piece = m_board[point];
175 if (piece) {
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 {
185 if (san.drop) {
186 Piece piece(m_turn, (PieceType)san.type);
188 if ( !m_pool.count(piece.color()) || !m_pool.find(piece.color())->second.count(piece.type()) ) {
189 ok = false;
190 return CrazyhouseMove::invalid();
192 else {
193 ok = true;
194 return CrazyhouseMove( piece, san.to);
197 else
198 return Base::getMove(san, ok);
201 void CrazyhousePosition::dump() const {
202 Base::dump();
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;
223 public:
224 CrazyhouseAnimator(CrazyhouseGraphicalAPI::Ptr cinterface)
225 : m_cinterface(cinterface) {
228 void updatePool(const CrazyhousePosition& final) {
229 final.dump();
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();
240 int pos = 0;
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);
248 ++before_it;
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;
255 ++after_it;
257 else {
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;
266 ++after_it;
267 ++before_it;
270 #if 0
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);
275 ++oldit;
277 else if (oldit == curr->end() || (newit != pool->end()
278 && newit->first->less(oldit->first) )) {
279 addToPool(newit->first, newit->second);
280 ++newit;
282 else {
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);
288 ++newit;
289 ++oldit;
292 #endif
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);
304 if( !c && f ) {
305 NamedSprite sprite = m_cinterface->setPiece(i, f, false);
306 res->addPreAnimation(m_cinterface->appearAnimation(sprite, GraphicalAPI::Instant));
308 else if (c && !f) {
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));
319 updatePool(final);
320 return res;
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);
330 if (piece)
331 res->addPreAnimation(m_cinterface->moveAnimation(piece, move.to));
332 else
333 ERROR("Bug!!!");
335 if (captured)
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);
342 if (capturedPawn) {
343 QPoint real = m_cinterface->converter()->toReal(phantom);
344 res->addPostAnimation(m_cinterface->disappearAnimation(capturedPawn));
346 else
347 ERROR("Bug!!!");
349 else if (move.type() == CrazyhouseMove::Promotion) {
350 CrazyhousePiece promoted = final.get(move.to);
352 if (promoted) {
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));
359 else
360 ERROR("Bug!!!");
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));
379 updatePool(final);
380 return res;
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));
393 if (!piece) {
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);
413 if (pawn_piece) {
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);
419 piece = 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));
443 updatePool(final);
444 return res;
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