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

Suggestion - query language for seed search #247

Open
IljaKosynkin opened this issue Oct 12, 2022 · 10 comments
Open

Suggestion - query language for seed search #247

IljaKosynkin opened this issue Oct 12, 2022 · 10 comments
Labels
enhancement New feature or request

Comments

@IljaKosynkin
Copy link

Problem
While the current search is pretty good I would like to be able to specify conditions in more precise and flexible way.

Describe the solution you'd like
I think the best solution would be to introduce an advanced search mode with query language to be able to test seeds against logical rules directly. For all I care, even JS code directly might be used with reference to the seed object which shall return a boolean.

Describe alternatives you've considered
None

Additional context
I tend to use search feature to find a good seed for long(ish) runs like 33 orb, all sun achievements etc.
Obviously, I would rather not spend 4 hours searching for a teleport bolt to then die from electric shock in water from my own "Electricity" perk because there was a pixel of poly in the pool of water (true story).

@IljaKosynkin IljaKosynkin added the enhancement New feature or request label Oct 12, 2022
@TwoAbove
Copy link
Owner

That's how the current search behaves: the AND OR and NOT are boolean operations. The rules return true when satisfied and false otherwise. So you can go as granular as you want

@IljaKosynkin
Copy link
Author

Maybe that's my programmer background speaking, but it does not seem like this for me. Or it rather hard to construct the query, at least from my perspective.
So for instance let's say I would like to find the seed with following properties:

  1. The first holy mountain should contain following perks: all-seeing eye, perk lottery and tinker with wands everywhere.
  2. I should be able to pick up all of the perks in the first holy mountain.
  3. The next two holy mountains should contain at least explosion and electric immunity (in any form).
  4. There should be projectile repulsion field and concentrated spells or hungry ghost somewhere.
  5. There should be fungal shifts that allow me to shift lava, acid, poison and ominous liquid and all types of polymorphine without shifts that would shift water or weird fungus itself in-between.
    Now maybe I misunderstand the way the current rules system works, but it seems like it would take quite a bit of effort and time to construct the ruleset properly. I'm not saying it would be trivial to describe all of the above in some query language, but it seems much easier to me.

@TwoAbove
Copy link
Owner

TwoAbove commented Oct 12, 2022

How do you envision this query language?
With the current setup, I think it can be something like this:

AND (
  perks: [1st: has these 3],
  lottery(not implemented): [...],
  OR (
    perks: [2nd: has one of ...],
    perks: [3rd: has one of ...]
  ),
  AND: (
    OR: (
      perks: [2nd: has repulsion_field],
      perks: [3rd: has repulsion_field],
      perks: [4th: has repulsion_field],
      perks: [5th: has repulsion_field],
      perks: [6th: has repulsion_field],
      perks: [7th: has repulsion_field],
    )
    OR: (
      OR: (
        perks: [2nd: has concentrated_spells],
        perks: [3rd: has concentrated_spells],
        perks: [4th: has concentrated_spells],
        perks: [5th: has concentrated_spells],
        perks: [6th: has concentrated_spells],
        perks: [7th: has concentrated_spells],
      ),
      OR: (
        perks: [2nd: has hungry_ghost],
        perks: [3rd: has hungry_ghost],
        perks: [4th: has hungry_ghost],
        perks: [5th: has hungry_ghost],
        perks: [6th: has hungry_ghost],
        perks: [7th: has hungry_ghost],
      )
    )
  ),
)

Not sure about 5, though

@TwoAbove
Copy link
Owner

There can be optimizations of the perk serch to reduce the ORs to a single rule

@IljaKosynkin
Copy link
Author

Well as you can see from your own example - that would take quite a bit of hopping in-between different windows wouldn't it?
Also, just out of curiosity, what was the reason for implementing builder style search? I, to be honest, would expect query language first and only than a UI wrapper around it for less tech-savvy users.
As for how it look like, I would see it as something like this:

// an object called 'seed' is provided implicitly and contains all the information about the seed
// ideally all names would be defined somewhere as constants and provided implicitly as well
const desired_first_row_perks = ["all_seeying_eye", "perk_lottery", "tinker_with_wands"];
const electric_immunity_perks = ["electricity", "electric_immunity"];
const explosion_immunity_perks = ["exploding_corpses", "explosion_immunity"];

