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 "chainreaction.h"
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 {
27 typedef PieceColor Color;
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;
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;
54 bool operator!=(const ChainReactionPiece& other) const {
55 return !(*this == other);
57 bool operator<(const ChainReactionPiece& other) const {
58 return m_color < other.m_color || (m_color == other.m_color && m_type < other.m_type);
60 bool equals(const ChainReactionPiece* other) const {
61 return other && *this == *other;
63 operator bool() const {
64 return m_type >= 1 && m_color != -1;
68 typedef Point ChainReactionMove;
70 class ChainReactionPosition {
72 typedef ChainReactionPiece Piece;
73 typedef ChainReactionMove Move;
74 typedef std::map<Piece, int> Pool;
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; }
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); }
111 const Piece* get(const Point& p) const {
112 return valid(p) && m_board[p] ? &m_board[p] : 0;
114 Piece* get(const Point& p) {
115 return valid(p) && m_board[p] ? &m_board[p] : 0;
117 const Piece* operator[](const Point& p) const { return get(p); }
118 void set(const Point& p, Piece* piece) {
121 m_board[p] = piece ? *piece : Piece();
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()
138 ChainReactionPosition::ChainReactionPosition(const OptList& l)
139 : m_board(options_list_find<IntOpt>(l, "width", 9),
140 options_list_find<IntOpt>(l, "height", 9))
143 ChainReactionPosition::ChainReactionPosition(Piece::Color turn, bool, bool, bool, bool, const Point&)
147 QStringList ChainReactionPosition::borderCoords() const
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);
158 ChainReactionMove ChainReactionPosition::getMove(const AlgebraicNotation& m, bool& ok) const {
163 ChainReactionMove ChainReactionPosition::getVerboseMove(int /*turn*/, const VerboseNotation& m) {
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) );
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;
184 bool exploding = false;
186 for(Point p = board.first(); p <= board.last(); p = board.next(p)) {
188 Point pts[] = { p+Point(0,-1), p+Point(0,1), p+Point(1,0), p+Point(-1,0) };
190 if(board.valid(pts[i]))
192 if(board[p].type()>max) {
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));
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))
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))
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)));
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;
244 bool m_anim_movement;
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)
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);
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;
279 shared_ptr<PieceSprite> sprite = p.sprite();
282 if (!p.piece()->equals(q)) {
283 shared_ptr<PieceSprite> sprite = p.sprite();
286 a = shared_ptr<Animation>(new PromotionAnimation( sprite,
287 m_position->setPiece(i, q, false, false) ));
291 m_position->removeElement(i);
292 a = shared_ptr<Animation>(new CaptureAnimation(sprite));
297 a = shared_ptr<Animation>(new DropAnimation( m_position->setPiece(i, q, false, false) ));
300 if (a) res->addPreAnimation(a);
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);
316 board[i] = Piece(static_cast<Piece::Color>(p.piece()->color()),
317 static_cast<Piece::Type>(p.piece()->type()));
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));
327 for(Point i = board.first(); i <= board.last(); i = board.next(i)) {
329 Point pts[] = { i+Point(0,-1), i+Point(0,1), i+Point(1,0), i+Point(-1,0) };
331 if(board.valid(pts[j]))
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)));
343 // {AnimationPtr next(new AnimationGroup);
344 // curr->addPostAnimation(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)));
366 AnimationPtr delay(new AnimationGroup);
367 delay->addPreAnimation(shared_ptr<Animation>(new DelayAnimation(200)));
368 curr->addPreAnimation(delay);
371 AnimationPtr next(new AnimationGroup);
372 curr->addPostAnimation(next);
375 while(Position::explodeStep(board, turn, target));
377 curr->addPostAnimation(warp(final));
382 ChainReactionAnimator::AnimationPtr ChainReactionAnimator::back(AbstractPosition::Ptr final,
383 const ChainReactionMove&) {
387 //END ChainReactionAnimator -----------------------------------------------------------------------
391 class ChainReactionVariantInfo {
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) {
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;
434 struct MoveFactory<ChainReactionVariantInfo> {
435 static ChainReactionMove createNormalMove(const NormalUserMove& move) {
438 static ChainReactionMove createDropMove(const ChainReactionPiece& /*piece*/, const Point& to) {
441 static NormalUserMove toNormal(const ChainReactionMove& m) {
442 return NormalUserMove(Point::invalid(), m);
447 class MoveSerializer<ChainReactionPosition> : public AbstractMoveSerializer {
448 ChainReactionMove m_move;
449 const ChainReactionPosition& m_ref;
451 MoveSerializer(const ChainReactionMove& m, const ChainReactionPosition& ref)
452 : m_move(m), m_ref(ref) { }
454 DecoratedMove toDecoratedMove() const {
455 return DecoratedMove() << SAN();
458 virtual QString SAN() const {
459 return m_move.toString(m_ref.size().y);
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;
469 ChainReactionAnimator(PointConverter* converter, const boost::shared_ptr<GPosition>& position)
470 : Base(converter, position) { }
472 AnimationPtr forward(const Position& final, const Move&) {
476 AnimationPtr back(const Position& final, const Move&) {