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
Multi-filter for recipes in crafting menu #27500
Multi-filter for recipes in crafting menu #27500
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A good feature that I would certainly like to exist. Some review comments about specific parts of the code below.
Also, the help message will need to be updated to explain how this new aspect works.
src/recipe_dictionary.cpp
Outdated
} | ||
|
||
return res; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new recipe_subset::search
has a lot of code duplication with the existing one. It would be preferable to not duplicate this logic.
I think the simplest way to achieve that is to have the old function call the new one (rather than the other way around, as you currently have). Alternatively, both of them could call some third (new) function.
src/crafting_gui.cpp
Outdated
|
||
// Populate if the first query filter, reduce otherwise | ||
if( qry_begin == 0 ) { | ||
picking.swap( available ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using swap
to assign a vector
is entirely correct, but no longer necessary in a C++11 world. It would probably be less confusing to move-assign.
(Similarly for col_result
below)
src/crafting_gui.cpp
Outdated
if( qry_begin == 0 ) { | ||
picking.swap( available ); | ||
} else { | ||
std::set_intersection( available.begin(), available.end(), picking.begin(), picking.end(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
col_result
can be declared inside this else
block.
src/recipe_dictionary.h
Outdated
@@ -133,6 +133,10 @@ class recipe_subset | |||
/** Find recipes matching query (left anchored partial matches are supported) */ | |||
std::vector<const recipe *> search( const std::string &txt, | |||
const search_type key = search_type::name ) const; | |||
/** Find recipes matching query existing in subset of recipes (left anchored partial matches are supported) */ | |||
std::vector<const recipe *> search( const std::vector<const recipe *> subset, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit strange to be asking a recipe_subset
object to filter a different subset of recipes. The name suggests that the recipe_subset
already represents a subset of recipes. So this interface is confusing (though I don't blame you for taking this approach; it's straightforward).
I feel like a more logical solution (which requires more changes) is that recipe_subset::search
should not return a vector<recipe*>
, but instead return a new recipe_subset
object representing the new, smaller subset. Then you would not need to add this new function; it would simply be a matter of repeated search
calls. That would naturally fix some of my objections above.
This is just an idea; I haven't thought it through in detail; it may not work out in practice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works surprisingly well actually! Gets rid of that second search
function, made a new function reduce
that calls into search
before returning a recipe_subset
reducible by future reduce
calls :D
src/recipe_dictionary.cpp
Outdated
} | ||
} ); | ||
} else { // Subset is empty, populate from recipe_subset data | ||
res = search( txt, key ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the subset is empty you are resetting the search to search from all known recipes once more? Perhaps I have misunderstood, but that seems like it could lead to oddities. If the first few search terms filter down to zero results, then suddenly it will expand again to all recipes matching the next filter, effectively ignoring those first few search terms.
Edit: I see you abort the loop once the subset is empty, so this shouldn't happen. It's still confusing code, though. Is this alternative branch really needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good.
src/recipe_dictionary.cpp
Outdated
@@ -222,6 +168,37 @@ std::vector<const recipe *> recipe_subset::search( const std::string &txt, | |||
|
|||
return res; | |||
} | |||
static void insert_vector( const recipe_subset &src, recipe_subset &dst, const std::vector<const recipe *> &recipes ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be a recipe_subset
constructor, rather than a static member function (Assuming I'm correct in thinking that you only ever use it to insert into an empty recipe_subset
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your assumption is correct, only ever adding to an empty recipe_subset
. A constructor would take the const recipe_subset &src
and const std::vector<const recipe *> &recipes
arguments and transplant the functionality I guess.
recipe_subset
doesn't currently have a constructor so I would need to define additional constructors (empty/copy at minimum). This is the only situation where we have a possible want for a new constructor, and at the moment would only be useful in the reduce/intersection/difference functions.
Unless there is a broader requirement for new constructors I am reluctant to add one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
recipe_subset
doesn't currently have a constructor so I would need to define additional constructors (empty/copy at minimum). This is the only situation where we have a possible want for a new constructor, and at the moment would only be useful in the reduce/intersection/difference functions.
You don't need to add a copy constructor; the default continues to exist even if you define others. And the default constructor is just a one line recipe_subset() = default;
.
Not vital; I think it would be neater, but that's subjective.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah okay, then my argument against is mostly moot. I'll try out the addition of recipe_subset() = default;
and recipe_subset( const recipe_subset &src, const std::vector<const recipe *> );
constructors. Probably is neater, at the very least it should clean up the reduce
/intersection
/difference
functions a little.
a9cea01
to
05afce5
Compare
Summary
SUMMARY: Interface "Allow multiple filters for crafting recipes in crafting menu"
Purpose of change
Current implementation disallows filtering on more than one criteria at once. It is therefore impossible to filter for all recipes that use
leather
that also cover thetorso
, or filter for allsock
recipes that useyarn
. Multiple filters gives more flexibility to how the crafting recipe set can be queried.Describe the solution
Iterate over query string finding a chosen delimiter (comma) to generate query substrings to be processed. The first substring is processed using the current implementation to get an initial filtered recipe set. Remaining substrings are processed to reduce the current filtered recipe set towards a final filtered recipe set.
Additional context
Example usage of multiple filters to select only yarn-based socks: