All right. Let's talk
version 1.6!
Three zlib vars were added, all defaulting to false:
priceAdvisor_obeyBuyLimit : if true, don't recommend anything with ingredients priced above your autoBuyPriceLimit (a Mafia setting)
priceAdvisor_conservative : if true, don't recommend anything with ingredients which are not buyable from NPCs or priced at mallmin.
priceAdvisor_CLIexecutable : if true, don't give any advice that isn't CLI-executable. A check for this currently wraps only two things:
- the "can't or doesn't sell" message, for things like useless powder
- the "trade your gloomies in to the Suspicious-Looking Guy" message
In both cases, the advice will be ("", 0.0) instead. The empty string is cli-executable with no problems. (If there's a way to trade your gloomies for oilies via CLI, I could use that replacement instead and you'd get that functionality back. Is there?)
Some name/interface changes:
- renamed the
best_advice cache to
best_cache
- renamed
best_price() to
best_advice() to better fit the naming conventions of the other helper functions
- changed
smashed_advice() to
smash_advice(), again for consistency
- changed the boolean argument of
smash_advice() to be
consider_more like everything else, not just
consider_malus
- changed the method of infinite recursion / circular opportunity cost prevention to be more uniform
Some fixes:
Fixed best_cache to cache results for consider_more being true and false separately.
Fixed an issue where invalid sub-results were appearing in the final result; now they invalidate the final result, which does not appear.
Fixed an issue where final result == original item was not being caught if it occurred as the first "sell" statement of an action.
Fixed/enhanced
replace_with_multiple() with xKiv's kindly-provided regex.
Fixed
best_advice() to return a newly-constructed
price_advice so nothing using its return value can mess with the best_cache.
Problems that remain in this version:
tldr; Maybe not quite cli-executable; cache is necessary to run at a reasonable speed but sometimes gives not-perfect advice
As I mentioned to dj_d, actions for things that report expected values will not be quite correct when cli_execute()'d. They say 1 of everything, when it might really be 2 of one thing and 0 of another. I don't really know what to do about this, since I don't know the results of actually performing the action. "*" is an option, but then it would act on everything in your inventory instead of just the results of the action.
There is an odd interaction between circular-opportunity-cost-prevention and caching. What I mean by circular opportunity cost is this:
Suppose A (sells for 100) and B (sells for 200) can be made into C (sells for 1000).
If you ask PA about A it considers:
Code:
- selling A : profit is 100
- making C and selling C :
- this requires B
- PA considers the opportunity cost of using B as an ingredient:
- selling B : profit is 200
- making C and selling C
- this requires A. To prevent infinite recursion, we consider A to
have its mallsell/autosell value here, which is just 100
- so making and selling C has profit 900 [B]for B[/B]
- since the largest profit for B is calculated at 900, that is the opportunity cost for B
- so making and selling C has profit 100 [B]for A[/B]
This is clearly crazy. Because we were already thinking about using B to make C, the opportunity cost for using B in C
when considering B should have been 0, not 900. Thus the opportunity cost of using B in C
when considering A should have been max(200, 0) = 200 and the final profit from A, using it and buying B to make C, would have been 800 -- as any casual glance will tell you is correct.
PA does do this calculation correctly, preventing itself from thinking about making C a second time when it is already being considered. It says:
Code:
- making C and selling C
- already considering C; profit of considering it again is 0
- since the largest profit from B is 200, that is its opportunity cost
- so making and selling C has profit 800 [B]for A[/B]
This is all fine and good, except that sometimes the first time an item is considered (such as B in this case) is underneath some other considerations, which are correctly taken into account when reporting its best advice under those considerations. However, since this is the first time B has been considered, this is also the advice that gets cached as the best advice for B. As long as the same instance of PA is running, it will tell you that you ought to just sell B for 200. (When clearly you ought to buy an A, make C, and profit by 900.)
I can't turn the cache off; for anything even mildly complicated PA just takes far, far too long to complete. I've even tried a much more sophisticated caching method, designed to never cache the wrong thing:
Code:
if item in cache
return best cached value that doesn't consider what's already being considered
else if cache mode on
old_cc = currently_considering
clear currently_considering // remove all context
cache mode off // don't cache anything with the new context
cache the result of price_advisor(item) -- every result, not just the best!
cache mode on // return to normal
currently_considering = old_cc // return to context
else return price_advisor(item)[0] // without caching it
This very nicely ensures that each value that is cached has been evaluated as if it were at the top-level. Unfortunately, my testing has showed that preventing all the lower-level caching still makes PA far, far too slow.
I'll keep trying things and suggestions are welcomed, but if you've ever wondered why PA tells you things like this:
Code:
> pa bottle of rum
[B]bottle of rum[/B]
make 1 bottle of Lieutenant Freeman; mallsell 1 bottle of Lieutenant Freeman
etc.
> pa Lieutenant Freeman
[B]bottle of Lieutenant Freeman[/B]
acquire 1 kiwi; make 1 caipifruta; mallsell 1 caipifruita
ect.
instead of
Code:
> pa bottle of rum
[B]bottle of rum:[/B]
make bottle of Lieutenant Freeman; acquire kiwi; make caipifruta; mallsell caipifruta
etc.
now you know.
However, since the results of PA will never be
worse than "just mallsell it", and will usually be better, I hope this affects its optimality rather than its usefulness.