Feature - Rejected Retrieve Worthless items by using gum

Status
Not open for further replies.

Veracity

Developer
Staff member
InventoryManager.retrieveWorthlessItems() is used to get a specified number of worthless items (of any type). As coded, it first uses 31337 scrolls, one at a time, until the specified number is in inventory or you run out of scrolls, and then attempts to adventure in the sewer, with a stop condition of the number needed.

There is no sewer any more. Instead, simply using chewing gum on a string gives you a chance to get worthless items. You are guaranteed to get a worthless item if you have at least one of every non-worthless item that gum can yield in inventory. If you have all such items and additionally all three kinds of worthless item in inventory, you get a random item selected from everything that gum can yield, worthless or not.

I propose something like the following as the algorithm

Code:
int needed = requested - inventory
while needed > 0
    move worthless items in inventory to closet
    buy and use one chewing gum on a string
    if got a worthless item
        needed = needed - 1
move requested - inventory worthless items out of closet
 

xKiv

Active member
If the gums are really multiusable, as I have seen mentioned in some thread here already, you could probably speed this up a bit by buying&using $needed gums at a time (a lower amount will never fully satisfy the request).
 
Last edited:

slyz

Developer
(a lower amount will never fully satisfy the request).

On the other hand, for a large amount, you will miss an opportunity to get guaranteed trinkets.

if you have all the starter items in your inventory already, you will have 3 guaranteed trinkets and random items after that. It would be nice to get the 3 guaranteed ones, then closet them and repeat until you have enough trinkets.

To know how many starter items you are missing, here is what i did in ASH:
PHP:
int num_missing_starters()
{
	int num = 0 ;
	foreach itm in $items[	seal-skull helmet, seal-clubbing club,
				helmet turtle, turtle totem,
				ravioli hat, pasta spoon,
				Hollandaise helmet, saucepan,
				disco mask, disco ball,
				mariachi hat, stolen accordion,
				old sweatpants ]
	{
		if ( item_amount( itm ) + equipped_amount( itm ) == 0 )
		{
			num += 1 ;
		}
	}
	return num ;
}

To know how many gums you can use at a time, making sure you can't get too many trinkets, and making sure you don't miss the opportunity to get guaranteed trinkets:
PHP:
to_use = min( needed , num_missing_starters() + 3 );

The algorithm would then be:
Code:
int needed = requested - inventory
while needed > 0
    move worthless items in inventory to closet
    buy and use min( needed , num_missing_starters() + 3 ) chewing gum on a string
    if got worthless items
        needed = needed - num_worthless_acquired
move requested - inventory worthless items out of closet

It would also be more efficient, meat-wise, to take out of the closet one of any starter item that isn't equipped or in your bag. But this can be left to the player, since I guess people might not approve of Mafia rummaging through their closet.
 
Last edited:

xKiv

Active member
Oh, duh. But you can still buy the full (needed) at once.
Then possibly buy a new batch once amount of gums in inventory is lower than 3 (and needed is greater than that), so that the next use bit us full three again.
 

slyz

Developer
Yes, this could avoid hitting the server to buy more each time, if you need a large amount.
Code:
int needed = requested - inventory
while needed > 0
    move worthless items in inventory to closet
    buy max( needed - gums in inventory , 0 ) chewing gum on a string
    use min( needed , num_missing_starters() + 3 ) chewing gum on a string
    if got worthless items
        needed = needed - num_worthless_acquired
move requested - inventory worthless items out of closet

Now, let's wait for for Zarqon to come along and streamline this, it's getting complicated =)
 
Last edited:

Theraze

Active member
Any way to just convert SewerRequest to use a chewing gum? Then anything that KoLmafia does that involves the sewers, or scripts that manually hit the sewers should just use the chewing gum, right? I tried changing it from a GenericRequest to a MultiUseRequest and giving it the item id as its super, but it wouldn't get past checking the character on login.
 

xKiv

Active member
Yes, this could avoid hitting the server to buy more each time, if you need a large amount.
Code:
int needed = requested - inventory
while needed > 0
    move worthless items in inventory to closet
    buy max( needed - gums in inventory , 0 ) chewing gum on a string
    use min( needed , num_missing_starters() + 3 ) chewing gum on a string
    if got worthless items
        needed = needed - num_worthless_acquired
move requested - inventory worthless items out of closet

Now, let's wait for for Zarqon to come along and streamline this, it's getting complicated =)

Nitpick: you should buy needed + num_missing_starters() - gums in inventory, so that you have enough gums for the next step even if you are missing starter items
Also, if you use N gums and only acquire A wrothlesses, then you gained B=N-A unique starters.
Also also, you are needlessly limiting yourself to "needed" when using if you request less than missing + 3.

