EatDrink.ash: Optimize your daily diet (and see how your old diet stacks up).

Sputnik1

Member
I tried this new version, but it doesnt work with Ascend.ash
it came up with an undefined reference to eatdrink.ash
the one with ascend still works fine and doesnt abort ascend
 

tgetgel

Member
The script is going into an infinite loop

This worked fine from dailygrind.ash, but looped in farm.ash.

When it chooses something to buy (my case was a dusty bottle of muscat) it seems to not try something different when the max price does not purchase the item. The drink map meat was 200 with max price of 250, but the mall only had 350 and above.
my session log said:
> drink: At 0, consuming to 19.
> Loading drink map from Mafia's datafiles
> Filtering by type
> Filtering by level
> Finding prices
> Setting values
> Choosing drink to consume.
> <b>dusty bottle of Muscat</b> lev:1 gain:2.0 adv:6.0 musc:12.5 myst:12.5 mox:12.5 meat:200 own:0 value:1904
> Waiting to consume...
> Shopping for a dusty bottle of Muscat in 1 seconds
> budgeting 250 for 1 additional dusty bottle of Muscat. You have 7644843 meat. You have 0 in inventory already.
> Purchased 0 dusty bottle of Muscat for 0 meat.
> Tried to get 1 dusty bottle of Muscat but got 0. Pricing error.
> Setting new effective price to the greater of 250 and 251
> Failed to get dusty bottle of Muscat for a max price of 1.25*200=250.0
> FAIL: <b>dusty bottle of Muscat</b> lev:1 gain:2.0 adv:6.0 musc:12.5 myst:12.5 mox:12.5 meat:200 own:0 value:1904
> Choosing drink to consume.
...
> Choosing drink to consume.
> <b>dusty bottle of Muscat</b> lev:1 gain:2.0 adv:6.0 musc:12.5 myst:12.5 mox:12.5 meat:200 own:0 value:1904
> Waiting to consume...
> Shopping for a dusty bottle of Muscat in 1 seconds
> budgeting 250 for 1 additional dusty bottle of Muscat. You have 7644843 meat. You have 0 in inventory already.
> Purchased 0 dusty bottle of Muscat for 0 meat.
> Tried to get 1 dusty bottle of Muscat but got 0. Pricing error.
> Seen a problem with this one before at a price of 1066.
> Setting new effective price to the greater of 250 and 1068
> Failed to get dusty bottle of Muscat for a max price of 1.25*200=250.0
> FAIL: <b>dusty bottle of Muscat</b> lev:1 gain:2.0 adv:6.0 musc:12.5 myst:12.5 mox:12.5 meat:200 own:0 value:1904
> Choosing drink to consume.
> <b>dusty bottle of Muscat</b> lev:1 gain:2.0 adv:6.0 musc:12.5 myst:12.5 mox:12.5 meat:200 own:0 value:1904
> Waiting to consume...
> Shopping for a dusty bottle of Muscat in 1 seconds
> budgeting 250 for 1 additional dusty bottle of Muscat. You have 7644843 meat. You have 0 in inventory already.
I even bought some bottles and sent them to this character trying to break the loop but the script did not recognize the increase in owned amount. The script seemed to not use the new effective price; I am not sure how the new effective price is used.

A couple of ways this might be handled:
1. increase the max price up to value of next best item. (Reverse the logic for determining the best items to calculate the max price before it changes the order. For example, item A is best as long as it costs less than X. If price more than X, get item B.) (this could be dangerous)
2. if pricing error seen, retrieve now current mall price for the item and rechoose.
3. rechoose based on the scripts new effective price. (not sure what this would do as I don't understand that code yet.)
 
Last edited:
2) Is because you are running an old version of mafia. The newest versions have this fixed in the mafia data file. The new script doesn't use the old data files, it uses mafia internals - so get the latest release!

I deleted the eatdrink data files from my data directory and updated mafia. The script had me consume 4 rockin' wagons and an elven moonshine. My parameters are set to maximize turns and the value of each turn = about 1100 meat.

Supernova champagne costs 1/3 of what elven moonshine costs and has better adventure yields. The script should basically never be consuming elven moonshine under any circumstances.

Any ideas on how I can get the script to stop drinking it?
 
I just ascended so don't have the skills available to test this case, but before I did it was giving me sensible results. I am running kolmafia version 7759 - Greenrider, are you using the .exe, which is out of date now?
 
I just ascended so don't have the skills available to test this case, but before I did it was giving me sensible results. I am running kolmafia version 7759 - Greenrider, are you using the .exe, which is out of date now?

Nah, I always use the jar. I was using 7755, but I'll try to replicate it with the latest build. Still, I think 7755 was recent enough that it shouldn't have made a difference.
 

jasonharper

Developer
Here's some code that may help address houeland's concerns about optimality - and MY concerns about the annoyingly slow & server-unfriendly way this script buys and consumes the same item one at a time. Basically, given the item of best value of each possible fullness, and the total fullness to be filled, it calculates the optimum number of each item to consume - including the possibility that you might not want to consume as many as possible of the largest item, if that would leave you with only crappy items to fill the remaining space.
Code:
// Minimal definitions of data for this example to work:

record con_rec
{
	string name;
	float value;
};

con_rec[int] bestByFullness;

// Some dummy data to work with:

bestByFullness[1] = new con_rec("nice cold beer (1)", 1000.0);
bestByFullness[2] = new con_rec("dusty bottle of dust (2)", 6000.0);
bestByFullness[3] = new con_rec("bottle of paint thinner (3)", 9000.0);
bestByFullness[4] = new con_rec("garnished varnish (4)", 13000.0);
//bestByFullness[6] = new con_rec("tiny plastic corpsedrink (6)", 18000.0);

// Solve a general integer knapsack problem:
// Find the combination of items from bestByFullness,
// that have the greatest total value,
// with no more than the specified total fullness.
// Return value is an int[int] map:
// keys are the NEGATIVE of fullness (so that bigger items iterate first),
// values are the number of items of that fullness to consume.

int[int] knapsack(int remainingFullness)
{
	float[int] values;
	int[int] fulls;
	values[0] = 0.0;
	fulls[0] = 0;
	
	// For each level of fullness, find the best final item to achieve it.
	// The value achievable by an item is the value of the item,
	// plus the (previously calculated) best value achievable at a
	// lesser fullness level: the considered fullness minus the item's fullness.
	
	for full from 1 upto remainingFullness {
		float bestValue = 0.0;
		int bestFull = 0;
		foreach itemFull, itemRec in bestByFullness {
			if (itemFull <= 0 || itemFull > full) continue;
			float value = itemRec.value;
			float prev = values[full - itemFull];
			if (value + prev > bestValue) {
				bestValue = value + prev;
				bestFull = itemFull;
			}
		}
		values[full] = bestValue;
		fulls[full] = bestFull;
	}
	
	// Now that we know the best final items at each fullness level,
	// backtrack through them to determine the entire set of items.
	
	int[int] result;
	while (remainingFullness > 0) {
		int full = -fulls[remainingFullness];
		if (full == 0) break;
		result[full] = result[full] + 1;
		remainingFullness = remainingFullness + full;
	}
	return result;
}

// Testing code.
// Note that with the sample values, a 3-full plus a 2-full item
// give a greater value than 4-full plus 1-full; the greedy
// algorithm of always choosing the largest item would therefore
// produce suboptimal results in some cases.

for i from 1 to 20 {
	print("");
	print("To achieve " + i + " fullness:");
	int[int] result = knapsack(i);
	if (count(result) == 0 ) {
		print("(nothing suitable)");
		continue;
	}
	foreach fullness, qty in result {
		print("...consume " + qty + " " + bestByFullness[-fullness].name);
	}
	// In actual use, the first item in the map would be acquired
	// (in the indicated quantity), whatever quantity was actually
	// acquired would be consumed, and then the whole calculation
	// would start over with whatever state that left you in.
}
 

