Continued refactor work.
[tagua.git] / src / variants / rubyvariant.cpp_
blobd502ec67b5f19aaa1a7e2a699c2d681797acea00
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 */
12 #include "rubyutils.h"
13 #include "rubyvariant.h"
14 #include "kboard.h"
15 #include "xchess/animator.h"
16 #include "xchess/piece.h"
17 #include "xchess/move.h"
18 #include "highlevel.h"
19 #include "moveserializer.impl.h"
20 #include "crazyhouse_p.h"
21 #include "piecefunction.h"
23 class RubyPosition;
25 int value2int(VALUE val) {
26         if (rb_respond_to(val, rb_intern("to_i")))
27                 return NUM2INT(rb_funcall(val, rb_intern("to_i"), 0));
28         else
29                 return static_cast<int>(SYM2ID(val));
32 class RubyPiece : public AbstractPiece {
33   VALUE m_piece; 
34 public:
35   RubyPiece(VALUE);
36   
37   VALUE inner() const { return m_piece; }
38   
39   virtual bool equals(AbstractPiece::Ptr other) const;
40   virtual bool less(AbstractPiece::Ptr other) const;
41   virtual QString name() const;
42   virtual AbstractPiece::Ptr clone() const;
43   virtual int color() const;
44   virtual int type() const;
47 class RubyMove : public AbstractMove {
48   VALUE m_move;
49 public:
50   RubyMove(VALUE move) : m_move(move) { }
51   
52   VALUE inner() const { return m_move; }
53   
54         virtual QString SAN(AbstractPosition::Ptr ref) const;
55         virtual DecoratedMove toDecoratedMove(AbstractPosition::Ptr) const;
56         virtual QString toString(AbstractPosition::Ptr) const;
57         virtual NormalUserMove toUserMove() const;
58         virtual bool equals(AbstractMove::Ptr) const;
61 class RubyPool {
62 public:
63   RubyPool(VALUE);
66 class RubyVariantInfo : public VariantInfo {
67   VALUE m_type;
68   VALUE m_color;
69   VALUE m_piece;
70   VALUE m_move;
71   VALUE m_position;
72   
73   QString m_name;
74 public:
75   VALUE typeValue(int type);
76   VALUE colorValue(int type);
78   virtual AbstractPosition::Ptr createPosition();
79   virtual AbstractPosition::Ptr createCustomPosition(const OptList& l);
81   virtual AbstractPosition::Ptr createPositionFromFEN(const QString& fen);
83   virtual AbstractPosition::Ptr createChessboard(int turn,
84                               bool wk, bool wq, bool bk, bool bq,
85                               const Point& ep);
86                               
87   virtual AbstractPiece::Ptr createPiece(int color, int type);
88   virtual void forallPieces(class PieceFunction& f);
89   virtual int moveListLayout() const;
90   virtual QStringList borderCoords() const;
92   virtual AbstractAnimator::Ptr createAnimator(PointConverter* converter,
93                                            GraphicalPosition* position);
94   virtual AbstractMove::Ptr createNormalMove(const NormalUserMove& move);
95   virtual AbstractMove::Ptr createDropMove(const DropUserMove& move);
97   virtual AbstractMove::Ptr getVerboseMove(int turn, const VerboseNotation& m) const;
98   virtual int type(const QString& str);
99   virtual QString typeSymbol(int type);
100   virtual bool simpleMoves();
101   virtual QString name() const;
102   virtual QString themeProxy() const;
103   virtual OptList positionOptions() const;
106 class RubyAnimator : public AbstractAnimator {
107         typedef boost::shared_ptr<AnimationGroup> AnimationPtr;
108 public:
109         RubyAnimator() { }
110   virtual AnimationPtr warp(AbstractPosition::Ptr) { return AnimationPtr(); }
112   virtual AnimationPtr forward(AbstractPosition::Ptr, AbstractMove::Ptr) { return AnimationPtr(); }
113   virtual AnimationPtr back(AbstractPosition::Ptr, AbstractMove::Ptr) { return AnimationPtr(); }
116 static VALUE pool_set_helper(VALUE arg, VALUE _pool) {
117   AbstractPosition::AbstractPool* pool;
118   Data_Get_Struct(_pool, AbstractPosition::AbstractPool, pool);
119   VALUE piece = rb_ary_entry(arg, 0);
120   int count = NUM2INT(rb_ary_entry(arg, 1));
121   (*pool)[AbstractPiece::Ptr(new RubyPiece(piece))] = count;
122   
123   return Qnil;
126 static VALUE execute_piece_function(VALUE arg, VALUE functor) {
127   PieceFunction* f;
128   Data_Get_Struct(functor, PieceFunction, f);
129   RubyPiece piece(arg);
130   (*f)(piece.color(), piece.type());
131   return Qnil;
135 RubyPiece::RubyPiece(VALUE piece)
136 : m_piece(piece) { }
138 bool RubyPiece::equals(AbstractPiece::Ptr _other) const {
139   if (!_other) return false;
140   RubyPiece* other = dynamic_cast<RubyPiece*>(_other.get());
142   if (other)
143     return RTEST(rb_funcall(m_piece, rb_intern("=="), 1, other->inner()));
144   else {
145     MISMATCH(*_other.get(),RubyPiece);
146     return false;
147   }
150 bool RubyPiece::less(AbstractPiece::Ptr _other) const {
151   if (!_other) return false;
152   RubyPiece* other = dynamic_cast<RubyPiece*>(_other.get());
154   if (other)
155     return RTEST(rb_funcall(m_piece, rb_intern("<="), 1, other->inner()));
156   else {
157     MISMATCH(*_other.get(),RubyPiece);
158     return false;
159   }
162 AbstractPiece::Ptr RubyPiece::clone() const {
163   VALUE cl = rb_funcall(m_piece, rb_intern("clone"), 0);
164   return AbstractPiece::Ptr(new RubyPiece(cl));
167 QString RubyPiece::name() const {
168   VALUE name_value = rb_funcall(m_piece, rb_intern("to_s"), 0);
169   return StringValuePtr(name_value); 
172 int RubyPiece::color() const {
173   VALUE color_value = rb_funcall(m_piece, rb_intern("color"), 0);
174         return value2int(color_value);
177 int RubyPiece::type() const {
178   if (rb_respond_to(m_piece, rb_intern("type"))) {
179     VALUE type_value = rb_funcall(m_piece, rb_intern("type"), 0);
180                 return value2int(type_value);
181   }
182   else return -1;
185 class RubyPosition : public AbstractPosition {
186   typedef RubyMove Move;
187   typedef RubyPiece Piece;
189   VALUE m_pos;
190   RubyVariantInfo* m_variant;
191 public:
192   VALUE& inner() { return m_pos; }
193   const VALUE& inner() const { return m_pos; }
195   RubyPosition(const VALUE& pos, RubyVariantInfo* variant)
196   : m_pos(pos)
197   , m_variant(variant) { }
199   virtual QString variant() const {
200     return m_variant->name();
201   }
203   virtual Point size() const {
204     VALUE res = rb_funcall(m_pos, rb_intern("size"), 0);
205     return Ruby::value2point(res);
206   }
208   virtual PoolPtr pool() const {
209     AbstractPool* p = new AbstractPool;
210     VALUE pool = rb_funcall(m_pos, rb_intern("pool"), 0);
211     VALUE c_pool = Data_Wrap_Struct(rb_cObject, 0, 0, p);
212     rb_iterate(rb_each, pool, (VALUE(*)(...))pool_set_helper, c_pool); 
213     return PoolPtr(p);
214   }
216   virtual void addToPool(AbstractPiece::Ptr _piece, int n) {
217     RubyPiece* piece = dynamic_cast<RubyPiece*>(_piece.get());
218     VALUE pool = rb_funcall(m_pos, rb_intern("pool"), 0);
220     if (piece)
221       rb_funcall(pool, rb_intern("[]="), 2, piece->inner(), INT2FIX(n));
222     else
223       MISMATCH(*_piece.get(),RubyPiece);
224   }
226   virtual void removeFromPool(AbstractPiece::Ptr _piece, int n) {
227     RubyPiece* piece = dynamic_cast<RubyPiece*>(_piece.get());
228     VALUE pool = rb_funcall(m_pos, rb_intern("pool"), 0);
229     
230     if (piece) {
231       VALUE count_value = rb_funcall(pool, rb_intern("[]"), 1, piece->inner());
232       int count = 0;
233       if (RTEST(count_value))
234         count = NUM2INT(count_value) - n;
235       if (count <= 0)
236         rb_funcall(pool, rb_intern("delete"), 1, piece->inner());
237       else
238         rb_funcall(pool, rb_intern("[]="), 2, piece->inner(), count);
239     }
240     else
241       MISMATCH(*_piece.get(),RubyPiece);
242   }
244   virtual void copyPoolFrom(AbstractPosition::Ptr _other) {
245     RubyPosition* other = dynamic_cast<RubyPosition*>(_other.get());
247     if (other) {
248       VALUE other_pool = rb_funcall(other->inner(), rb_intern("pool"), 0);
249       rb_funcall(m_pos, rb_intern("pool="), 1, other_pool);
250     }
251     else
252       MISMATCH(*_other.get(), RubyPosition);
253   }
255   virtual void setPool(PoolPtr new_pool) {
256     VALUE pool = rb_funcall(m_pos, rb_intern("pool"), 0);
257     rb_funcall(pool, rb_intern("clear"), 0);
259     for (AbstractPool::iterator it = new_pool->begin(); it != new_pool->end(); ++it) {
260       RubyPiece* piece = dynamic_cast<RubyPiece*>(it->first.get());
262       if (piece)
263         rb_funcall(pool, rb_intern("[]="), 2, piece->inner(), NUM2INT(it->second));
264       else {
265         MISMATCH(*it->first.get(), RubyPiece);
266         return;
267       }
268     }
269   }
271   virtual AbstractPiece::Ptr get(const Point& p) const {
272     VALUE piece = rb_funcall(m_pos, rb_intern("[]"), 1, Ruby::point2value(p));
273     if (piece)
274       return AbstractPiece::Ptr(new RubyPiece(piece));
275     else
276       return AbstractPiece::Ptr();
277   }
279   virtual void set(const Point& p, AbstractPiece::Ptr _piece) {
280     if (!_piece)
281       rb_funcall(m_pos, rb_intern("[]="), 2, Ruby::point2value(p), Qnil);
282     else {
283       RubyPiece* piece = dynamic_cast<RubyPiece*>(_piece.get());
285       if (piece)
286         rb_funcall(m_pos, rb_intern("[]="), 2, Ruby::point2value(p), piece->inner());
287       else
288         MISMATCH(*_piece.get(),RubyPiece);
289     }
290   }
292   virtual int turn() const {
293     VALUE turn_value = rb_funcall(m_pos, rb_intern("turn"), 0);
294                 return value2int(turn_value);
295   }
297   virtual void setTurn(int turn) {
298     VALUE turn_value = m_variant->colorValue(turn);
299     rb_funcall(m_pos, rb_intern("turn="), 1, turn_value);
300   }
302   virtual int previousTurn() const {
303     VALUE turn_value = rb_funcall(m_pos, rb_intern("previous_turn"), 0);
304     return value2int(turn_value);
305   }
307   virtual void switchTurn() {
308     rb_funcall(m_pos, rb_intern("switch_turn"), 0);
309   }
311   virtual bool testMove(AbstractMove::Ptr _move) const {
312     RubyMove* move = dynamic_cast<RubyMove*>(_move.get());
314     if (move)
315       return RTEST(rb_funcall(m_pos, rb_intern("test_move"), 1, move->inner()));
316     else {
317       MISMATCH(*_move.get(),RubyMove);
318       return false;
319     }
320   }
322   virtual void move(AbstractMove::Ptr _move) {
323     RubyMove* move = dynamic_cast<RubyMove*>(_move.get());
325     if (move)
326       rb_funcall(m_pos, rb_intern("move"), 1, move->inner());
327     else
328       MISMATCH(*_move.get(),RubyMove);
329   }
331   virtual void setup() {
332     rb_funcall(m_pos, rb_intern("setup"), 0);
333   }
335   virtual AbstractPosition::Ptr clone() const {
336     VALUE cl = rb_funcall(m_pos, rb_intern("clone"), 0);
337     return AbstractPosition::Ptr(new RubyPosition(cl, m_variant));
338   }
340   virtual bool equal(AbstractPosition::Ptr _other) const {
341     RubyPosition* other = dynamic_cast<RubyPosition*>(_other.get());
343     if(other)
344       return RTEST(rb_funcall(m_pos, rb_intern("=="), 1, other->inner()));
345     else {
346       MISMATCH(*_other.get(),RubyPosition);
347       return false;
348     }
349   }
351   virtual AbstractMove::Ptr getMove(const AlgebraicNotation&) const {
352     return AbstractMove::Ptr();
353   }
355   virtual AbstractMove::Ptr getMove(const QString&) const {
356     return AbstractMove::Ptr();
357   }
359   virtual QString state() const {
360     return ""; // TODO
361   }
362   
363         virtual QStringList borderCoords() const {
364                 return QStringList(); //TODO
365         }
367   virtual QString fen(int /*halfmove*/, int /*fullmove*/) const {
368     return "";
369   }
371   virtual AbstractPiece::Ptr moveHint(AbstractMove::Ptr) const {
372     // TODO
373     return AbstractPiece::Ptr();
374   }
376   virtual void dump() const {
377     if (rb_respond_to(m_pos, rb_intern("to_s"))) {
378       VALUE dumped_value = rb_funcall(m_pos, rb_intern("to_s"), 0);
379       const char* dumped = StringValuePtr(dumped_value);
380       std::cout << wrap_cptr(dumped) << std::endl;
381     }
382   }
386 QString RubyMove::SAN(AbstractPosition::Ptr ref) const {
387         if (RubyPosition* pos = dynamic_cast<RubyPosition*>(ref.get())) {
388                 VALUE res = rb_funcall(m_move, rb_intern("san"), 1, pos->inner());
389                 return StringValuePtr(res);
390         }
391         else {
392                 MISMATCH(*ref.get(), RubyPosition);
393                 return "";
394         }
397 DecoratedMove RubyMove::toDecoratedMove(AbstractPosition::Ptr ref) const {
398         // TODO
399         DecoratedMove res;
400         QString san = SAN(ref);
401         res.push_back(MovePart(san));
402         return res;
404         
405 QString RubyMove::toString(AbstractPosition::Ptr ref) const {
406         if (RubyPosition* pos = dynamic_cast<RubyPosition*>(ref.get())) {
407                 VALUE res = rb_funcall(m_move, rb_intern("to_s"), 1, pos->inner());
408                 return StringValuePtr(res);
409         }
410         else {
411                 MISMATCH(*ref.get(), RubyPosition);
412                 return "";
413         }
416 NormalUserMove RubyMove::toUserMove() const {
417         VALUE res = rb_funcall(m_move, rb_intern("to_user"), 0);
418         Point from = Ruby::value2point(rb_funcall(res, rb_intern("from"), 0));
419         Point to = Ruby::value2point(rb_funcall(res, rb_intern("to"), 0));
420         return NormalUserMove(from, to);
422         
423 bool RubyMove::equals(AbstractMove::Ptr other) const {
424         if (RubyMove* mv = dynamic_cast<RubyMove*>(other.get())) {
425                 return RTEST(rb_funcall(m_move, rb_intern("=="), 1, mv->inner()));
426         }
427         else {
428                 MISMATCH(*other, RubyMove);
429                 return false;
430         }
434 VALUE RubyVariantInfo::typeValue(int type) {
435         if (rb_respond_to(m_type, rb_intern("from_i")))
436                 return rb_funcall(m_type, rb_intern("from_i"), 1, type);
437         else
438                 return ID2SYM(static_cast<ID>(type));
441 VALUE RubyVariantInfo::colorValue(int color) {
442         if (rb_respond_to(m_type, rb_intern("from_i")))
443                 return rb_funcall(m_type, rb_intern("from_i"), 1, color);
444         else
445                 return ID2SYM(static_cast<ID>(color));
448 AbstractPosition::Ptr RubyVariantInfo::createPosition() {
449   VALUE pos = rb_funcall(m_position, rb_intern("new"), 0);
450   return AbstractPosition::Ptr(
451     new RubyPosition(pos, this));
454 AbstractPosition::Ptr RubyVariantInfo::createCustomPosition(const OptList&) {
455   // TODO
456   return createPosition();
459 AbstractPosition::Ptr RubyVariantInfo::createPositionFromFEN(const QString& fen) {
460   if (rb_respond_to(m_position, rb_intern("from_fen"))) {
461 //     int ok;
462     VALUE pos = rb_funcall(m_position, rb_intern("from_fen"), 1, rb_str_new2(fen.toAscii()));
463 //     if (!ok) return AbstractPosition::Ptr();
464     return AbstractPosition::Ptr(new RubyPosition(pos, this));
465   }
466   
467   return AbstractPosition::Ptr();
470 AbstractPosition::Ptr RubyVariantInfo::createChessboard(int /*turn*/,
471                             bool /*wk*/, bool /*wq*/, bool /*bk*/, bool /*bq*/,
472                             const Point& /*ep*/) {
473   return AbstractPosition::Ptr();
476 AbstractPiece::Ptr RubyVariantInfo::createPiece(int color, int type) {
477   if (rb_respond_to(m_piece, rb_intern("from_color_type"))) {
478         VALUE piece = rb_funcall(m_piece, rb_intern("from_color_type"), 2, 
479                 colorValue(color), typeValue(type));
480                 return AbstractPiece::Ptr(new RubyPiece(piece));
481   }
482   else
483         return AbstractPiece::Ptr();
486 void RubyVariantInfo::forallPieces(PieceFunction& f) {
487   VALUE functor = Data_Wrap_Struct(rb_cObject, 0, 0, &f);
488   VALUE piece_class = rb_funcall(m_piece, rb_intern("class"), 0);
489   rb_iterate(rb_each, piece_class, (VALUE(*)(...))execute_piece_function, functor);
492 int RubyVariantInfo::moveListLayout() const {
493 //   if (rb_respond_to(m_variant, rb_intern("movelist_layout")))
494 //     return NUM2INT(rb_funcall(m_variant, rb_intern("movelist_layout")));
495 //   else
496     return 0;
499 QStringList RubyVariantInfo::borderCoords() const {
500   // TODO
501   return QStringList() << "a" << "b" << "c" << "d" << "e" << "f" << "g" << "h"
502                       << "1" << "2" << "3" << "4" << "5" << "6" << "7" << "8";
505 AbstractAnimator::Ptr RubyVariantInfo::createAnimator(PointConverter* /*converter*/,
506                                           GraphicalPosition* /*position*/) {
507         // TODO
508   return AbstractAnimator::Ptr(new RubyAnimator);
511 AbstractMove::Ptr RubyVariantInfo::createNormalMove(const NormalUserMove& move) {
512         VALUE mv = rb_funcall(m_move, rb_intern("from_normal"), Ruby::point2value(move.from), Ruby::point2value(move.to));
513   return AbstractMove::Ptr(new RubyMove(mv));
516 AbstractMove::Ptr RubyVariantInfo::createDropMove(const DropUserMove& move) {
517   RubyPiece* piece = dynamic_cast<RubyPiece*>(move.m_piece.get());
518   if (piece) {
519         VALUE mv = rb_funcall(m_move, rb_intern("from_drop"), piece->inner(), Ruby::point2value(move.m_to));
520     return AbstractMove::Ptr(new RubyMove(mv));
521   }
522   else {
523     MISMATCH(move.m_piece.get(), RubyPiece);
524     return AbstractMove::Ptr();
525   }
528 AbstractMove::Ptr RubyVariantInfo::getVerboseMove(int /*turn*/, const VerboseNotation& /*m*/) const {
529 //   Move res = Position::getVerboseMove(static_cast<typename Piece::Color>(turn), m);
530 //   return AbstractMove::Ptr(new RubyMove(res));
531         // TODO
532         return AbstractMove::Ptr(new RubyMove(Qnil));
535 int RubyVariantInfo::type(const QString& str) {
536         VALUE type_str = rb_str_new2(str.toAscii());
537         if (rb_respond_to(m_type, rb_intern("from_s"))) {
538         VALUE res = rb_funcall(m_type, rb_intern("from_s"), type_str);
539         return value2int(res);
540         }
541         else
542                 return -1;
545 QString RubyVariantInfo::typeSymbol(int type) {
546         VALUE type_value = typeValue(type);
547         if (rb_respond_to(type_value, rb_intern("symbol"))) {
548                 VALUE res = rb_funcall(type_value, rb_intern("symbol"), 0);
549                 return StringValuePtr(res);
550         }
551         else
552                 return "";
555 bool RubyVariantInfo::simpleMoves() {
556         //TODO
557   return false;
560 QString RubyVariantInfo::name() const {
561   return m_name;
563 QString RubyVariantInfo::themeProxy() const {
564   return "";
566 OptList RubyVariantInfo::positionOptions() const {
567   return OptList();