So, probably:
Code:
int needed_trinkets = requested - inventory
int missing = num_missing_starters()
while needed_trinkets > 0
  move worthlesses from inventory to closet (or convert them directly to hermit items if the request is for hermit items)
  need_gums = max(needed_trinkets + missing - gums_in_inventory,0) # the max is to ensure that you don't need negative gums
  buy(need_gums) gums
  use_gums = missing + min(needed,3)
  use(use_gums) gums
  w = how many worthless items you got # this should always be at least 1
  needed_trinkets -= w
  missing -= use_gums - w # gained non-trinkets are missing uniques

missing *should* be non-zero only the first time; if needed_trinkets is 3 or more, you will get all uniques in the first use and if it is less, then you eighter got all uniques and your requested trinkets, or more trinkets than what you wanted (which is not bad, IMAO, unless you are really hurting for meat).
 
Last edited:

slyz

Developer
I don't think Mafia should try to guarantee having all the missing starter items before getting trinkets: if a player (or a script) wants to do this, he should do it himself. It could cost a lot of unnecessary meat on day 1 of a run for example, and people who get rid or closet their starter items would not like to see Mafia getting them back every time they want a trinket.
 

Veracity

Developer
Staff member
I think it should uncloset (and recloset) any starting items you happen to have, and assume that all the missing ones will just show up. So, if you need 3 trinkets and are missing 3 starter items, it will buy and use 6 pieces of gum.

These are the starting items:

seal-skull helmet
seal-clubbing club
helmet turtle
turtle totem
ravioli hat
pasta spoon
Hollandaise helmet
saucepan
disco mask
disco ball
mariachi hat
stolen accordion
old sweatpants
worthless trinket
worthless gewgaw
worthless knick-knack

16 in total.
 

slyz

Developer
So, if you need 3 trinkets and are missing 3 starter items, it will buy and use 6 pieces of gum.
This would avoid server hits, but you could get 3 trinkets from 3 gums, so on average it would cost the player more meat, especially if people then proceed to get rid of the starting items.
 

Theraze

Active member
Any chance we just rewrite the code so that anytime it would have done a sewer adventure, it uses a chewing gum instead? It already purchases the chewing gum automatically, it just plans to adventure once instead of using it... Then the most efficient way to actually run these can be done in scripts, and you won't get people running hardcore complaining because their one WI attempt for epic weapon drained all their starting money...
 

Veracity

Developer
Staff member
Any chance we just rewrite the code so that anytime it would have done a sewer adventure, it uses a chewing gum instead?
Isn't that what I am proposing? I want to fix "acquire 3 worthless item" to get it by using gum, rather than by adventuring in the sewer. I do not want to leave the Sewer as a (pseudo-)adventure location. Saying "you can get chewing gum items by 'adventuring' in the sewer" looks like an ugly kludge, to me. I want to remove SewerRequest entirely from the code base.

you won't get people running hardcore complaining because their one WI attempt for epic weapon drained all their starting money...
What does this mean? What is a "WI attempt"? Oh, wait: "worthless item". So, you are worried lest somebody saying "acquire 1 worthless item" is annoyed because it comes back after spending 500 meat and says "sorry! I failed because you are out of meat", rather than is annoyed because it comes back after spending 10 adventures and 300 meat and says "sorry! I failed because you are out of meat and/or adventures."

It sounds like you are suggesting that we entirely remove "acquire 1 worthless item" from KoLmafia and require people to use a script for that functionality. I don't agree with that suggestion.
 

Veracity

Developer
Staff member
OK, "acquire 3 worthless item" now is a simple minded replacement of the previous functionality, which simply adventured in the sewer until you either acquired enough worthless items or ran out of meat and/or adventures. The current code simply acquires and uses chewing gum until the requisite number of worthless items are in inventory.

We can optimize this later, as discussed in this thread.
 

Theraze

Active member
What does this mean? What is a "WI attempt"? Oh, wait: "worthless item". So, you are worried lest somebody saying "acquire 1 worthless item" is annoyed because it comes back after spending 500 meat and says "sorry! I failed because you are out of meat", rather than is annoyed because it comes back after spending 10 adventures and 300 meat and says "sorry! I failed because you are out of meat and/or adventures."

It sounds like you are suggesting that we entirely remove "acquire 1 worthless item" from KoLmafia and require people to use a script for that functionality. I don't agree with that suggestion.

No... that wasn't what I was aiming for at all...

What I was actually asking for is that there be some way to acquire 1 worthless item... I was suggesting that the acquisition of 3 may be better served by a script as people have different opinions on the 'best' optimization. People in this thread have always referred to the acquisition of 3, not the single one that you're more likely to want if you're on the cheap.

The HC complaint thing wasn't that it runs 10 times and burns all their money... it already ran that way with the sewers. Some of the optimization suggestions though have been to buy enough gum to guarantee that you get 3 worthless items, which isn't necessarily good if you just want the one.

I see that you did spin a patch that just tries to collect it 1 item at a time without optimization... that's exactly what I was trying to suggest. I wasn't necessarily wanting the kludge patch, just something that allows for optimization based on the user's opinions. If you have all the starter items already and want 3 worthless items, it may eventually be good to do the closet handling internally to guarantee getting those items as quickly as possible, but barring a function to collect all the gum items (again, probably better to leave as a script), there's probably not too much more I think the code should handle internally.