dj_d

Member
@JH: The reason it buys one at a time is because buying an item X is only optimal if the price is at or near the price used in the calculation that selected it. Since mafia pricing uses deliberately out-of-date values, you may find that a given item can't be bought for that price (or the second instance of a given item can't be bought for the same price as the first), and so is no longer optimal.

You're right, though, that it'd be better to consume the items all at once.
 

lostcalpolydude

Developer
Staff member
mallprices.txt gives you the price of the fifth cheapest store as of whenever that search was done. Everything should be cheaper than that (the only practical diet where someone would want more than 5 of an item is dusty wines I think, and those can generally be bought in bulk from the first store you try). Also, wasn't the buy function recently changed so you can specify a maximum price, and the function won't buy anything that costs more than that? I don't actually write any scripts, I just absorb this information to regurgitate in a hopefully intelligent manner, so hopefully I have some of this close enough anyway...
 

jasonharper

Developer
If an item happens to be cheaper than expected, that can hardly make it less desirable to consume - you're still going to want to consume at least as many as originally planned.

If the item turns out to be more expensive, then the price limit keeps you from buying any at inappropriate prices - any that were bought under the limit would, by definition, meet the original criteria for consuming them. Ideally, the price limit would be the point at which the item ceases to be the best value, rather than the expected price plus a margin, but that wouldn't be trivial to calculate (and probably wouldn't make that much difference in practice).

So basically, you're making no sense at all.

lostcalpolydude: the Mall price functions return the price of the 5th item, not the 5th store. Typically that would be the first store that doesn't have a 1/day limit. As for practical diets, spleen filling could easily use 15 wads.
 

tgetgel

Member
I noted that the decrement of the number owned no longer decrements.

Code:
12: twinkly wad lev:6 gain:1.0 adv:1.0 musc:9.0 myst:9.0 mox:9.0 meat:229 own:100 value:71
Choosing spleen to consume.
Waiting to consume...
twinkly wad lev:6 gain:1.0 adv:1.0 musc:9.0 myst:9.0 mox:9.0 meat:229 own:100 value:71
Countdown: 1 second...
Waiting completed.
You have at least one twinkly wad in inventory.
Countdown: 1 second...
Waiting completed.
Using 1 twinkly wad...
You gain 1 Adventure
You gain 8 Beefiness
You gain 11 Wizardliness
You gain 9 Cheek
You acquire an effect: Aspect of the Twinklefairy (duration: 10 Adventures)
Finished using 1 twinkly wad.
13: twinkly wad lev:6 gain:1.0 adv:1.0 musc:9.0 myst:9.0 mox:9.0 meat:229 own:100 value:71
Using jar 7768 and eatdrink.ash v3.0.
 

CoC

New member
Still seems to have the interminable loop in hardcore (and i s'pose ronin) when it can't buy or make what it thinks is best to consume.

using eatdrink.ash v3 and jar 7771
 

Banana Lord

Member
Eatdrink's going into an infinite loop for me too (out of Ronin, HC):

Code:
Equipment changed.
(usable quantity of rockin' wagon is limited to 0 by inebriety)
Putting on General Sage's Lonely Diamonds Club Jacket...
Equipment changed.
FAIL: [B]rockin' wagon[/B] lev:4 gain:4.0 adv:12.0 musc:0.0 myst:0.0 mox:35.0 meat:1700 own:0 
value:7335
Internal checkpoint created.
Putting on tuxedo shirt...
Equipment changed.
(usable quantity of rockin' wagon is limited to 0 by inebriety)
Putting on General Sage's Lonely Diamonds Club Jacket...
Equipment changed.
FAIL: [B]rockin' wagon[/B] lev:4 gain:4.0 adv:12.0 musc:0.0 myst:0.0 mox:35.0 meat:1700 own:0 
value:7335
Internal checkpoint created.
Putting on tuxedo shirt...
Equipment changed.

.... And so on.

Using version 3.0, mafia build 7768.
 

dj_d

Member
@JH: You pretty much figured it out right there. The margin is set high by default to keep from wrecking the server with repeat hits, but if you paid more than you expected, it's probably nonoptimal and you want to recalc. It's a good idea to set the margin to the next-best thing; that's more realistic now that I'm sorting, but I'll have to think that through.

When I built this originally, there was someone regularly supplying 5 twinkly wads/day for much less than the going rate. I built this for myself, not for wide distribution, and I was more concerned about optimizing than execution speed.

Since I decided to share it I've made some changes to accommodate a wider user base (using defaults designed to reduce server hits for example) but at the end of the day I'm building it to meet my own goals, not anyone else's.

If you'd like to put together a version that defaults to the behavior you describe and has a setting to revert to original behavior, I'm happy to post that, but I barely have time to keep an eye on my characters these days so doing it myself isn't likely to happen soon. I'm sure you're similarly busy keeping Mafia up and running.
 
1) That's because it hasn't included the effects of milk of magnesium properly at that stage so doesn't eat the first chow mein until it's reassessed its value. There should probably be a different message to FAIL in this case!

So I'm still a bit confused by why the script buys a chow mein every day and then decides not to consume it, giving me that FAIL message. Is this a bug, or am I doing something wrong?
 

Xenthes

Member
First off, I like this script and use it pretty much every time I play KoL.

The 3.0 version isn't working with ascend.ash. When I run ascend.ash I get:
> call scripts\Ascend.ash

Undefined reference to function 'eatdrink' (Ascend.ash, line 61)
eatdrink.ash still plays well with an older version..
I have mafia version 7772 currently.
 

Banana Lord

Member
So I'm still a bit confused by why the script buys a chow mein every day and then decides not to consume it, giving me that FAIL message. Is this a bug, or am I doing something wrong?

This is pretty much what's happening to me but instead of a chow mein it buys me a rockin' wagon and gives me the fail message as per my previous post.

I'm now on build 7772 if that makes a difference.
 

Banana Lord

Member
I just checked this - the version in the first post doesn't include the fix to that issue that I posted last. Not sure how that happened! Sorry. My fix was here:

http://kolmafia.us/showpost.php?p=19230&postcount=259


Ah great, thanks! I'll try it out tonight.

EDIT: Hmmm. Still not working:

Code:
Choosing drink to consume.
Shopping for a rockin' wagon in 0 seconds
budgeting 1500 for 1 additional rockin' wagon. You have 35584389 meat. You have 0 in inventory already.
Using cached search results for rockin' wagon...
[COLOR=red]Stopped purchasing rockin' wagon @ 1,700.[/COLOR]
Purchased 0 rockin' wagon for 0 meat.
Tried to get 1 rockin' wagon but got 0. Pricing error.
Seen a problem with this one before at a price of 1844.
Setting new effective price to the greater of 1500 and 1846
Failed to get rockin' wagon for a max price of 1.25*1200=1500.0
FAIL: [B]rockin' wagon[/B] lev:4 gain:4.0 adv:12.0 musc:0.0 myst:0.0 mox:35.0 meat:1200 own:0      
value:7735
Choosing drink to consume.
Shopping for a rockin' wagon in 0 seconds
budgeting 1500 for 1 additional rockin' wagon. You have 35584389 meat. You have 0 in inventory already.
Using cached search results for rockin' wagon...
[COLOR=red]Stopped purchasing rockin' wagon @ 1,700.[/COLOR]
Purchased 0 rockin' wagon for 0 meat.
Tried to get 1 rockin' wagon but got 0. Pricing error.
Seen a problem with this one before at a price of 1845.
Setting new effective price to the greater of 1500 and 1847
Failed to get rockin' wagon for a max price of 1.25*1200=1500.0
FAIL: [B]rockin' wagon[/B] lev:4 gain:4.0 adv:12.0 musc:0.0 myst:0.0 mox:35.0 meat:1200 own:0 
value:7735
Choosing drink to consume.
Etc.
 
Last edited:
Top