/* * Copyright (c) 2001 Mikhail Kourinny (mkourinny@yahoo.com) * Copyright (c) 2002 Nicolas HADACEK (hadacek@kde.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "solver.h" #include "solver.moc" #include #include #include #include #include #include #include #include "headerP.h" //----------------------------------------------------------------------------- class SolverPrivate { public: SolverPrivate() : facts(0), rules(0) {} ~SolverPrivate() { delete facts; delete rules; } AdviseFast::FactSet *facts; AdviseFast::RuleSet *rules; #ifdef DEBUG unsigned long t0, t; #endif }; Solver::Solver(TQObject *parent) : TQObject(parent) { d = new SolverPrivate; #ifdef DEBUG #define PRINT_ELAPSED(purpose) \ d->t = time(0); \ cout << "Spent " << d->t - d->t0 << " seconds on " purpose << endl; \ d->t0 = d->t; #endif } Solver::~Solver() { delete d; } Coord Solver::advise(BaseField &field, float &probability) { Coord point; probability = 1; delete d->facts; d->facts = new AdviseFast::FactSet(&field); delete d->rules; d->rules = new AdviseFast::RuleSet(d->facts); if( AdviseFast::adviseFast(&point, d->facts, d->rules) ) return point; CoordSet surePoints; AdviseFull::ProbabilityMap probabilities; AdviseFull::adviseFull(d->facts, &surePoints, &probabilities); // return one of the sure point (random choice to limit the tropism) [NH] if( !surePoints.empty() ) { KRandomSequence r; uint k = r.getLong(surePoints.size()); CoordSet::iterator it = surePoints.begin(); for (uint i=0; ifirst; return probabilities.begin()->second; } // Otherwise the Field is already solved :) return Coord(-1,-1); } void Solver::solve(BaseField &field, bool noGuess) { _field = &field; initSolve(false, noGuess); } bool Solver::initSolve(bool oneStep, bool noGuess) { _inOneStep = oneStep; _noGuess = noGuess; delete d->facts; d->facts = new AdviseFast::FactSet(_field); delete d->rules; d->rules = new AdviseFast::RuleSet(d->facts); #ifdef DEBUG d->t0 = time(0); #endif return solveStep(); } bool Solver::solveStep() { if ( _field->isSolved() ) { emit solvingDone(true); return true; } d->rules->solve(); #ifdef DEBUG PRINT_ELAPSED("fast rules") #endif if( _field->isSolved() ) { emit solvingDone(true); return true; } CoordSet surePoints; AdviseFull::ProbabilityMap probabilities; AdviseFull::adviseFull(d->facts, &surePoints, &probabilities); #ifdef DEBUG PRINT_ELAPSED("full rules") #endif if(!surePoints.empty()){ CoordSet::iterator i; for(i=surePoints.begin(); i!=surePoints.end(); ++i) { bool b = d->rules->reveal(*i); assert(b); } } else if ( !_noGuess ) { #ifdef DEBUG cout << "Applying heuristics!" << endl; cout << *_field << endl; #endif // Minimum probability logic assert(!probabilities.empty()); #ifdef DEBUG AdviseFull::ProbabilityMap::iterator i=probabilities.begin(); cout << "Probability is " << i->first << endl; #endif bool success = d->rules->reveal(probabilities.begin()->second); if ( !success ) { emit solvingDone(false); return false; } } if (_inOneStep) return solveStep(); else TQTimer::singleShot(0, this, TQT_SLOT(solveStep())); return false; } bool Solver::solveOneStep(BaseField &field) { _field = &field; return initSolve(true, false); } //----------------------------------------------------------------------------- SolvingRateDialog::SolvingRateDialog(const BaseField &field, TQWidget *parent) : KDialogBase(Plain, i18n("Compute Solving Rate"), Ok|Close, Close, parent, "compute_solving_rate", true, true), _refField(field) { connect(&_solver, TQT_SIGNAL(solvingDone(bool)), TQT_SLOT(solvingDone(bool))); KGuiItem item = KStdGuiItem::ok(); item.setText(i18n("Start")); setButtonOK(item); TQVBoxLayout *top = new TQVBoxLayout(plainPage(), 0, spacingHint()); TQLabel *label = new TQLabel(i18n("Width: %1").arg(field.width()), plainPage()); top->addWidget(label); label = new TQLabel(i18n("Height: %1").arg(field.height()), plainPage()); top->addWidget(label); label = new TQLabel(i18n("Mines: %1 (%2%)").arg(field.nbMines()) .arg( field.nbMines() * 100.0 / field.size()), plainPage()); top->addWidget(label); top->addSpacing(spacingHint()); _progress = new KProgress(NB_STEPS, plainPage()); _progress->setTextEnabled(true); _progress->setFormat("%v"); top->addWidget(_progress); _label = new TQLabel(i18n("Success rate:"), plainPage()); top->addWidget(_label); } void SolvingRateDialog::slotOk() { enableButtonOK(false); _i = 0; _success = 0; _progress->setValue(0); TQTimer::singleShot(0, this, TQT_SLOT(step())); } void SolvingRateDialog::step() { if ( _i==NB_STEPS ) { enableButtonOK(true); return; } _i++; _field.reset(_refField.width(), _refField.height(), _refField.nbMines()); _solver.solve(_field, false); } void SolvingRateDialog::solvingDone(bool success) { if (success) _success++; _label->setText(i18n("Success rate: %1%") .arg(_success * 100.0 / _i, 0, 'f', 3)); _progress->advance(1); TQTimer::singleShot(0, this, TQT_SLOT(step())); }