Beispiel #1
0
results::WordsVector Searches::advance(
    std::string query,
    std::string lang,
    int size,
    int offset
) {
    SearchResults resultIds = SearchEngine::get_instance()->search(
        query,
        lang,
        size,
        offset
    );
    
    results::WordsVector wordsVector(resultIds.size());

    models::Words wordsModel;

    int resultSize = resultIds.size();
    for (int i = 0; i < resultSize; ++i) {
        wordsVector[i] = wordsModel.get_word_with_id(
            resultIds[i]
        );
    }
    wordsVector.offset = offset;
    wordsVector.maxsize = resultIds.maxsize;
    return wordsVector;
}
Beispiel #2
0
void testSingleSearch()
{
	StarcraftState init(true);
	//init.doAction(DATA.getAction(BWAPI::UnitTypes::Zerg_Drone), init.resourcesReady(DATA.getAction(BWAPI::UnitTypes::Zerg_Drone)));
	//init.doAction(DATA.getAction(BWAPI::UnitTypes::Zerg_Drone), init.resourcesReady(DATA.getAction(BWAPI::UnitTypes::Zerg_Drone)));
	//init.doAction(DATA.getAction(BWAPI::UnitTypes::Zerg_Drone), init.resourcesReady(DATA.getAction(BWAPI::UnitTypes::Zerg_Drone)));
	//init.doAction(DATA.getAction(BWAPI::UnitTypes::Zerg_Drone), init.resourcesReady(DATA.getAction(BWAPI::UnitTypes::Zerg_Drone)));
	//init.doAction(DATA.getAction(BWAPI::UnitTypes::Zerg_Spawning_Pool), init.resourcesReady(DATA.getAction(BWAPI::UnitTypes::Zerg_Spawning_Pool)));
	//init.doAction(DATA.getAction(BWAPI::UnitTypes::Zerg_Extractor), init.resourcesReady(DATA.getAction(BWAPI::UnitTypes::Zerg_Extractor)));

	init.printData();

	SearchParameters params(defaultZergGoal(), init, StarcraftSearchConstraints());

	//params.goal.setGoal( DATA.getAction(BWAPI::UnitTypes::Zerg_Zergling), 14);
	//params.goal.setGoal( DATA.getAction(BWAPI::UnitTypes::Zerg_Drone), 9);
	params.goal.setGoal( DATA.getAction(BWAPI::UnitTypes::Zerg_Mutalisk), 4);
	params.goal.setGoalMax( DATA.getAction(BWAPI::UnitTypes::Zerg_Overlord), 3);
	params.goal.setGoalMax( DATA.getAction(BWAPI::UnitTypes::Zerg_Drone), 12);

	params.useRepetitions = true;

	DFBBStarcraftSearch SCSearch(params);

	SearchResults result = SCSearch.search();
	
	//if (result.solved)
	//{
		result.printResults(true);
	//}
}
Beispiel #3
0
static void search_utemplate(br_const_utemplate query, br_callback_context)
{
    SearchResults *searchResults = new FaceRecognition(query);
    foreach (const MappedGallery &gallery, galleries)
        br_iterate_utemplates(reinterpret_cast<br_const_utemplate>(gallery.data), reinterpret_cast<br_const_utemplate>(gallery.data + gallery.size), compare_utemplates, searchResults);
    searchResults->print();
    delete searchResults;
}
Beispiel #4
0
void testSmartSearch() {
    // default state
    StarcraftState initialState(true);

    SmartStarcraftSearch sss;
    sss.addGoal(DATA.getAction(BWAPI::UnitTypes::Protoss_Carrier), 1);
    //sss.addGoal(DATA.getAction(BWAPI::UpgradeTypes::Carrier_Capacity), 1);
    sss.setState(initialState);

    // do the search
    SearchResults result = sss.search();

    if (result.solved) {
        result.printResults(true);
    }
}
Beispiel #5
0
inline void gatherResultstoProcZero(MPI_Comm comm, SearchResults& boxIdPairResults)
{
    int procId=-1;
    MPI_Comm_rank(comm, &procId);

    int numProc=-1;
    MPI_Comm_size(comm, &numProc);

    int procIdDestination = 0;
    stk::CommAll gather(comm);
    for (int phase=0; phase<2; ++phase)
    {
        if ( procId != procIdDestination )
        {
            for (size_t j=0;j<boxIdPairResults.size();++j)
            {
                gather.send_buffer(procIdDestination).pack< std::pair<Ident, Ident> >(boxIdPairResults[j]);
            }
        }

        if (phase == 0) { //allocation phase
          gather.allocate_buffers( numProc / 4 );
        }
        else { // communication phase
          gather.communicate();
        }
    }

    if ( procId == procIdDestination )
    {
        for ( int p = 0 ; p < numProc ; ++p )
        {
            stk::CommBuffer &buf = gather.recv_buffer( p );
            while ( buf.remaining() )
            {
                std::pair<Ident, Ident> temp;
                buf.unpack< std::pair<Ident, Ident> >( temp );
                boxIdPairResults.push_back(temp);
            }
        }
    }
}
Beispiel #6
0
yaml::Mapping CyclopsMaster::reduce(const PendingRequest& results) {
  // for getPoint, we should get errors from all the dataset parts except the one that
  // actually contained it
  if (results.request["method"] == "getPoint") {
    for (int i=0; i<results.replies.size(); i++) {
      if (results.replies[i].contains("result")) {
        return results.replies[i];
      }
    }
  }

  // for getPoints, we need to get all the datasets we got back (if any), and merge
  // them together before returning the result. If the total number of points is different
  // from the number of points we asked, we need to get which are the missing ones and return
  // an error message with that
  if (results.request["method"] == "getPoints") {
    // enclose all of this inside a try/catch block, so that if any error occurs (such as
    // invalid arguments) we just fall through to the normal reduce/sendReply which will
    // send the correct error message back to the client
    // FIXME: this is just a temporary hack, a correct solution would imply a more in-depth
    //        refactoring of how arguments are checked
    try {
      if (results.request["params"].sequence().size() < 2) throw InvalidParams();
      return reduceGetPoints(results.replies, results.request["params"][1].sequence());
    }
    catch (...) {}
    /*
    DataSet resultds;
    for (int i=0; i<results.replies.size(); i++) {
      // all replies should contain result, even if only an empty dataset
      DataSet ds;
      ds.fromBase64(results.replies[i]["result"].scalar().toAscii());
      resultds.appendDataSet(&ds);
    }
    if (resultds.size() == results.request["params"][1].sequence().size()) {
      yaml::Mapping result(results.replies[0]);
      result["result"] = resultds.toBase64();
      return result;
    }

    // need to find the missing points
    QSet<QString> asked;
    foreach (const yaml::Node& n, results.request["params"][1].sequence()) asked << n.scalar();
    QSet<QString> found = QSet<QString>::fromList(resultds.pointNames());
    QStringList notfound = (asked - found).toList();

    yaml::Mapping result;
    result.insert("id", results.request["id"]);
    result.insert("error", QString("Following points could not be found: ") + notfound.join(", "));
    return result;
    */
  }

  // first check there has been no errors, otherwise return that as a common answer
  for (int i=0; i<results.replies.size(); i++) {
    if (results.replies[i].contains("error")) {
      return results.replies[i];
    }
  }

  // for size queries, we need to sum up the size of all parts
  if (results.request["method"] == "size") {
    int total = 0;
    for (int i=0; i<results.replies.size(); i++) {
      total += results.replies[i]["result"].scalar().toInt();
    }

    yaml::Mapping result;
    result.insert("id", results.request["id"]);
    result.insert("result", QString::number(total));

    return result;
  }

  // for chainedSearch queries, we need to merge the results now, only keeping the best ones
  if (results.request["method"] == "chainedSearch") {
    /*
    SearchResults allResults;
    for (int i=0; i<results.replies.size(); i++) {
      const yaml::Sequence& result = results.replies[i]["result"].sequence();
      for (int j=0; j<result.size(); j++) {
        allResults << Result(result[j][0].scalar(), result[j][1].scalar().toFloat());
      }
    }

    sort(allResults.begin(), allResults.end(), cmpSearchResults);
    */
    CyclopsResults allResults;

    for (int i=0; i<results.replies.size(); i++) {
      const yaml::Sequence& result = results.replies[i]["result"]["results"].sequence();
      const yaml::Sequence& values = results.replies[i]["result"]["values"].sequence();

      for (int j=0; j<result.size(); j++) {
        QList<QVariant> vals;
        int vsize = values[j].sequence().size();
        for (int k=0; k<vsize; k++) vals << values[j][k].scalar();

        allResults.append(Result(result[j][0].scalar(), result[j][1].scalar().toFloat()),
                          vals);
      }
    }
    allResults.sort();

    int nresults = results.request["params"][2].scalar().toInt();
    int offset   = results.request["params"][3].scalar().toInt();
    allResults.mid(offset, qMin(allResults.size()-offset, nresults));

    yaml::Mapping result = results.replies[0];
    result["result"] = toYaml(allResults);
    // add the header only now, to avoid a conversion yaml -> QVariant -> yaml
    result["result"]["header"] = results.replies[0]["result"]["header"];

    return result;
  }

  // for nnSearch queries, we need to merge the results now, only keeping the best ones
  if (results.request["method"].scalar().startsWith("nnSearch")) {
    SearchResults allResults;
    for (int i=0; i<results.replies.size(); i++) {
      const yaml::Sequence& result = results.replies[i]["result"].sequence();
      for (int j=0; j<result.size(); j++) {
        allResults << Result(result[j][0].scalar(), result[j][1].scalar().toFloat());
      }
    }

    sort(allResults.begin(), allResults.end(), cmpSearchResults);
    int npos = 3;
    if (results.request["method"].scalar().endsWith("Filter")) npos = 4;
    int nresults = results.request["params"][npos].scalar().toInt();
    allResults = allResults.mid(0, qMin(allResults.size(), nresults));

    yaml::Mapping result = results.replies[0];
    result["result"] = toYaml(allResults);

    return result;
  }

  // for queries that return None, we can return the first one
  // for datasetNames, distanceNames and layout, we assume all results are the same and return the first one
  return results.replies[0];

}
Beispiel #7
0
static void compare_utemplates(br_const_utemplate target, br_callback_context context)
{
    SearchResults *searchResults = (SearchResults*) context;
    searchResults->consider(target);
}
void SearchVideos::run()
{
	// search started
	emit searchStarted();
	// stop getting previews
	imageCatcher->stop();
	// clear previous results
	searchResults->removeAllSearchResults();
	// has plugins to search?
	if (internalPluginsIds.count() == 0)
	{
		// search finished
		emit searchFinished();
		// abort process
		return;
	}
	// build the plugins search list
	QList<VideoInformationPlugin *> plugins;
	// check which plugins goes into the list
	if (internalPluginsIds.at(0) == SEARCH_ID_ALL) // all plugins
		plugins.append(VideoInformation::instance()->getAllSearchPlugins());
	else if (internalPluginsIds.at(0) == SEARCH_ID_STANDARD) // all standard plugins
		plugins.append(VideoInformation::instance()->getAllSearchStandardPlugins());
	else if (internalPluginsIds.at(0) == SEARCH_ID_ADULTS) // all adult plugins
		plugins.append(VideoInformation::instance()->getAllSearchAdultPlugins());
	else if (internalPluginsIds.count() == 1) // single search
		plugins.append(VideoInformation::instance()->getRegisteredPlugin(internalPluginsIds.at(0)));
	else // custom search, so add them...
		for (int n = 0; n < internalPluginsIds.count(); n++)
			plugins.append(VideoInformation::instance()->getRegisteredPlugin(internalPluginsIds.at(n)));
	// if adult sites are disabled, then remove them from list
	if (VideoInformation::instance()->getBlockAdultContent())
		for (int n = plugins.count() - 1; n >= 0; n--)
			if (plugins.at(n)->hasAdultContent())
				plugins.removeAt(n);
	// inits
	int lastCount = 0;
	// start to search
	while (!plugins.isEmpty())
	{
		VideoInformationPlugin *plugin = plugins.takeFirst();

		if (plugin != NULL)
		{
			// execute search into current thread
			SearchResults results = plugin->searchVideos(internalKeyWords, internalPage);
			// check if we are destroying the searchResults (if yes, then abort the process)
			if (destroying) return;
			// add results
			searchResults->addSearchResults(results);
			searchResults->setSummary(results.getSummary());
			// add new search block
			emit addNewSearchBlock(plugin);
			// has results?
			if (searchResults->getSearchResultCount() == 0)
			{
				// emit add no results
				emit searchResultAdded(NULL);
				// next search...
				continue;
			}
			// show results
			for (int n = lastCount; n < searchResults->getSearchResultCount(); n++)
			{
				// emit add result
				emit searchResultAdded(searchResults->getSearchResult(n));
				// add to previews download previews
				imageCatcher->addPreview(searchResults->getSearchResult(n));
			}
		}
		// update last count
		lastCount = searchResults->getSearchResultCount();
	}
	// search finished
	emit searchFinished();
}
bool
NavOneSearchHandler::handleOneSearch( NavRequestData& rd ) {
    if ( !checkExpectations( rd.params, rd.reply ) ) {
        return false;
    }

    // The user
    UserUser* user = rd.session->getUser()->getUser();
    uint32 startTime = TimeUtility::getCurrentTime();
    uint32 now = TimeUtility::getRealTime();

    bool ok = true;

    // AURA
    set< uint32 >* allowedMaps = NULL;
    if ( !m_thread->getMapIdsForUserRegionAccess( user, allowedMaps,
            now, rd.urmask ) )
    {
        mc2log << warn << "handleOneSearch: "
               << "getMapIdsForUserRegionAccess failed. ";
        if ( TimeUtility::getCurrentTime() - startTime > 3000 ) {
            rd.reply->setStatusCode(
                NavReplyPacket::NAV_STATUS_REQUEST_TIMEOUT );
            mc2log << "Timeout";
        } else {
            rd.reply->setStatusCode( NavReplyPacket::NAV_STATUS_NOT_OK );
            mc2log << "Error";
        }
        mc2log << endl;
        ok = false;
    }
    delete allowedMaps;

    // Start parameter printing
    mc2log << info << "handleOneSearch:";
    CompactSearch params;
    params.m_oneResultList = true;
    params.m_itemInfoFilter = ItemInfoEnums::OneSearch_All;

    params.m_language = rd.clientLang;
    mc2log << " Lang " << StringTable::getString(
               StringTable::getLanguageAsStringCode( rd.stringtClientLang ),
               StringTable::ENGLISH );
    if ( getParam( 6805, params.m_round, rd.params ) ) {
        mc2log << " Round " << params.m_round;
    }
    if ( getParam( 6804, params.m_maxHits, rd.params ) ) {
        mc2log << " MAX " << params.m_maxHits;
    }
    if ( getParam( 6800, params.m_what, rd.params ) ) {
        mc2log << " What " << params.m_what;
    }
    if ( NavParamHelper::getMC2CoordAndAngle( rd.params.getParam( 6802 ),
            params.m_location.m_coord,
            params.m_location.m_angle ) ) {
        mc2log << " Pos " << params.m_location.m_coord;
    }
    if ( getParam( 6803, params.m_distance, rd.params ) ) {
        mc2log << " Dist " << params.m_distance;
    } else if ( params.m_location.isValid() ) {
        // default 100km for distance
        params.m_distance = 100000;
        mc2log << " Dist " << params.m_distance;
    }

    if ( ! getParam( 6806, params.m_includeInfoItem, rd.params ) ) {
        params.m_includeInfoItem = true;
    }

    if ( params.m_includeInfoItem ) {
        mc2log << " include info fields ";
    }

    // Get the sorting type
    params.m_sorting = SearchTypes::DistanceSort;
    int32 sortType;
    if ( getParam( 6807, sortType, rd.params ) ) {
        mc2log << " Sort " << sortType;
        if( sortType == 1 ) {
            params.m_sorting = SearchTypes::AlphaSort;
        }
    }

    // Search category
    const NParam* p = rd.params.getParam( 6801 );
    if ( p != NULL ) {
        uint32 length = p->getLength();
        params.m_categoryIDs.resize( length );
        for ( uint32 i = 0; i < length; ++i ) {
            params.m_categoryIDs.push_back( p->getInt32( i ) );
        }
    }

    if ( rd.reqVer >= 2 ) {
        if ( getParam( 6808, params.m_where, rd.params ) ) {
            mc2log << " Where " << params.m_where;
        }

        if ( getParam( 6809, params.m_topRegionID, rd.params ) ) {
            mc2log << " TopRegionID " << params.m_topRegionID;
        }

        int32 searchType;
        if ( getParam( 6810, searchType, rd.params ) ) {
            if ( searchType == 0x1 && params.m_round == 0 ) {
                mc2log << " Address search ";
                params.m_heading = 1; // Address heading
            }
        }
    }

    // strip any leading and trailing white space from input
    params.cleanInput();

    // Validate input fields
    if ( ! params.validInput() ) {
        rd.reply->setStatusCode( NavReplyPacket::NAV_STATUS_PARAMETER_INVALID );
        rd.reply->setStatusMessage( "Invalid input" );
        ok = false;
    }

    // End parameter printing
    mc2log << endl;

    // Set end index from max nbr hits and start index
    params.m_startIndex = 0;
    params.m_endIndex = params.m_maxHits - 1;

    // Make request
    typedef STLUtility::AutoContainerMap<
    SearchParserHandler::SearchResults > SearchResults;
    SearchResults results;
    if ( ok ) {
        results = m_thread->getSearchHandler().compactSearch( params );
        for ( SearchResults::const_iterator it = results.begin() ;
                it != results.end() ; ++it ) {
            if ( (*it).second->getSearchResultRequest()->getStatus() !=
                    StringTable::OK ) {
                mc2log << "handleOneSearch: compactSearch Heading "
                       << (*it).first << " failed: ";
                if ( (*it).second->getSearchResultRequest()->getStatus() ==
                        StringTable::TIMEOUT_ERROR ) {
                    mc2log << " REQUEST_TIMEOUT";
                    rd.reply->setStatusCode(
                        NavReplyPacket::NAV_STATUS_REQUEST_TIMEOUT );
                } else if ( (*it).second->getSearchResultRequest()->getStatus() ==
                            StringTable::OUTSIDE_ALLOWED_AREA ) {
                    mc2log << " OUTSIDE_ALLOWED_AREA";
                    rd.reply->setStatusCode(
                        NavReplyPacket::NAV_STATUS_OUTSIDE_ALLOWED_AREA );
                } else {
                    mc2log << " NOT_OK";
                    rd.reply->setStatusCode(
                        NavReplyPacket::NAV_STATUS_NOT_OK );
                }
                if ( params.m_round == 1 &&
                        (*it).second->getSearchResultRequest()->getStatus() !=
                        StringTable::OUTSIDE_ALLOWED_AREA ) {
                    mc2log << " BUT round 1 (ExternalSearch) so we ignore";
                    rd.reply->setStatusCode( NavReplyPacket::NAV_STATUS_OK );
                } else {
                    ok = false;
                }
                mc2log << endl;
            }
        }
    }

    // Put reply together
    if ( ok ) {
        // one search only returns one heading in the list...
        SearchResults::const_iterator it = results.begin();
        if ( it != results.end() ) {
            const SearchResultRequest* match =
                (*it).second->getSearchResultRequest();
            const vector<VanillaMatch*>& matches = match->getMatches();
            uint32 numberMatches = MIN( params.m_maxHits, matches.size() );

            rd.rparams.addParam( NParam( 6900, numberMatches ) );
            rd.rparams.addParam( NParam( 6901, match->getTotalNbrMatches() ) );

            if ( numberMatches > 0 ) {
                using namespace OneSearchUtils;
                BinarySearchResult binaryResult;
                serializeResults( matches.begin(),
                                  matches.begin() + numberMatches,
                                  m_thread->getSearchHandler(),
                                  &binaryResult );

                // Add SearchStringTable
                addDataBuffer( 6902, rd.rparams, binaryResult.m_stringTable.get() );

                // Add AreaTable
                addDataBuffer( 6903, rd.rparams, binaryResult.m_areaTable.get() );

                // Add infoItemTable
                addDataBuffer( 6904, rd.rparams, binaryResult.m_infoItemTable.get() );

                // Add Matches
                addDataBuffer( 6905, rd.rparams, binaryResult.m_matchesTable.get() );
            } else {
                // No hits. Add empty arrays
                rd.params.addParam( NParam( 6902 ) );
                rd.params.addParam( NParam( 6903 ) );
                rd.params.addParam( NParam( 6904 ) );
                rd.params.addParam( NParam( 6905 ) );
            }
        }
    }

    return ok;
}
	// recursive function which does all search logic
	void DFBB(StarcraftState & s, int depth)
	{		
		// increase the node expansion count
		nodesExpanded++;
		
		// if we have constraints and they are not met
		if (params.useConstraints && !s.meetsConstraints(params.ssc))
		{
			// this state is not legal
			return;
		}
	
		// the time at which the last thing in the queue will finish
		int finishTime = s.getLastFinishTime();
		
		/*int lookupVal = TT.lookup(s.hashAllUnits(1), s.hashAllUnits(2));
		if (lookupVal != -1 && lookupVal < finishTime)
		{
		    ttcuts++;
		    //return;
		}

		TT.save(s.hashAllUnits(1), s.hashAllUnits(2), finishTime);*/

		// if we already have completed the units for the goal, don't worry about last finish time
		if (s.meetsGoalCompleted(params.goal))
		{
			finishTime = s.getCurrentFrame();
		}

		// if we have met the goal, we're good
		if (s.meetsGoal(params.goal)) 
		{
			// if it's better than the current best solution, set the new best
			if (finishTime < upperBound)//  || ((finishTime == upperBound) && (s.getWorkerCount() > winnerWorkerCount))) 
			{
				// set the winning info
				upperBound = finishTime;
				winner = s;
				winnerFound = true;
				winnerWorkerCount = s.getWorkerCount();

				results = SearchResults(true, upperBound, nodesExpanded, searchTimer.getElapsedTimeInMilliSec(), s.getBuildOrder());
				results.upperBound = s.calculateUpperBoundHeuristic(params.goal);
				results.lowerBound = s.eval(params.goal);
				results.avgBranch = numChildren / (double)numGenerations;
				results.minerals = s.getFinishTimeMinerals();
				results.gas = s.getFinishTimeGas();
				
				results.saveState = SearchSaveState(getBuildOrder(s), upperBound);
				
				//graphVizOutput(s, true);
				results.printResults(true);
				
				s.printData();

				return;
			}
		}
		
		// if we are using search timeout and we are over the limit
		// (nodesExpanded % 1000 == 0) only checks the time every 1000 expansions, since it is slow
		if (params.searchTimeLimit && (nodesExpanded % 200 == 0) && (searchTimer.getElapsedTimeInMilliSec() > params.searchTimeLimit))
		{
			results.saveState = SearchSaveState(getBuildOrder(s), upperBound);
			//results.saveState.print();
		
			// throw an exception to unroll the recursion
			throw 1;
		}
		
		// get the legal action set
		ActionSet legalActions = s.getLegalActions(params.goal); 

		// only use relevant actions
		legalActions = legalActions & relevantActions;
		
		// if we enabled the supply bounding flag
		if (params.useSupplyBounding)
		{
			// if we are more than 2 supply providers in the lead 
			if ((s.getMaxSupply() - s.getCurrentSupply()) >= params.supplyBoundingThreshold*DATA[DATA.getSupplyProvider()].supplyProvided())
			{
				// make supply providers illegal
				legalActions.subtract(DATA.getSupplyProvider());
			}
		}
		
		// if we enabled the always make workers flag, and workers are legal
		if (params.useAlwaysMakeWorkers && !params.goal[DATA.getWorker()] && legalActions[DATA.getWorker()])
		{
			ActionSet tempLegal(legalActions);
			ActionSet legalBeforeWorker;
			
			// compute when the next worker will be trainable
			int workerReady = s.resourcesReady(DATA.getWorker());
			
			// for each other legal action
			while (!tempLegal.isEmpty())
			{
				Action nextAction = tempLegal.popAction();
				
				// if the action will be ready before the next worker
				if (s.resourcesReady(nextAction) <= workerReady)
				{
					// it's legal
					legalBeforeWorker.add(nextAction);
				}
			}
			
			// update the legal actions
			legalActions = legalBeforeWorker;
		}
		
		// if we enabled the use worker cutoff flag and we're above the cutoff
		if (params.useWorkerCutoff && s.getCurrentFrame() > (params.workerCutoff * upperBound))
		{
			// workers are no longer legal
			legalActions.subtract(DATA.getWorker());

			// if we have enough supply for the remaining goal
			if (s.hasEnoughSupplyForGoal(params.goal))
			{
				// make supply providers illegal
				legalActions.subtract(DATA.getSupplyProvider());
			}
		}	

		// if we have children, update the counter
		if (!legalActions.isEmpty())
		{
			numGenerations += 1;
			numChildren += legalActions.numActions();
		}
		
		// load the save state if we are using it
		if (params.useSaveState && !finishedLoadingSaveState)
		{
			// if we are under the saved depth, load accordingly
			if (depth < params.saveState.getDepth())
			{
				// pop actions until the NEXT action is the one we want to start on
				while (!legalActions.isEmpty() && legalActions.nextAction() != params.saveState[depth])
				{
					legalActions.popAction();
				}
			}
			// if we are over the depth, we are finished loading
			else
			{
				finishedLoadingSaveState = true;
			}
		}
		
		// children of this state in the search
		std::vector<StarcraftState> childStates;

		// while there are still legal actions to perform
		while (!legalActions.isEmpty()) 
		{				
			// get the next action
			Action nextAction = legalActions.popAction();
			
			// when this action would finish
			int actionFinishTime = s.resourcesReady(nextAction) + DATA[nextAction].buildTime();
			
			// heuristic value of the goal state
			int heuristicTime = s.getCurrentFrame() + s.eval(params.goal, params.useLandmarkLowerBoundHeuristic);
			
			// the h value for this node
			int h = (actionFinishTime > heuristicTime) ? actionFinishTime : heuristicTime;
			
			// primary cut-off, very quick heuristic
			if (h <= upperBound)
			{
				bool stillLegal = true;
				StarcraftState child(s);
				
				// set the repetitions if we are using repetitions, otherwise set to 1
				int repeat = params.useRepetitions ? params.getRepetitions(nextAction) : 1;
				
				// if we are using increasing repetitions
				if (params.useIncreasingRepetitions)
				{
					// if we don't have the threshold amount of units, use a repetition value of 1
					repeat = child.getNumUnits(nextAction) >= params.getRepetitionThreshold(nextAction) ? repeat : 1;
				}
				
				// make sure we don't repeat to more than we need for this unit type
				if (params.goal.get(nextAction))
				{
					repeat = (std::min)(repeat, params.goal.get(nextAction) - child.getNumUnits(nextAction));
				}
				else if (params.goal.getMax(nextAction))
				{
					repeat = (std::min)(repeat, params.goal.getMax(nextAction) - child.getNumUnits(nextAction));
				}

				// limit repetitions to how many we can make based on current used supply
				if (DATA[nextAction].supplyRequired() > 0)
				{
					int haveSupplyFor = (s.getMaxSupply() + s.getSupplyInProgress() - s.getCurrentSupply()) / DATA[nextAction].supplyRequired();

					repeat = (std::min)(repeat, haveSupplyFor);
				}
				
				// if we're not finished loading the state, repeat value is 1
				if (params.useSaveState && !finishedLoadingSaveState)
				{
					repeat = 1;
				}

				// for each repetition of this action
				for (int r = 0; r < repeat; ++r)
				{
					// if the action is still legal
					if (child.isLegal(nextAction, params.goal))
					{						
						int readyTime = child.resourcesReady(nextAction); 
						child.doAction(nextAction, readyTime);
					}
					// if it's not legal, break the chain
					else
					{
						stillLegal = false;
						break;
					}
				}
				
				// if all actions in a row are legal, recurse on the child
				if (stillLegal)
				{
					child.setParent(&s);
					child.setActionPerformedK((UnitCountType)repeat);
					//DFBB(child, depth+1);
					childStates.push_back(child);
				}
			}
		}	
		
		//std::sort(childStates.begin(), childStates.end(), StarcraftStateCompare<StarcraftStateType>(params));
		//std::random_shuffle(childStates.begin(), childStates.end());
		for (size_t i(0); i<childStates.size(); ++i)
		{
		    DFBB(childStates[i], depth+1);
		}
	}