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; i<k; i++) ++it; return *it; } // Just a minimum probability logic here if( !probabilities.empty() ) { probability = probabilities.begin()->first; return probabilities.begin()->second; } // Otherwise the Field is already solved :) return Coord(-1,-1); }
void AdviseFast::FactSet::addFact( Coord const &point, Fact const &fact) { if(this->count(point)) this->deleteFact(point); Fact &f = ((*this)[point] = fact); // Remove marked points CoordSet marked; set_intersection( f.pointSet.begin(), f.pointSet.end(), _marked.begin(), _marked.end(), inserter(marked, marked.begin())); CoordSet::iterator i; for(i=marked.begin(); i!=marked.end(); ++i) f.pointSet.erase(*i); f.mines -= marked.size(); // Don't insert empty fact if(f.pointSet.empty()) { this->erase(point); return;} for(i=f.pointSet.begin(); i!=f.pointSet.end(); ++i) _containingFacts[*i].insert(point); }
void AdviseFull::EquationSet::normalize() { short i=0; set<short> empty; for(i=0; i<_maxPointSet; ++i){ if(!_pointSets.count(i)) continue; if(_pointSets[i].empty()){ this->substitute(i, empty); continue; } for(short j=i+1;j<_maxPointSet; ++j){ if(!_pointSets.count(j)) continue; if(_pointSets[j].empty()){ this->substitute(j, empty); continue; } CoordSet intersect; set_intersection( _pointSets[i].begin(), _pointSets[i].end(), _pointSets[j].begin(), _pointSets[j].end(), inserter(intersect, intersect.begin())); if(intersect.empty()) continue; CoordSet _i, _j; set_difference( _pointSets[i].begin(), _pointSets[i].end(), _pointSets[j].begin(), _pointSets[j].end(), inserter(_i, _i.begin())); set_difference( _pointSets[j].begin(), _pointSets[j].end(), _pointSets[i].begin(), _pointSets[i].end(), inserter(_j, _j.begin())); set<short> _ip, _jp; _ip.insert(_maxPointSet); _jp.insert(_maxPointSet); _pointSets[_maxPointSet++] = intersect; _ip.insert(_maxPointSet); _pointSets[_maxPointSet++] = _i; _jp.insert(_maxPointSet); _pointSets[_maxPointSet++] = _j; this->substitute(i, _ip); this->substitute(j, _jp); break; } } }
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 QTimer::singleShot(0, this, SLOT(solveStep())); return false; }
bool AdviseFast::FactSet::reveal( Coord point, CoordSet *affectedFacts) { // Tolerate :) if( !_field->isCovered(point) ) return true; // :) CoordList tmp; if(_field->doReveal(point, &tmp, 0) == false) // Blew up :( return false; CoordSet autorevealed; for (CoordList::const_iterator it = tmp.begin(); it!=tmp.end(); ++it) autorevealed.insert(*it); autorevealed.insert(point); affectedFacts->insert(autorevealed.begin(), autorevealed.end()); CoordSet::const_iterator i; for(i=autorevealed.begin(); i!=autorevealed.end(); ++i) { // I still think that each poing will belong to // at least one fact, but don't want to waste time // proving it :) if(_containingFacts.count(*i)){ CoordSet const &affF = _containingFacts[*i]; affectedFacts->insert( affF.begin(), affF.end()); for(CoordSet::const_iterator j=affF.begin(); j!=affF.end(); ++j) { (*this)[*j].pointSet.erase(*i); if((*this)[*j].pointSet.empty()) this->erase(*j); } _containingFacts.erase(*i); } Fact f; retrieveFact(*i, &f); this->addFact(*i, f); } return true; }
void AdviseFull::adviseFull( AdviseFast::FactSet *facts, CoordSet *surePoints, ProbabilityMap *probabilities) { EquationSet eqs(*facts); #if defined(DEBUG) && DEBUG >= 2 eqs.prettyprint(); #endif eqs.normalize(); #if defined(DEBUG) && DEBUG >= 2 eqs.prettyprint(); #endif list<EquationSet> eqss; eqs.separate(&eqss); #ifdef DEBUG {list<EquationSet>::iterator i; for(i=eqss.begin(); i!=eqss.end(); ++i) i->prettyprint(); } #endif // OK, uneffective, but simple :( surePoints->clear(); probabilities->clear(); // Get a fraction; float fraction; { BaseField const *f = facts->getField(); fraction = ((float)f->nbMines()) / (f->width() * f->height()); } /* From now on the first equation set on the list includes * the equation corresponding to "total" fact. This is the * first equation on the set. * * Give it a special treatment ;) */ if(!eqss.empty()) do { EquationSet prime = eqss.front(); EquationSet::Equation total = prime._equations.front(); prime._equations.pop_front(); list<EquationSet> prime_sep; prime.separate(&prime_sep); // Find a pool list<EquationSet::Equation>::iterator i = prime._equations.begin(); while(!prime._equations.empty()){ set<short>::iterator j; for( j = i->pointSets.begin(); j != i->pointSets.end(); ++j) prime._pointSets.erase(*j); i = prime._equations.erase(i); } assert(prime._pointSets.size() <= 1); if(prime._pointSets.size() == 0) break; short pool = prime._pointSets.begin()->first; CoordSet const &p = prime._pointSets[pool]; #ifdef DEBUG cout << "Prime equation set:" << endl << " separated into " << prime_sep.size() << endl << " pool size is " << p.size() << endl; #endif // Euristic // if( prime_sep.size () > 6 && p.size() >= prime_sep.size() * 10){ if(p.size() < (prime_sep.size()+1) * 10) // No special treatment!! break; // Actually, just substitute prime (!!!) eqss.pop_front(); eqss.insert(eqss.begin(), prime_sep.begin(), prime_sep.end()); prime._equations.clear(); EquationSet::Equation o; o.pointSets.insert(pool); // #### is the convertion right ? (NH) o.mines = (ushort)(fraction * p.size()); // A precaution if(o.mines == 0) o.mines = 1; // ;) prime._equations.push_front(o); eqss.push_front(prime); #ifdef DEBUG cout << "Specially treated:" << endl; { list<EquationSet>::iterator i; for(i=eqss.begin(); i!=eqss.end(); ++i) i->prettyprint(); } #endif } while (false); list<EquationSet>::const_iterator i; for(i=eqss.begin(); i!=eqss.end(); ++i){ CoordSet sp; ProbabilityMap pb; list<EquationSet::Solution> solutions; map<short, CoordSet> const &m = i->solve(&solutions); #ifdef DEBUG printf("Got solutions.\n"); #if defined(DEBUG) && DEBUG >= 2 { list<EquationSet::Solution>::iterator i; for( i = solutions.begin(); i != solutions.end(); ++i) { EquationSet::Solution::iterator j; for(j=i->begin(); j!=i->end(); ++j) printf("%d:\t%d\n", j->first, j->second); printf("\n"); } } #endif #endif //bool sure = AdviseFull::surePoints(m, solutions, &sp); surePoints->insert(sp.begin(), sp.end()); getProbabilities(m, solutions, &pb, fraction); probabilities->insert(pb.begin(), pb.end()); } // That's it return; }