Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add version of GetUnits to take a set of filters #98

Open
ImpulseCloud opened this issue Mar 18, 2021 · 3 comments
Open

Add version of GetUnits to take a set of filters #98

ImpulseCloud opened this issue Mar 18, 2021 · 3 comments
Labels
feature New feature or request

Comments

@ImpulseCloud
Copy link

Is your feature request related to a problem? Please describe.
Currently, only 1 type of Filter can be passed to GetUnits to return a filtered list of units. We then have to do additional manually filtering after the initial call.

Describe the solution you'd like
It would be great to use multiple filters in one call.

alkurbatov: "i.e. assuming that we have IsNonSaturatedTownHall, IsTownHall and IsFinished it would be convenient to use e.g. 'AllOf' predicate which uses inside all of these." -- "I suggest to add it ... in the form of a separate call like getUnits, but getUnitsAllOf with array of filters passed by reference. In this case the implementation will be much simpler."

Describe alternatives you've considered
Instead of an array of filters, allow sequential chaining composition. [e.g. .GetUnits( IsNonSaturated( IsFinished( IsTownHall())) ) ] A filter could take a filter input and output a compound filter.

References for different chaining syntaxes:
https://www.fluentcpp.com/2019/08/06/chaining-output-iterators-into-a-pipeline/
http://cpptruths.blogspot.com/2014/03/fun-with-lambdas-c14-style-part-1.html
https://stackoverflow.com/questions/8367879/c-lambda-expression-for-method-chains
https://chriskohlhepp.wordpress.com/advanced-c-lisp/lambda-over-lambda-in-cplusplus14/

@alkurbatov alkurbatov added the feature New feature or request label Mar 19, 2021
@alkurbatov alkurbatov added this to the v1.4.0 milestone Mar 19, 2021
@kubivan
Copy link

kubivan commented Jun 4, 2021

I'm working on api extensions, and resolved the problem in the following way:
https://github.com/kubivan/sc2-bot/blob/master/src/utils/UnitQuery.h
so, you can easily implement your own filters, even in compile time sometimes:

const auto is_mineral = type(UNIT_TYPEID::NEUTRAL_MINERALFIELD) || type(UNIT_TYPEID::NEUTRAL_MINERALFIELD750);
const auto is_resource = is_mineral || is_gas;
const auto resources_around_probe = obs->GetUnits(is_resource && in_radius(probe_pos, 10 ));

@Nickrader
Copy link
Contributor

Nickrader commented Oct 6, 2021

I assumed this issue meant we wanted a variable number of arguments to be passable to GetUnits (or similar function).
I started with looking at Variadic templates, but couldn't figure it out. Then more googling pointed me to std::initializer_list.

So I think I have the start of a solution with overloading GetUnits() using a std::initializer_list.
That way the user doesn't have to change the function to use lists.
I have only implemented a rudimentary test in tutorial bot to test it, seems to work.
I assume it is duplicating units in the pool should they fall into multiple filters.
The testing framework still will take me time to learn.

https://github.com/Nickrader/cpp-sc2/blob/iss_98/src/sc2api/sc2_client.cc

Units GetUnits(std::initializer_list<Filter> filters) const final;
Units ObservationImp::GetUnits(std::initializer_list<Filter> filters) const {
    Units units;
    std::initializer_list<Filter>::iterator it = filters.begin();
    for (it; it != filters.end(); ++it ) {
        const Filter arg = *it;
        unit_pool_.ForEachExistingUnit([&](Unit& unit) {
            if (arg(unit)) {
                units.push_back(&unit);
            }
        }
        );
    }
    return units;
}

https://github.com/Nickrader/cpp-sc2/blob/iss_98/include/sc2api/sc2_interfaces.h

    //! Get all units belonging to self that meet the conditions provided by the list of filters. The unit structure is const data only.
    //! Therefore editing that data will not change any in game state. See the ActionInterface for changing Unit state.
    //!< \param filter A functor or lambda used to filter out any unneeded units in the list.
    //!< \return A list of units that meet the conditions provided by the filter.
    virtual Units GetUnits(std::initializer_list<Filter>) const = 0;

Open on thoughts on where to go from here, or refinements to make, or if I am missing something and this isn't the right path.

@alkurbatov alkurbatov modified the milestones: v1.4.0, v1.4.1 Oct 7, 2021
@alkurbatov alkurbatov modified the milestones: v1.4.1, v1.4.2 Jan 8, 2022
@alkurbatov alkurbatov removed this from the v1.4.2 milestone Aug 6, 2022
@Nickrader
Copy link
Contributor

Nickrader commented Sep 29, 2022

Here is my new and improved attempt.
Nickrader@5129366

It lacks testing at the moment, beyond the simple test I put in Tutorial.cc

also, edited sc2_api.h for convenience, but that can be undone and include statements added in the working file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants