#include "ai.h" #include "ai.moc" #include #include #include #include #include #include #include #include #include #include #include "commonprefs.h" #include "board.h" #include "base/piece.h" #include "base/factory.h" //----------------------------------------------------------------------------- AIPiece::AIPiece() : _current(0) {} AIPiece::~AIPiece() { delete _current; } void AIPiece::init(const Piece *piece, Board *b) { _piece = piece; _board = b; if ( _current==0 ) _current = new Piece; reset(); } void AIPiece::reset() { curPos = 0; curRot = 0; if (_piece) _current->copy(_piece); // else _current->generateNext(0); nbRot = _current->nbConfigurations() - 1; nbPos = _board->matrix().width() - _current->size().first + 1; } bool AIPiece::increment() { curPos++; if ( curPos==nbPos ) { if ( curRot==nbRot ) { // if ( _piece || _current->type()==Piece::info().nbTypes() ) { reset(); return false; // } // _current->generateNext(_current->type()+1); // nbRot = _current->nbConfigurations() - 1; // curRot = 0; } _current->rotate(true, TQPoint(0, 0)); nbPos = _board->matrix().width() - _current->size().first + 1; curRot++; curPos = 0; } return true; } bool AIPiece::place() { if ( curRot==3 ) { if ( !_board->rotateRight() ) return false; } else for (uint i=0; irotateLeft() ) return false; curDec = curPos - _board->currentPos().first - _current->min().first; if ( curDec!=0 && _board->moveRight(curDec)!=(uint)kAbs(curDec) ) return false; _board->dropDown(); return !_board->isGameOver(); } //----------------------------------------------------------------------------- const AI::Data AI::LastData = { 0, 0, 0, false, 0 }; AI::AI(uint tTime, uint oTime, const Data *DATA) : timer(this), thinkTime(tTime), orderTime(oTime), stopped(false), board(0) { connect(&timer, TQ_SIGNAL(timeout()), TQ_SLOT(timeout())); for (uint i=0; DATA[i].name; i++) { Element element; element.coefficient = 0.; element.trigger = 0; element.data = &DATA[i]; _elements.append(element); } settingsChanged(); } void AI::resizePieces(uint size) { uint oldSize = pieces.size(); for (uint i=size; icopy(*main); } void AI::launch(Board *m) { main = m; if ( board==0 ) board = static_cast(bfactory->createBoard(false, 0)); pieces[0]->init(main->currentPiece(), board); // current if ( pieces.size()>=2 ) pieces[1]->init(main->nextPiece(), board); // next state = Thinking; hasBestPoints = false; startTimer(); } void AI::stop() { timer.stop(); stopped = true; } void AI::start() { if (stopped) { startTimer(); stopped = false; } } void AI::startTimer() { switch (state) { case Thinking: timer.start(thinkTime, true); break; case GivingOrders: timer.start(orderTime, true); break; } } void AI::timeout() { switch (state) { case Thinking: if ( think() ) state = GivingOrders; break; case GivingOrders: if ( emitOrder() ) return; break; } startTimer(); } bool AI::emitOrder() { if ( bestRot==3 ) { bestRot = 0; main->pRotateRight(); } else if (bestRot) { bestRot--; main->pRotateLeft(); } else if ( bestDec>0 ) { bestDec--; main->pMoveRight(); } else if ( bestDec<0 ) { bestDec++; main->pMoveLeft(); } else { main->pDropDownStart(); return true; } return false; } bool AI::think() { initThink(); bool moveOk = true; for (uint i=0; iplace() ) { moveOk = false; break; } if (moveOk) { double p = points(); if ( !hasBestPoints || p>bestPoints || (p==hasBestPoints && random.getBool()) ) { hasBestPoints = true; bestPoints = p; bestDec = pieces[0]->dec(); bestRot = pieces[0]->rot(); } } for (uint i=pieces.size(); i>0; i--) if ( pieces[i-1]->increment() ) return false; return true; } double AI::points() const { double pts = 0; for (uint i=0; i<_elements.size(); i++) { if ( _elements[i].coefficient==0.0 ) continue; double v = _elements[i].data->function(*main, *board); if ( _elements[i].data->triggered && tqRound(v)<_elements[i].trigger ) continue; pts += _elements[i].coefficient * v; } return pts; } void AI::settingsChanged() { int d = CommonPrefs::thinkingDepth(); resizePieces(d); for (uint i=0; i<_elements.size(); i++) { const Data &data = *_elements[i].data; _elements[i].coefficient = AIConfig::coefficient(data); if (data.triggered) _elements[i].trigger = AIConfig::trigger(data); } if ( timer.isActive() ) launch(main); } double AI::nbOccupiedLines(const Board &, const Board ¤t) { return current.matrix().height() - current.nbClearLines(); } double AI::nbHoles(const Board &, const Board ¤t) { uint nb = 0; for (uint i=0; i=0; j--) { KGrid2D::Coord c(i, j); if ( current.matrix()[c]==0 ) nb++; } } return nb; } double AI::peakToPeak(const Board &, const Board ¤t) { int min = current.matrix().height()-1; for (uint i=0; i &elements) : TQWidget(0, "ai config") { TQGridLayout *top = new TQGridLayout(this, 3, 2, KDialog::marginHint(), KDialog::spacingHint()); TQLabel *label = new TQLabel(i18n("Thinking depth:"), this); top->addWidget(label, 0, 0); KIntNumInput *in = new KIntNumInput(this, "kcfg_ThinkingDepth"); in->setRange(minThinkingDepth, maxThinkingDepth); top->addWidget(in, 0, 1); top->addRowSpacing(1, KDialog::spacingHint()); TQGrid *grid = new TQGrid(2, this); top->addMultiCellWidget(grid, 2, 2, 0, 1); for (uint i=0; isetFrameStyle(TQFrame::Panel | TQFrame::Plain); TQVBox *vb = new TQVBox(grid); if (data.whatsthis) TQWhatsThis::add(vb, i18n(data.whatsthis)); vb->setMargin(KDialog::spacingHint()); vb->setSpacing(KDialog::spacingHint()); vb->setFrameStyle(TQFrame::Panel | TQFrame::Plain); if (data.triggered) { KIntNumInput *trig = new KIntNumInput(vb, triggerKey(data.name)); trig->setRange(0, 10, 1, true); } KDoubleNumInput *coeff = new KDoubleNumInput(vb, coefficientKey(data.name)); coeff->setRange(0.0, 1.0, 1.0, true); } } TQCString AIConfig::triggerKey(const char *name) { return "kcfg_Trigger_" + TQCString(name); } TQCString AIConfig::coefficientKey(const char *name) { return "kcfg_Coefficient_" + TQCString(name); } double AIConfig::coefficient(const AI::Data &data) { TDEConfigSkeletonItem *item = CommonPrefs::self()->findItem( TQString("Coefficient_%1").arg(data.name) ); assert(item); return item->property().toDouble(); } int AIConfig::trigger(const AI::Data &data) { TDEConfigSkeletonItem *item = CommonPrefs::self()->findItem( TQString("Trigger_%1").arg(data.name) ); assert(item); return item->property().toInt(); }