Just my thoughts though. :)
 
Last edited:

slyz

Developer
People in this thread have always referred to the acquisition of 3, not the single one that you're more likely to want if you're on the cheap.
The algorithm discussed by xKiv and I wasn't only about acquiring 3, it was to acquire the amount the user asked for with as little server hits as possible while also taking advantage of the fact that you could guarantee getting trinkets in certain cases.

In what we discussed, "acquire 1 worthless item" would use gums one by one, but "acquire 10 worthless item" would end up using gums 3 by 3 to make sure you don't start getting random items. I think we can find a way to optimize this without making any assumptions on what the user would choose.
 

Theraze

Active member
True... it was later (and in other threads) that the 3 seems to always be mentioned.

Now I'm trying to think through how this should work for optimal as well, and the problem is that either you have the code do single-buy and use for each and if you want to do more you can have an external script to handle closeting and the like, completely ignore the internal workings and have the script purchase and use the items as you desire them, or optimize the internal workings, either partially or fully...

The thought that hit me was... in the cases of trying to pick up multiple worthless items, I think it would make sense to do more like your suggested, not xKiv's version. I'd restarted it all, but then looked back and basically reworked exactly what you had. :) A bit of cleanup would only buy if either don't have 3 worthless left or how many you're going for... I think something like:
Code:
int needed = requested - inventory
while needed > 0
    move worthless items in inventory to closet
    if ( needed > 3 && gums in inventory < min(needed, 3) )
        buy max( needed - gums in inventory , 0 ) chewing gum on a string
    else if ( needed < 4 && gums in inventory < needed )
        buy max( needed - gums in inventory , 0 ) chewing gum on a string
    use min( needed, num_missing_starters() + 3 ) chewing gum on a string
    if got worthless items
        needed = needed - num_worthless_acquired
    move requested - inventory worthless items out of closet
 

holatuwol

Developer
If I'm understanding the way this works correctly (and I'm just guessing based on what's been stated in this thread), I think the main problem with any sort of server-hit optimized solution is that as soon as you acquire a worthless item, your probability for getting another significantly drops.

For example, you have five starter items and none of them are worthless items. The probability that you'll find a worthless item is 3/11 (because you won't get any of the five starter items you already have). If you are lucky enough to find a worthless item on your next gum, your probability of being lucky again drops to 2/10. If you find another, it drops to 1/9. If this is the way it works, people are going to find that unacceptable and write their own scripts.

So, this is one of those cases where KoLmafia should do the correct thing and only go after more than 1 gum only when it knows that it's safe to do so. That way, you avoid the problem of people who write scripts that go one at a time even after it's okay to get three at a time. For now, this is what it does in revision 8696.

Additionally, there is the problem of retrieving starter items one at a time if they've all been closeted, and that's something that KoLmafia can actually help with if it's the one doing the right thing (as opposed to another user script that tries to be optimal if KoLmafia is not). That is added in revision 8697.
 
Last edited:

xKiv

Active member
If I'm understanding the way this works correctly (and I'm just guessing based on what's been stated in this thread), I think the main problem with any sort of server-hit optimized solution is that as soon as you acquire a worthless item, your probability for getting another significantly drops.

Unless you already have all the starter items or are willing to pay the one-time cost of getting them all anyway (which you eventually will, as long as you want to get more than a couple worthlesses), yes. Worst case is loss of 600 meat per ascension.
 

holatuwol

Developer
Oh huh, if it's only 600, then out of Ronin, you might as well just go straight for all the starter items all the time, and only leave optimization for the people who are in hardcore or in ronin where the funds are tighter. (Or I assume they're tighter. Can't say I remember much of the bleeding-edge gameplay of KoL anymore. *cough*)

Update: So after a bunch of tweaking and random realizations, the friendlier version is essentially xKiv's algorithm (a few minor differences to avoid recomputations, but it's more or less the same), and the less friendly version resembles none listed, since it starts using 1-3 worthless items depending on how many are still needed as soon as there's at most one missing starter item (with starter item meaning the 13 that aren't worthless items rather than all 16 items available via chewing gum), but always uses one chewing gum up until that point. See revision 8702.
 
Last edited:

slyz

Developer
I'm going through the changes, and I don't think it's necessary to call InventoryManager.retrieveItem( starterItem ) (lines 685-692) before starting to use chewing gums. Since one of each starter item has already been taken out of the closet if possible, retrieveItem() will either unequip them (which is not necessary, since an equipped starter item counts when you use a chewing gum) or buy them from the mall (and cause server hits to get the item in a more expensive way than using a gum). Of course, there's the clan stash, but I think just "buying" the missing starter items through chewing gums is good enough.

Other than that, the update seems to fit the bill: having a separate logic for Ronin/HC and for aftercore is great, and should probably satisfy everyone.

Thanks for the update!

(edited for clarity)
 
Last edited:
Status
Not open for further replies.
Top