Feature - Implemented maximize() that returns suggested items, skills, etc

roippi

Developer
Discussion split from BCC's thread starting here.

After thinking about this for a little bit, I went through and coded up something in an hour or two:

Code:
> ash maximizeTEST( "mox", true);

Maximizing...
15552 combinations checked, best score 2,367.00
Returned: aggregate int [string]
...or acquire & use 1 Breath mint => 43
...or acquire & use 1 flask of porquoise juice => 436
...or acquire & use 1 vial of porquoise juice => 436
...or use 1 Crimbo candied pecan => 43
...or use 1 Tasty Fun Good rice candy => 43
...or use Crimbo fudge => 43
...or use Crimbo peppermint bark => 43
acquire & use 1 banana smoothie => 40
acquire & use 1 bottle of pirate juice => 100
acquire & use 1 Climate Colada => 261
acquire & use 1 Connery's Elixir of Audacity => 1744
acquire & use 1 dubious peppermint => 87
acquire & use 1 extra-potent gremlin mutagen => 436
acquire & use 1 floaty sand => 5
acquire & use 1 green candy heart => 3
acquire & use 1 gremlin mutagen => 218
acquire & use 1 gummi canary => 100
acquire & use 1 hair of the fish => 5
acquire & use 1 jellyfish gel => 261
acquire & use 1 jug of porquoise juice => 436
acquire & use 1 lavender candy heart => 3
acquire & use 1 lime supersucker => 174
acquire & use 1 Lobos Mints => 741
acquire & use 1 love song of icy revenge => 1
acquire & use 1 love song of naughty innuendo => 1
acquire & use 1 lump of Saccharine Maple sap => 872
acquire & use 1 mariachi toothpaste => 436
acquire & use 1 potion of temporary gr8tness => 872
acquire & use 1 powdered toad horn => 87
acquire & use 1 pressurized potion of pulchritude => 2616
acquire & use 1 sensitive poetry journal => 174
acquire & use 1 shaving cream => 5
acquire & use 1 sugar-coated pine cone => 43
acquire & use 1 toothbrush => 1
acquire & use 1 Ultrasoldier Serum => 872
acquire & use 1 unstable DNA => 87
acquire & use 1 yellow candy heart => 3
ballpit => 872
buy & use 1 Black Body™ spray => 87
buy & use 1 pirate pamphlet => 87
cast 1 The Moxious Madrigal => 10
concert Elvish => 87
equip acc1 plexiglass pendant => 261
equip acc2 Hodgman's bow tie => 174
equip acc3 stainless steel suspenders => 131
equip back Misty Cape => 5
equip familiar bugged balaclava => 0
equip hat Hodgman's porkpie hat => 174
equip off-hand wicker shield => 6
equip pants plexiglass pants => 218
equip shirt letterman's jacket => 87
equip weapon scratch 'n' sniff sword => 261
gong roach allstats => 87
gong roach moxie => 261
hatter 7 => 10
make & use 1 cold-filtered water => 872
make & use 1 cool cat elixir => 30
make & use 1 eyedrops of newt => 25
make & use 1 serum of sarcasm => 872
make & use 1 tomato juice of powerful power => 436
summon 10 => 9
telescope look high => 305
use 1 Angry Farmer candy => 43
use 1 Black No. 2 => 15
use 1 bottle of fire => 523
use 1 box of sunshine => 15
use 1 Crimbo fudge => 5
use 1 CSA bravery badge => 30
use 1 goofballs => 174
use 1 handsomeness potion => 43
use 1 Knob Goblin love potion => 2
use 1 lime-and-chile-flavored chewing gum => 5
use 1 mafia aria => 523
use 1 orange candy heart => 3
use 1 pink candy heart => 3
use 1 potion of blessing => 218
use 1 roofie => 5
use 1 seal-brain elixir => 218
use 1 super-spiky hair gel => 6
use 1 Trivial Avocations Card: What? => 87
use 1 Trivial Avocations Card: What?, 1 Trivial Avocations Card: When?, 1 Trivial Avocations Card: Who?, 1 Trivial Avocations Card: Where? => 872
use 1 Trivial Avocations Card: When? => 87
use 1 Trivial Avocations Card: Where? => 87
use 1 Trivial Avocations Card: Who? => 87
use 1 weremoose spit => 52
use 1 white candy heart => 3

Okay, that's something. Is the fact that maps don't preserve iteration order going to be an issue for people? All the boosts were nicely sorted going into the aggregate but obviously are no longer.

I'm trying to get a feel for what will make this useful to people.
 
Well, the scores aren't necessarily integers, and those aren't the actual command strings that could be executed to obtain the boost, and you've lost all information as to which of the boosts are alternate sources of the same effect and therefore can't usefully be stacked...
 
If I ran a command like this I wouldn't really care about having the correct command string, if it got "use" in it I know it's an item, "cast" leads to a skill and anything else needed can be scripted around as well. Knowing what can reasonable be used together might be nice though, as would being able to sort them by most useful (i.e. highest score modifier).
 
Well, the scores aren't necessarily integers, and those aren't the actual command strings that could be executed to obtain the boost,

Ok, both trivial adjustments. I could put the actual command in another slice if that's useful.

and you've lost all information as to which of the boosts are alternate sources of the same effect and therefore can't usefully be stacked...

Correct me if I'm wrong, but the maximizer itself doesn't keep this information, it just pops out that way from sorting since their scores are the same, so compareTo is 0 preserving order, etc. Like I said, putting this order-important data into a map creates issues, that certainly being one of them. I'm kind of looking for suggestions since ash data types are not my forte.
 
What I'd like to be able to do with that information is a cost benefit analysis. Buff duration and price would be needed. It's looking pretty complicated.
 
Price can be calculated yourself by putting any "item" into a mall_price/historical_price and the cost for a skill is just the mp for it. For things that can be crafted that is a bit more difficult, but the UI as is doesn't give you that either I think. Buff duration can also be deduced from skills and items available to the player, can't it? No need to complicate the output with things that can easily be done afterwards.
 
Right, the grouping of multiple sources of the same effect is currently relying on the assumption that they'll all have the same score, and therefore the sort will keep them together, in the same order. That's something that really should change, to allow multiple sources of different effectiveness - for example, an effect that depends on the number of turns remaining could have sources like "use 1 X", "use 5 X", and "use 10 X", each of which would sort to a different place in the list. However, I can't think of a good way to visually indicate that these sources are related/mutually exclusive when they aren't together in the list.

An array of records would be the logical choice to preserve order, and allow future expansion.
 
Huh. Mod log says I stuck the thread though I swear I didn't. Fixed.

An array of records sounds great, actually. That lets us stuff it with lots of fields. I'd gotten about as far as the previous approach would take me:

Code:
> ash maximizeTEST("familiar exp", true);

Maximizing (1st time may take a while)...
2688 combinations checked, best score 0.00
Returned: aggregate float [string, string]
acquire & use 1 black snowcone => aggregate string [float]
**use 1 black snowcone => 2.0
acquire & use 1 essential cameraderie => aggregate string [float]
**use 1 essential cameraderie => 3.0
acquire & use 1 green snowcone => aggregate string [float]
**use 1 green snowcone => 2.0
equip acc1 Hodgman's bow tie => aggregate string [float]
**equip acc1 Hodgman's bow tie => 0.0
equip acc2 hopping socks => aggregate string [float]
**equip acc2 hopping socks => 0.0
equip acc3 plexiglass pendant => aggregate string [float]
**equip acc3 plexiglass pendant => 0.0
equip familiar bugged balaclava => aggregate string [float]
**equip familiar bugged balaclava => 0.0
equip hat Hodgman's porkpie hat => aggregate string [float]
**equip hat Hodgman's porkpie hat => 0.0
equip off-hand stress ball => aggregate string [float]
**equip off-hand stress ball => 0.0
equip pants Hodgman's lobsterskin pants => aggregate string [float]
**equip pants Hodgman's lobsterskin pants => 0.0
equip weapon lawn dart => aggregate string [float]
**equip weapon lawn dart => 0.0
friars familiar => aggregate string [float]
**friars familiar => 2.0
hatter 6 => aggregate string [float]
**hatter 6 => 3.0
use 1 white candy heart => aggregate string [float]
**use 1 white candy heart => 1.0

and it didn't really feel like it was.. y'know, useful. Back to the drawing board!
 
Getting better...

Code:
> ash maximizeTEST( "familiar exp", true);