const first_row_perks = seed.worlds[0].holy_mountains[0].perks.map(p => p.name);
const second_row_perks = seed.worlds[0].holy_mountains[1].perks.map(p => p.name);
const all_perks =  seed.worlds[0].holy_mountains.map(w => w.perks.map(p=>p.name)).flat();

const dangerous_materials = { "acid": false, "polymorphine": false, "lava": false, "omnious_liquid": false };
for (const shift in seed.fingal_shifts) {
     if (shift.from.includes("water") || shift.from.includes("weird_fungus")) break;
     let intersection = shift.from.filter(x => Object.keys(dangerous_materials).includes(x));
     if (intersection.length == 0) continue;
     dangerous_materials[intersection[0]] = true;
    if (Object.values(dangerous_materials).every(x => x)) break;
}

return first_row_perks.every(fp => desired_first_row_perks.includes(fp)) 
    && second_row_perks.some(sp => electric_immunity_perks.includes(sp))  
    && second_row_perks.some(sp => explosion_immunity_perks.includes(sp)) 
    && all_perks.includes("projectile_repulsion_field") 
    && (all_perks.includes("hungry_ghost") || all_perks.includes("concentrated_spells")) 
    && Object.values(dangerous_materials).every(x => x);

Just for the sake of simplicity I tried to use JS (even though I do not really know the language very well, as you can probably tell). IMO, just allowing user to write the code and then evaluating it is probably the easiest and fastest overall (not the safest though) option. However, arbitrary query language can be defined like JQL of Atlassian.
I also tried to present the readable version of the query; technically whole section above can be collapsed into a single logical statement, making it more "query-like" by the price of readability and performance.

@TwoAbove
Copy link
Owner

🤔 Thanks, this is interesting.
I've elected a drag-and-drop approach because it's very intuitive to do, and mobile-friendly.

I'm dissatisfied with the search as well, so I have the desire to redo it somehow, but don't have that many ideas as to how to make it both simpler and handle more complex scenarios.

I'll think about it after I finish the map gen stuff.

@IljaKosynkin
Copy link
Author

Oh it definitely is intuitive, you did great job on that front :)
Out of curiosity, does it really make sense to support search on mobile? As mobile developer myself I don't really see much point in doing quite a CPU intensive work on mobile which will cut battery life and lead to over-heating issues on some devices. I don't suggest to explicitly disable it, at the end of the day if you want to run CPU-intensive tasks on device that is really not meant to do those - it's your device and funeral, however I'm wondering why put additional focus on it

Well, I don't think "redoing" is necessary really. Current version is really good for simple searches and those will be used by majority of users I'm pretty sure. I do believe the best option would be to just add a "advanced mode" on top of current search functionality. From my experience it's pretty common for search features that are UI-based to have a fallback with query language of some sort. Aforementioned JQL is a good example.

Ye, I don't think it's super critical. The way I do it now is that I just pick the perks I need in the first mountain and manually check seeds to make sure fungal shifts and everything else is good. It's a little bit tedious, but since those seeds are meant for super long runs - it doesn't really matter in the end IMO.

@TwoAbove
Copy link
Owner

I wouldn't say it was the primary focus – I intentionally gather a very limited amount of info on usage, but do know that tablets are not that small of a % of users, so I had usability in mind there. Coding will definitely be unreasonable there, but hiding it behind an advanced flag (like perk gen) seems like a great idea.

I'll leave this ticket open to track progress on implementing something like JQL (I'll need to think hard about how to implement something like this client-side) and the advanced view

@denis-rossati
Copy link

This issue is gold. I was about to open a similar request feature because I too would enjoy advanced query (I didn't even realize that I needed a query language until I read this).

I'll leave my 5 cents here instead of opening a new issue: it would be delightful if this feature included some kind of "have to have X somewhere". For example, I wish I could have a run with 4 more love perks, but today I don't have a way to query "the seed have to have 'more love' perk in the first 5 rolls in distinct levels in the holy moutain" (or at least, don't know how to query it), so this feat would be pretty neat.

One last point. As a noita addicted and open source lover, I'm looking foward to start to colaborate in this project. I'm frequently taking a look at the open issues, if there is some "good first issue" around here, let me know :)

@TwoAbove
Copy link
Owner

Cool! Thanks @denis-rossati
I'll go through the issues, add comments, and make it more contribution-friendly. (there is a long-running branch called map-gen-updates that has lots of changes and I'll merge it in next week)

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

No branches or pull requests

3 participants