/* * Copyright (c) 2001 Mikhail Kourinny (mkourinny@yahoo.com) * * 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 #include #include "adviseFast.h" using std::set; AdviseFast::RuleSet::RuleSet(FactSet *f) : facts(f) { FactSet::iterator i; for(i=facts->begin(); i!=facts->end(); ++i) addGeneral(i->first); } AdviseFast::RuleSet::~RuleSet(){ } void AdviseFast::RuleSet::addRule(Entry const &entry) { _rules.insert(entry); } bool AdviseFast::RuleSet::getSurePoint(Coord *sp) { if(_surePoints.empty()){ if(!apply()) return false; } CoordSet::iterator i = _surePoints.begin(); *sp = *i; _surePoints.erase(i); return true; } bool AdviseFast::RuleSet::reveal(Coord what) { CoordSet affectedFacts; if(!facts->reveal(what, &affectedFacts)) // OOPS :( return false; CoordSet::iterator i; for( i = affectedFacts.begin(); i != affectedFacts.end(); ++i) this->addGeneral(*i); return true; } void AdviseFast::RuleSet::solve() { Coord p; while(getSurePoint(&p)) { bool res = reveal(p); assert(res); Q_UNUSED(res); } } bool AdviseFast::RuleSet::apply() { while(!_rules.empty()){ set::iterator i = _rules.begin(); std::unique_ptr r (this->newRule(*i)); _rules.erase(i); if(r->apply(&this->_surePoints)) return true; } return false; } AdviseFast::Rule * AdviseFast::RuleSet::newRule(Entry const &e){ CoordSet::const_iterator i = e.second.begin(); Coord p, p1; switch(e.first){ case EMPTY: assert(e.second.size() == 1); return new EmptyRule(*i, this); case FULL: assert(e.second.size() == 1); return new FullRule(*i, this); case INCLUDE: assert(e.second.size() == 2); p = *i; ++i; p1 = *i; return new InclusionRule(p, p1, this); case INCLUDE1: assert(e.second.size() == 2); p = *i; ++i; p1 = *i; return new InclusionRule(p1, p, this); case INTERSECT: assert(e.second.size() == 2); p = *i; ++i; p1 = *i; return new IntersectionRule(p, p1, this); case INTERSECT1: assert(e.second.size() == 2); p = *i; ++i; p1 = *i; return new IntersectionRule(p1, p, this); case GENERAL: assert(e.second.size() == 1); return new GeneralRule(*i, this); default: assert(false); } // Make compiler happy return 0; } void AdviseFast::RuleSet::removeRef(Coord p){ set::iterator i, j; for( i = j = _rules.begin(); i != _rules.end(); i = j) { ++j; if(i->second.count(p)) _rules.erase(i); } } void AdviseFast::RuleSet::addGeneral(Coord p){ this->removeRef(p); Entry e; e.first = GENERAL; e.second.insert(p); this->addRule(e); } #if defined(DEBUG) && DEBUG >= 2 int AdviseFast::Rule::leaks = 0; #endif AdviseFast::Rule::Rule(RuleSet *parent) : _parent(parent), _facts(parent->facts) { #if defined(DEBUG) && DEBUG >= 2 cout << "Rule::Rule, leaks = " << ++leaks << endl; #endif } AdviseFast::Rule::~Rule() { #if defined(DEBUG) && DEBUG >= 2 cout << "Rule::~Rule, leaks = " << --leaks << endl; #endif } AdviseFast::GeneralRule::GeneralRule( Coord fact, RuleSet *parent) : Rule(parent), _fact(fact) {} bool AdviseFast::GeneralRule::apply(CoordSet *) { #if defined(DEBUG) && DEBUG >= 2 operator <<( cout << "Applying general rule ", _fact) << endl; #endif // Return if there's no more such fact if(!_facts->count(_fact)) return false; Fact const &f = (*_facts)[_fact]; #if defined(DEBUG) && DEBUG >= 2 cout << f << endl; #endif // Insert intersection rules first // relatedFacts -- facts which have non-zero intersection CoordSet relatedFacts; { CoordSet::const_iterator i; for( i=f.pointSet.begin(); i!=f.pointSet.end(); ++i){ CoordSet const & ps = *_facts->getContainingFacts(*i); relatedFacts.insert( ps.begin(), ps.end()); } } relatedFacts.erase(_fact); // ;) CoordSet::iterator i; for( i=relatedFacts.begin(); i!=relatedFacts.end(); ++i) { RuleSet::Entry e; e.second.insert(_fact); e.second.insert(*i); e.first = RuleSet::INTERSECT1; _parent->addRule(e); e.first = RuleSet::INTERSECT; _parent->addRule(e); e.first = RuleSet::INCLUDE1; _parent->addRule(e); e.first = RuleSet::INCLUDE; _parent->addRule(e); } // Now simple rules, so that they appear first in the list RuleSet::Entry e; e.second.insert(_fact); e.first = RuleSet::FULL; _parent->addRule(e); e.first = RuleSet::EMPTY; _parent->addRule(e); // No point revealed, so... return false; } AdviseFast::EmptyRule::EmptyRule( Coord fact, RuleSet *parent) : Rule(parent), _fact(fact) {} bool AdviseFast::EmptyRule::apply( CoordSet *surePoints) { #if defined(DEBUG) && DEBUG >= 2 operator <<( cout << "Applying empty rule ", _fact) << endl; #endif if(!_facts->count(_fact)) return false; Fact const &f = (*_facts)[_fact]; #if defined(DEBUG) && DEBUG >= 2 cout << f << endl; #endif // FactSet does not contain empty facts!! assert(!f.pointSet.empty()); // If there are mines around, alas :( if(f.mines) return false; #if defined(DEBUG) && DEBUG >= 2 cout << "succeeded!" << endl; #endif surePoints->insert( f.pointSet.begin(), f.pointSet.end()); _parent->removeRef(_fact); return true; } AdviseFast::FullRule::FullRule( Coord fact, RuleSet *parent) : Rule(parent), _fact(fact) {} bool AdviseFast::FullRule::apply( CoordSet */*surePoints*/) { #if defined(DEBUG) && DEBUG >= 2 operator <<( cout << "Applying full rule ", _fact) << endl; #endif if(!_facts->count(_fact)) return false; Fact f = (*_facts)[_fact]; #if defined(DEBUG) && DEBUG >= 2 cout << f << endl; #endif // FactSet does not contain empty facts!! assert(!f.pointSet.empty()); // The point set is not full of mines... :( if(f.mines != (int)f.pointSet.size()) return false; #if defined(DEBUG) && DEBUG >= 2 cout << "succeeded!" << endl; #endif CoordSet affectedFacts; CoordSet::iterator i; for( i=f.pointSet.begin(); i!=f.pointSet.end(); ++i) _facts->mark(*i, &affectedFacts); for( i=affectedFacts.begin(); i!=affectedFacts.end(); ++i) _parent->addGeneral(*i); _parent->removeRef(_fact); // No mines revealed return false; } AdviseFast::InclusionRule::InclusionRule( Coord bigger, Coord smaller, RuleSet *parent) : Rule(parent), _bigger(bigger), _smaller(smaller) {} bool AdviseFast::InclusionRule::apply( CoordSet */*surePoints*/) { #if defined(DEBUG) && DEBUG >= 2 cout << "Applying inclusion rule "; operator <<(cout, _bigger) << ' '; operator <<(cout, _smaller) << endl; #endif if(!_facts->count(_bigger)) return false; if(!_facts->count(_smaller)) return false; Fact b = (*_facts)[_bigger]; Fact s = (*_facts)[_smaller]; #if defined(DEBUG) && DEBUG >= 2 cout << b << endl << s << endl; #endif assert(!s.pointSet.empty()); CoordSet diff; set_difference( s.pointSet.begin(), s.pointSet.end(), b.pointSet.begin(), b.pointSet.end(), inserter(diff, diff.begin())); if(!diff.empty()) // That is s is not included in b return false; #if defined(DEBUG) && DEBUG >= 2 cout << "succeeded!" << endl; #endif diff.clear(); set_difference( b.pointSet.begin(), b.pointSet.end(), s.pointSet.begin(), s.pointSet.end(), inserter(diff, diff.begin())); if(diff.empty()){ _facts->deleteFact(_bigger); _parent->removeRef(_bigger); } else { b.pointSet = diff; b.mines -= s.mines; _facts->addFact(_bigger, b); _parent->addGeneral(_bigger); } // No points revealed return false; } AdviseFast::IntersectionRule::IntersectionRule( Coord bigger, Coord smaller, RuleSet *parent) : Rule(parent), _bigger(bigger), _smaller(smaller) {} bool AdviseFast::IntersectionRule::apply( CoordSet *surePoints) { #if defined(DEBUG) && DEBUG >= 2 cout << "Applying intersection rule "; operator <<(cout, _bigger) << ' '; operator <<(cout, _smaller) << endl; #endif if(!_facts->count(_bigger)) return false; if(!_facts->count(_smaller)) return false; Fact b = (*_facts)[_bigger]; Fact s = (*_facts)[_smaller]; #if defined(DEBUG) && DEBUG >= 2 cout << b << endl << s << endl; #endif CoordSet diff; set_difference( b.pointSet.begin(), b.pointSet.end(), s.pointSet.begin(), s.pointSet.end(), inserter(diff, diff.begin())); if((int)diff.size() != b.mines - s.mines) // Oops :( return false; #if defined(DEBUG) && DEBUG >= 2 cout << "succeeded!" << endl; #endif CoordSet cross, diffs; set_difference( s.pointSet.begin(), s.pointSet.end(), b.pointSet.begin(), b.pointSet.end(), inserter(diffs, diffs.begin())); set_intersection( s.pointSet.begin(), s.pointSet.end(), b.pointSet.begin(), b.pointSet.end(), inserter(cross, cross.begin())); b.pointSet = diff; b.mines -= s.mines; _facts->addFact(_bigger, b); s.pointSet = cross; _facts->addFact(_smaller, s); { _parent->removeRef(_bigger); _parent->addGeneral(_smaller); RuleSet::Entry e; e.first = RuleSet::FULL; e.second.insert(_bigger); _parent->addRule(e); } if(diffs.empty()) return false; // Otherwise we have something to reveal!! surePoints->insert(diffs.begin(), diffs.end()); return true; }