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.
12 #include "rubyutils.h"
13 #include "rubyvariant.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"
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));
29 return static_cast<int>(SYM2ID(val));
32 class RubyPiece : public AbstractPiece {
37 VALUE inner() const { return m_piece; }
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 {
50 RubyMove(VALUE move) : m_move(move) { }
52 VALUE inner() const { return m_move; }
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;
66 class RubyVariantInfo : public VariantInfo {
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,
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;
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;
126 static VALUE execute_piece_function(VALUE arg, VALUE functor) {
128 Data_Get_Struct(functor, PieceFunction, f);
129 RubyPiece piece(arg);
130 (*f)(piece.color(), piece.type());
135 RubyPiece::RubyPiece(VALUE piece)
138 bool RubyPiece::equals(AbstractPiece::Ptr _other) const {
139 if (!_other) return false;
140 RubyPiece* other = dynamic_cast<RubyPiece*>(_other.get());
143 return RTEST(rb_funcall(m_piece, rb_intern("=="), 1, other->inner()));
145 MISMATCH(*_other.get(),RubyPiece);
150 bool RubyPiece::less(AbstractPiece::Ptr _other) const {
151 if (!_other) return false;
152 RubyPiece* other = dynamic_cast<RubyPiece*>(_other.get());
155 return RTEST(rb_funcall(m_piece, rb_intern("<="), 1, other->inner()));
157 MISMATCH(*_other.get(),RubyPiece);
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);
185 class RubyPosition : public AbstractPosition {
186 typedef RubyMove Move;
187 typedef RubyPiece Piece;
190 RubyVariantInfo* m_variant;
192 VALUE& inner() { return m_pos; }
193 const VALUE& inner() const { return m_pos; }
195 RubyPosition(const VALUE& pos, RubyVariantInfo* variant)
197 , m_variant(variant) { }
199 virtual QString variant() const {
200 return m_variant->name();
203 virtual Point size() const {
204 VALUE res = rb_funcall(m_pos, rb_intern("size"), 0);
205 return Ruby::value2point(res);
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);
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);
221 rb_funcall(pool, rb_intern("[]="), 2, piece->inner(), INT2FIX(n));
223 MISMATCH(*_piece.get(),RubyPiece);
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);
231 VALUE count_value = rb_funcall(pool, rb_intern("[]"), 1, piece->inner());
233 if (RTEST(count_value))
234 count = NUM2INT(count_value) - n;
236 rb_funcall(pool, rb_intern("delete"), 1, piece->inner());
238 rb_funcall(pool, rb_intern("[]="), 2, piece->inner(), count);
241 MISMATCH(*_piece.get(),RubyPiece);
244 virtual void copyPoolFrom(AbstractPosition::Ptr _other) {
245 RubyPosition* other = dynamic_cast<RubyPosition*>(_other.get());
248 VALUE other_pool = rb_funcall(other->inner(), rb_intern("pool"), 0);
249 rb_funcall(m_pos, rb_intern("pool="), 1, other_pool);
252 MISMATCH(*_other.get(), RubyPosition);
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());
263 rb_funcall(pool, rb_intern("[]="), 2, piece->inner(), NUM2INT(it->second));
265 MISMATCH(*it->first.get(), RubyPiece);
271 virtual AbstractPiece::Ptr get(const Point& p) const {
272 VALUE piece = rb_funcall(m_pos, rb_intern("[]"), 1, Ruby::point2value(p));
274 return AbstractPiece::Ptr(new RubyPiece(piece));
276 return AbstractPiece::Ptr();
279 virtual void set(const Point& p, AbstractPiece::Ptr _piece) {
281 rb_funcall(m_pos, rb_intern("[]="), 2, Ruby::point2value(p), Qnil);
283 RubyPiece* piece = dynamic_cast<RubyPiece*>(_piece.get());
286 rb_funcall(m_pos, rb_intern("[]="), 2, Ruby::point2value(p), piece->inner());
288 MISMATCH(*_piece.get(),RubyPiece);
292 virtual int turn() const {
293 VALUE turn_value = rb_funcall(m_pos, rb_intern("turn"), 0);
294 return value2int(turn_value);
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);
302 virtual int previousTurn() const {
303 VALUE turn_value = rb_funcall(m_pos, rb_intern("previous_turn"), 0);
304 return value2int(turn_value);
307 virtual void switchTurn() {
308 rb_funcall(m_pos, rb_intern("switch_turn"), 0);
311 virtual bool testMove(AbstractMove::Ptr _move) const {
312 RubyMove* move = dynamic_cast<RubyMove*>(_move.get());
315 return RTEST(rb_funcall(m_pos, rb_intern("test_move"), 1, move->inner()));
317 MISMATCH(*_move.get(),RubyMove);
322 virtual void move(AbstractMove::Ptr _move) {
323 RubyMove* move = dynamic_cast<RubyMove*>(_move.get());
326 rb_funcall(m_pos, rb_intern("move"), 1, move->inner());
328 MISMATCH(*_move.get(),RubyMove);
331 virtual void setup() {
332 rb_funcall(m_pos, rb_intern("setup"), 0);
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));
340 virtual bool equal(AbstractPosition::Ptr _other) const {
341 RubyPosition* other = dynamic_cast<RubyPosition*>(_other.get());
344 return RTEST(rb_funcall(m_pos, rb_intern("=="), 1, other->inner()));
346 MISMATCH(*_other.get(),RubyPosition);
351 virtual AbstractMove::Ptr getMove(const AlgebraicNotation&) const {
352 return AbstractMove::Ptr();
355 virtual AbstractMove::Ptr getMove(const QString&) const {
356 return AbstractMove::Ptr();
359 virtual QString state() const {
363 virtual QStringList borderCoords() const {
364 return QStringList(); //TODO
367 virtual QString fen(int /*halfmove*/, int /*fullmove*/) const {
371 virtual AbstractPiece::Ptr moveHint(AbstractMove::Ptr) const {
373 return AbstractPiece::Ptr();
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;
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);
392 MISMATCH(*ref.get(), RubyPosition);
397 DecoratedMove RubyMove::toDecoratedMove(AbstractPosition::Ptr ref) const {
400 QString san = SAN(ref);
401 res.push_back(MovePart(san));
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);
411 MISMATCH(*ref.get(), RubyPosition);
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);
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()));
428 MISMATCH(*other, RubyMove);
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);
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);
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&) {
456 return createPosition();
459 AbstractPosition::Ptr RubyVariantInfo::createPositionFromFEN(const QString& fen) {
460 if (rb_respond_to(m_position, rb_intern("from_fen"))) {
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));
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));
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")));
499 QStringList RubyVariantInfo::borderCoords() const {
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*/) {
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());
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));
523 MISMATCH(move.m_piece.get(), RubyPiece);
524 return AbstractMove::Ptr();
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));
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);
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);
555 bool RubyVariantInfo::simpleMoves() {
560 QString RubyVariantInfo::name() const {
563 QString RubyVariantInfo::themeProxy() const {
566 OptList RubyVariantInfo::positionOptions() const {