Maximizing (1st time may take a while)...
2688 combinations checked, best score 0.00
Returned: aggregate {display; command; score;} [16]
0 => record {display; command; score;}
**display => equip hat Hodgman's porkpie hat
**cmd => equip hat Hodgman's porkpie hat
**score => 0.0
1 => record {display; command; score;}
**display => equip weapon lawn dart
**cmd => equip weapon lawn dart
**score => 0.0
2 => record {display; command; score;}
**display => equip off-hand stress ball
**cmd => equip off-hand stress ball
**score => 0.0
3 => record {display; command; score;}
**display => keep back: paperclip cape
**cmd =>
**score => 0.0
4 => record {display; command; score;}
**display => keep shirt: sea salt scrubs
**cmd =>
**score => 0.0
5 => record {display; command; score;}
**display => equip pants Hodgman's lobsterskin pants
**cmd => equip pants Hodgman's lobsterskin pants
**score => 0.0
6 => record {display; command; score;}
**display => equip acc1 Hodgman's bow tie
**cmd => equip acc1 Hodgman's bow tie
**score => 0.0
7 => record {display; command; score;}
**display => equip acc2 hopping socks
**cmd => equip acc2 hopping socks
**score => 0.0
8 => record {display; command; score;}
**display => equip acc3 plexiglass pendant
**cmd => equip acc3 plexiglass pendant
**score => 0.0
9 => record {display; command; score;}
**display => equip familiar bugged balaclava
**cmd => equip familiar bugged balaclava
**score => 0.0
10 => record {display; command; score;}
**display => acquire & use 1 essential cameraderie
**cmd => use 1 essential cameraderie
**score => 3.0
11 => record {display; command; score;}
**display => hatter 6
**cmd => hatter 6
**score => 3.0
12 => record {display; command; score;}
**display => friars familiar
**cmd => friars familiar
**score => 2.0
13 => record {display; command; score;}
**display => acquire & use 1 green snowcone
**cmd => use 1 green snowcone
**score => 2.0
14 => record {display; command; score;}
**display => acquire & use 1 black snowcone
**cmd => use 1 black snowcone
**score => 2.0
15 => record {display; command; score;}
**display => use 1 white candy heart
**cmd => use 1 white candy heart
**score => 1.0

I'll add a item and skill field which will have $item[none] and $skill[none] when not applicable.

edit: maybe not.. there may be no way at that data for the majority of boosts without doing string parsing. I'll keep poking at it. If not, this is still probably good enough to commit as an experimental doodad.
 
Last edited:
I'll add a item and skill field which will have $item[none] and $skill[none] when not applicable.

edit: maybe not.. there may be no way at that data for the majority of boosts without doing string parsing. I'll keep poking at it. If not, this is still probably good enough to commit as an experimental doodad.

Isn't that string parsing already there, so that maximizer can know which item's price to look up?
 
I haven't had a chance to look at this in detail, but the effect field may need a bit of work - a boost can consist of removal of an effect. There is also the future possibility of boosts that involve removing one effect and gaining another (switching from one pressurized potion to another, for example).
 
(continued from the bumcheekcend thread)
(re: (and that's not even going into "I want to be maximized for X turns, give me appropriate amounts of items/casts for long enough buffs))
Eh? Does the maximizer even do that?

No, but it's what I (want to) do in my scripts. That should be now easy for single-item things (query "Effect Duration" modifier on the item) and single-skill casts (call turns_per_cast). More involved for mutually exclusive things (but I can still do it easily if I get indication of what's mutually exclusive).
I am not even beginning to think about non-hardcoded way to handle things like trivia master (where you have to use three different items, but the composite effect is not on any of them).

This method is better and worse than just returning a int[$string] map - better in that it diminishes the parsing burden on the scripter, worse in that some data is lost. "acquire & use 1 jug of porquoise juice" would, for example, become {$item[jug of porquoise juice], score} so the acquire bit is lost, as is the usually unimportant quantity. It might just be for the best (also in terms of maintainability) if we just went with int[string] and let scripters deal with it.

I see you ended up adding a .cmd field, which is what I would do.
 
This is a great start. A question: In the printout some of the text is printed with grey and some with black. What is the difference? It's not that I can't do the things in grey that I've tested.
 
Isn't that string parsing already there, so that maximizer can know which item's price to look up?

Huh. Yeah. I confused myself due to an eccentricity of how Boost.getItem() worked. r11775 adds an item field. $skill would certainly require some text parsing, not sure if that burden should be on mafia or the scripter.

I haven't had a chance to look at this in detail, but the effect field may need a bit of work - a boost can consist of removal of an effect. There is also the future possibility of boosts that involve removing one effect and gaining another (switching from one pressurized potion to another, for example).

Aye. For now the what-you're-actually-doing-with-the-effect info would have to be parsed out of the command field - perhaps not ideal but it's somewhere at least.
 
and r11781 adds a .skill field.

I think this is pretty much done as I envisioned. Marking implemented.
 
Back
Top