ICSAPI::parseVerbose is now used instead of VariantInfo::getVerboseMove.
[tagua/yd.git] / src / variants / chainreaction.cpp_
blob1e0e0df993c87df992ce1127cf6a4219dd7a729b
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 "chainreaction.h"
12 #include <map>
13 #include "xchess/animator.impl.h"
14 #include "xchess/piece.h"
15 #include "xchess/move.h"
16 #include "piecefunction.h"
17 #include "highlevel.h"
18 #include "algebraicnotation.h"
19 #include "graphicalposition.h"
20 #include "pointconverter.h"
21 #include "piecegrid.h"
23 using namespace boost;
25 class ChainReactionPiece {
26 public:
27   typedef PieceColor Color;
28   typedef int Type;
29 private:
30   Color m_color;
31   int   m_type;
32 public:
33   ChainReactionPiece()
34   : m_color(static_cast<Color>(-1)), m_type(static_cast<Type>(-1)) { }
35   ChainReactionPiece(Color color, Type t)
36   : m_color(color), m_type(t) { }
37   Color color() const { return m_color; }
38   Type type() const { return m_type; }
39   int id() const { return static_cast<int>(m_color); }
40   QString name() const {
41                    return (m_color == WHITE ? "white_"
42                         : m_color == BLACK ? "black_"
43                         : m_color == 2 ? "neutral_" : "unknown")
44                       +(m_type>0 ? QString::number(m_type) : QString("add")); }
45   static Color oppositeColor(Color color) {
46     return color == WHITE ? BLACK : WHITE;
47   }
48   static int getType(const QString&) { return -1; }
49   static QString typeSymbol(int) { return QString(); }
51   bool operator==(const ChainReactionPiece& other) const {
52     return m_color == other.m_color && m_type == other.m_type;
53   }
54   bool operator!=(const ChainReactionPiece& other) const {
55     return !(*this == other);
56   }
57   bool operator<(const ChainReactionPiece& other) const {
58     return m_color < other.m_color || (m_color == other.m_color && m_type < other.m_type);
59   }
60   bool equals(const ChainReactionPiece* other) const {
61     return other && *this == *other;
62   }
63   operator bool() const {
64     return m_type >= 1 && m_color != -1;
65   }
68 typedef Point ChainReactionMove;
70 class ChainReactionPosition {
71 public:
72   typedef ChainReactionPiece Piece;
73   typedef ChainReactionMove Move;
74   typedef std::map<Piece, int> Pool;
75 private:
76   Pool m_pool;
77   Grid<Piece> m_board;
78   Piece::Color m_turn;
80 public:
81   static bool explodeStep(const Grid<Piece>& board, Piece::Color turn, Grid<Piece>& target);
83   ChainReactionPosition();
84   ChainReactionPosition(const OptList& l);
85   ChainReactionPosition(Piece::Color turn, bool wk, bool wq,
86                                           bool bk, bool bq, const Point& ep);
88   Pool& pool() { return m_pool; }
89   const Pool& pool() const { return m_pool; }
90   void addToPool(const Piece&, int) { }
91   void removeFromPool(const Piece&, int) { }
93   Piece::Color turn() const { return m_turn; }
94   void setTurn(Piece::Color turn) { m_turn = turn; }
95   void switchTurn();
96   Piece::Color previousTurn() const { return Piece::oppositeColor(m_turn); }
98   void fromFEN(const QString&, bool& ok) { ok = true;}
99   QString fen(int,int) const { return QString(); }
101   static Move getVerboseMove(int turn, const VerboseNotation& m);
102   Move getMove(const AlgebraicNotation& m, bool& ok) const;
104   bool testMove(Move& p) const;
105   void move(const Move& p);
107   Point size() const { return m_board.getSize(); }
108   bool valid(const Point& p) const { return m_board.valid(p); }
109   void setup();
111   const Piece* get(const Point& p) const {
112     return valid(p) && m_board[p] ? &m_board[p] : 0;
113   }
114   Piece* get(const Point& p) {
115     return valid(p) && m_board[p] ? &m_board[p] : 0;
116   }
117   const Piece* operator[](const Point& p) const { return get(p); }
118   void set(const Point& p, Piece* piece) {
119     if (!valid(p))
120       return;
121     m_board[p] = piece ? *piece : Piece();
122   }
123   void removePiece(const Point& p) { set(p, 0); }
125   bool operator==(const ChainReactionPosition& other) const;
127   shared_ptr<Piece> moveHint(const Move& m) const;
129   void dump() const { }
131   QStringList borderCoords() const;
134 ChainReactionPosition::ChainReactionPosition()
135 : m_board(9,9)
136 , m_turn(WHITE) { }
138 ChainReactionPosition::ChainReactionPosition(const OptList& l)
139 : m_board(options_list_find<IntOpt>(l, "width", 9),
140            options_list_find<IntOpt>(l, "height", 9))
141 , m_turn(WHITE) { }
143 ChainReactionPosition::ChainReactionPosition(Piece::Color turn, bool, bool, bool, bool, const Point&)
144 : m_board(9,9)
145 , m_turn(turn) { }
147 QStringList ChainReactionPosition::borderCoords() const
149   QStringList retv;
150   Point p = m_board.getSize();
151   for(int i=0; i<p.x; i++)
152     retv << QChar('a'+i);
153   for(int i=1; i<=p.y; i++)
154     retv += QString::number(i);
155   return retv + retv;
158 ChainReactionMove ChainReactionPosition::getMove(const AlgebraicNotation& m, bool& ok) const {
159   ok = true;
160   return m.to;
163 ChainReactionMove ChainReactionPosition::getVerboseMove(int /*turn*/, const VerboseNotation& m) {
164   return m.to;
167 void ChainReactionPosition::setup() {
168   for(Point p = m_board.first(); p <= m_board.last(); p = m_board.next(p)) {
169     m_board[p] = Piece(static_cast<Piece::Color>(2), static_cast<Piece::Type>(1) );
170   }
173 bool ChainReactionPosition::explodeStep(const Grid<Piece>& board, Piece::Color turn, Grid<Piece>& target) {
174   bool all_this_color = true;
175   for(Point p = board.first(); p <= board.last(); p = board.next(p))
176   if(target[p].color() != turn) {
177     all_this_color = false;
178     break;
179   }
180   if(all_this_color)
181     return false;
183   target = board;
184   bool exploding = false;
186   for(Point p = board.first(); p <= board.last(); p = board.next(p)) {
187     int max = 0;
188     Point pts[] = { p+Point(0,-1), p+Point(0,1), p+Point(1,0), p+Point(-1,0) };
189     for(int i=0;i<4;i++)
190     if(board.valid(pts[i]))
191       max++;
192     if(board[p].type()>max) {
193       exploding = true;
194       for(int i=0;i<4;i++)
195       if(board.valid(pts[i]))
196         target[pts[i]] = Piece(turn, static_cast<Piece::Type>(target[pts[i]].type()+1));
197       target[p] = Piece(turn, static_cast<Piece::Type>(target[p].type()-max));
198     }
199   }
201   return exploding;
204 void ChainReactionPosition::switchTurn() {
205   m_turn = Piece::oppositeColor(m_turn);
208 bool ChainReactionPosition::testMove(Move& p) const {
209   if (!valid(p) || m_board[p].color()==Piece::oppositeColor(m_turn))
210     return false;
212   return true;
215 void ChainReactionPosition::move(const Move& p) {
216   m_board[p] = Piece(m_turn, static_cast<Piece::Type>(m_board[p].type()+1));
217   Grid<Piece> tmp = m_board;
218   while(explodeStep(m_board, m_turn, tmp))
219     m_board = tmp;
220   switchTurn();
223 bool ChainReactionPosition::operator==(const ChainReactionPosition& other) const {
224   return m_board == other.m_board
225       && m_turn == other.m_turn;
228 shared_ptr<ChainReactionPiece> ChainReactionPosition::moveHint(const Move& /*p*/) const {
229   return shared_ptr<Piece>(new Piece(m_turn, static_cast<Piece::Type>(-1)));
232 #if 0
233 //BEGIN ChainReactionAnimator ---------------------------------------------------------------------
235 class ChainReactionAnimator {
236   typedef boost::shared_ptr<AnimationGroup> AnimationPtr;
237   typedef ChainReactionPiece Piece;
238   typedef ChainReactionPosition Position;
240   PointConverter* m_converter;
241   GraphicalPosition* m_position;
242   Random m_random;
244   bool m_anim_movement;
245   bool m_anim_explode;
246   bool m_anim_fade;
247   bool m_anim_rotate;
248 public:
249   ChainReactionAnimator(PointConverter* converter, GraphicalPosition* position);
250   AnimationPtr warp(AbstractPosition::Ptr);
251   AnimationPtr forward(AbstractPosition::Ptr, const ChainReactionMove& move);
252   AnimationPtr back(AbstractPosition::Ptr, const ChainReactionMove& move);
255 ChainReactionAnimator::ChainReactionAnimator(PointConverter* converter, GraphicalPosition* position)
256 : m_converter(converter)
257 , m_position(position)
258 , m_anim_movement(false)
259 , m_anim_explode(false)
260 , m_anim_fade(false)
261 , m_anim_rotate(false) {
262   if(position->getBoolSetting("animations", true)) {
263     m_anim_movement = (bool)position->getBoolSetting("animations.movement", true);
264     m_anim_explode = (bool)position->getBoolSetting("animations.explode", true);
265     m_anim_fade = (bool)position->getBoolSetting("animations.fading", true);
266     m_anim_rotate = (bool)position->getBoolSetting("animations.transform", true);
267   }
270 ChainReactionAnimator::AnimationPtr ChainReactionAnimator::warp(AbstractPosition::Ptr final) {
271   AnimationPtr res(new AnimationGroup);
272   for (Point i = m_position->first(); i <= m_position->last(); i = m_position->next(i)) {
273     QPoint real = m_converter->toReal(i);
274     Element p = m_position->getElement(i);
275     AbstractPiece::Ptr q = final->get(i);
276     shared_ptr<Animation> a;
278     if (p) {
279       shared_ptr<PieceSprite> sprite = p.sprite();
280       Q_ASSERT(sprite);
282       if (!p.piece()->equals(q)) {
283         shared_ptr<PieceSprite> sprite = p.sprite();
285         if (q) {
286           a = shared_ptr<Animation>(new PromotionAnimation( sprite,
287                                 m_position->setPiece(i, q, false, false) ));
288         }
289         else {
290           // remove it
291           m_position->removeElement(i);
292           a = shared_ptr<Animation>(new CaptureAnimation(sprite));
293         }
294       }
295     }
296     else if (q) {
297       a = shared_ptr<Animation>(new DropAnimation( m_position->setPiece(i, q, false, false) ));
298     }
300     if (a) res->addPreAnimation(a);
301   }
303   return res;
306 ChainReactionAnimator::AnimationPtr ChainReactionAnimator::forward(AbstractPosition::Ptr final,
307                                                                 const ChainReactionMove& m) {
309   AnimationPtr retv(new AnimationGroup);
310   AnimationPtr curr = retv;
312   Grid<Piece> board(final->size().x,final->size().y);
313   for (Point i = m_position->first(); i <= m_position->last(); i = m_position->next(i)) {
314     Element p = m_position->getElement(i);
315     if(p.piece())
316       board[i] = Piece(static_cast<Piece::Color>(p.piece()->color()),
317                               static_cast<Piece::Type>(p.piece()->type()));
318   }
319   Grid<unsigned char> exploded(board.getSize().x, board.getSize().y);
320   Grid<Piece> target = board;
321   Piece::Color turn = Piece::oppositeColor(static_cast<Piece::Color>(final->turn()));
322   target[m] = Piece(turn, static_cast<Piece::Type>(target[m].type()+1));
324   do {
325     bool added = false;
327     for(Point i = board.first(); i <= board.last(); i = board.next(i)) {
328       int max = 0;
329       Point pts[] = { i+Point(0,-1), i+Point(0,1), i+Point(1,0), i+Point(-1,0) };
330       for(int j=0;j<4;j++)
331       if(board.valid(pts[j]))
332         max++;
333       exploded[i] = false;
334       if(board[i].type() > max) {
335         if(shared_ptr<PieceSprite> sprite = m_position->getSprite(i)) {
336           curr->addPreAnimation(shared_ptr<Animation>(
337             new ExplodeAnimation(sprite, m_random)));
338           exploded[i] = true;
339         }
340       }
341     }
343 //     {AnimationPtr next(new AnimationGroup);
344 //     curr->addPostAnimation(next);
345 //     curr = next;}
347     for(Point i = target.first(); i <= target.last(); i = target.next(i)) {
348       Element p = m_position->getElement(i);
349       if(!p.piece() || p.piece()->color() != target[i].color()
350                   || p.piece()->type() != target[i].type()) {
351         if(p.sprite() && !exploded[i])
352           curr->addPreAnimation(shared_ptr<Animation>(
353             new CaptureAnimation(p.sprite())));
354         AbstractPiece::Ptr piece = ChainReactionVariant::info()->createPiece(
355                                               target[i].color(), target[i].type() );
356         shared_ptr<PieceSprite> s = m_position->setPiece(i, piece, false, false);
357         curr->addPreAnimation(shared_ptr<Animation>(
358             new DropAnimation(s)));
359         added = true;
360       }
361     }
363     board = target;
365 #if 1
366     AnimationPtr delay(new AnimationGroup);
367     delay->addPreAnimation(shared_ptr<Animation>(new DelayAnimation(200)));
368     curr->addPreAnimation(delay);
369     curr = delay;
370 #endif
371     AnimationPtr next(new AnimationGroup);
372     curr->addPostAnimation(next);
373     curr = next;
374   }
375   while(Position::explodeStep(board, turn, target));
377   curr->addPostAnimation(warp(final));
379   return retv;
382 ChainReactionAnimator::AnimationPtr ChainReactionAnimator::back(AbstractPosition::Ptr final,
383                                                                 const ChainReactionMove&) {
384   return warp(final);
387 //END ChainReactionAnimator -----------------------------------------------------------------------
389 #endif
391 class ChainReactionVariantInfo {
392 public:
393   typedef ChainReactionPosition Position;
394   typedef Position::Move Move;
395   typedef Position::Piece Piece;
396   typedef class ChainReactionAnimator Animator;
398   static const bool m_simple_moves = true;
399   static const char *m_name;
400   static const char *m_theme_proxy;
402   static void forallPieces(PieceFunction& f);
403   static int moveListLayout() { return 0; }
404   static OptList positionOptions() { return OptList()
405       << OptPtr(new IntOpt("width", "Board width:", 9, 2, 40))
406       << OptPtr(new IntOpt("height", "Board height:", 9, 2, 40)); }
409 const char *ChainReactionVariantInfo::m_name = "ChainReaction";
410 const char *ChainReactionVariantInfo::m_theme_proxy = "ChainReaction";
412 void ChainReactionVariantInfo::forallPieces(PieceFunction& f) {
413   f(WHITE, 0);
414   f(BLACK, 0);
415   f(WHITE, 1);
416   f(BLACK, 1);
417   f(WHITE, 2);
418   f(BLACK, 2);
419   f(WHITE, 3);
420   f(BLACK, 3);
421   f(WHITE, 4);
422   f(BLACK, 4);
425 VariantInfo* ChainReactionVariant::static_chainreaction_variant = 0;
427 VariantInfo* ChainReactionVariant::info() {
428   if (!static_chainreaction_variant)
429     static_chainreaction_variant = new WrappedVariantInfo<ChainReactionVariantInfo>;
430   return static_chainreaction_variant;
433 template <>
434 struct MoveFactory<ChainReactionVariantInfo> {
435   static ChainReactionMove createNormalMove(const NormalUserMove& move) {
436     return move.to;
437   }
438   static ChainReactionMove createDropMove(const ChainReactionPiece& /*piece*/, const Point& to) {
439     return to;
440   }
441   static NormalUserMove toNormal(const ChainReactionMove& m) {
442     return NormalUserMove(Point::invalid(), m);
443   }
446 template <>
447 class MoveSerializer<ChainReactionPosition> : public AbstractMoveSerializer {
448   ChainReactionMove m_move;
449   const ChainReactionPosition& m_ref;
450 public:
451   MoveSerializer(const ChainReactionMove& m, const ChainReactionPosition& ref)
452   : m_move(m), m_ref(ref) { }
454   DecoratedMove toDecoratedMove() const {
455     return DecoratedMove() << SAN();
456   }
458   virtual QString SAN() const {
459     return m_move.toString(m_ref.size().y);
460   }
463 class ChainReactionAnimator : public SimpleAnimator<ChainReactionVariantInfo> {
464   typedef SimpleAnimator<ChainReactionVariantInfo> Base;
465   typedef Base::Position Position;
466   typedef Base::Move Move;
467   typedef Base::GPosition GPosition;
468 public:
469   ChainReactionAnimator(PointConverter* converter, const boost::shared_ptr<GPosition>& position)
470   : Base(converter, position) { }
472   AnimationPtr forward(const Position& final, const Move&) {
473     return warp(final);
474   }
475   
476   AnimationPtr back(const Position& final, const Move&) {
477     return warp(final);
478   }