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

I'm not really sure if I have something wrong (probably) or am missing some key piece of information (also probably), but I have been trying to figure out the optimum diet thing for a while now, and started comparing the different sources for optimum diet plans. I've discovered what appears to be a discrepancy that I'm struggling to qualify.

I've been using this site for a while now to figure out the optimal diet:
http://www.houeland.com/kol/diets

The lists seem pretty good except it assumes you buy everything from the mall, so it never takes into account inventory and crafting abilities. I can usually eat/drink to full at a fraction of the cost that it recommends.

I started using this script to see if the results were pretty close, but it seems like the results from this script are WAY off from the table on the website. Normally, I would say this is expected, but the problem is that it's off in the wrong direction.

For instance:
From the website
I check Ode + Tuxedo Suite, Liver of Steel, No Semi-Rares, Maximize for Adventures
If I assume a profit of 500 mpa, I go down the list, and it says that I will earn 188.1 turns, and spend 13k meat doing it. The food/drink/spleen list comes back with:
1x milk of magnesium [889 meat]
3x spooky lo mein [1483.7 meat]
1x pear tart [445 meat]
9x dusty bottle of {fantastic wine} [200 meat]
1x shot of blackberry schnapps [265 meat]
1x rockin' wagon [1595 meat]
15x twinkly wad [238 meat]

Now, with the script, I would assume that I would get the same or more turns, for the same or less spent trying to create all this stuff.
15 int foodMax
19 int drinkMax
15 intSpleenMax

The food list changes, but the booze/spleen list seems to be similar:
1x milk of magnesium
3x Boris' Key Lime Pie
1x Pear Tart
9x Dusty Bottle of Zinfandel
1x Cruelty-free Wine
15x Twinkly Wad
1x Horizontal Tango

Spent 31046 meat. Gained Fullness: 15. Inebriety: 23. Spleen: 15. Adventures: 182. Muscle: 333. Moxie: 243. Mysticality: 325.

Now, this script is supposed to take inventory into account, yet it claims I'll need to spend 31k to get 6 less adventures.

The strange part, to me, is that I know that i can craft (or even buy every item from the mall) on that list, and it won't add up to 31k meat. In fact, if I buy every ingredient on that list and craft everything, it only works out to 9,730 meat for the entire list. What's more, is that I have most of the ingredients in inventory already, so I wouldn't even have to purchase most of it, bringing the cost down even more.

I figure it's using the mall price for key lime pies, which is alright, but the spooky lo mein is also in the mall, and is about 1/4 the cost, for more adventures per fullness, which means it should be giving me that instead of the key-lime pies, anyway.


I apologize if I am totally missing the point of this script, or what it's supposed to do, but I just want to try and understand the differences, and weather or not it's truly giving out the best meal-plan.
 
Found the bug: Line 298 uses integer division. It should be:
{ return ((statrange.max + statrange.min) /2.0); }
I think!

Also, elven moonshine is incorrectly listed in eatdrink_drink_data.txt as having max adventures 15 and min 6 (should be 10-7). Is there some way of automatically checking those numbers for the whole list? My eatdrink_drink_data.txt doesn't seem to have the fantastic bottle of dusty wine data either.

Thanks again for your work!

Edit: a couple of other finds

lines 213-217 should consider if you're already wearing the shirt:

boolean tuxworthy(item it)
{
return (tuxable contains it) && (have_item($item[tuxedo shirt]) > 0) &&
can_equip($item[tuxedo shirt]);
}

Also, lines 989-990 should be
if (tuxworthy(it))
advscore = advscore + (2 * VALUE_OF_ADVENTURE / full);

although I don't yet know how to avoid that integer division (which is more important e.g. on line 997: costscore = con.price / full; ). Using to_float(full) doesn't seem to work... also, the tux adventures are missed off the final summary (in simulation mode).

edit 2: ah, that's because advscore and costscore are ints. Perhaps the arithmetic should be done with floats before converting for an integer final value, if that's what's desired?

edit 3: Ok, so I realised there's a new beta version which uses floating arithmetic already. It seems great - awesome and thanks! Sorry for being a pain. The tuxedo alterations from the above still need to be incorporated though.
 
Last edited:
Good call on the tuxworthy fixes! Next version I post will have that. And yes, I converted everything to floats already (once I had JH's profiler to show that it wouldn't nuke performance).
 
Amazing script, dj_d. The few times I've run this directly from the CLI, it has worked with flying colors. Thanks again!

I have a problem though. :( I'm trying to write a script that automates some amount of eating and leaving room for fortune cookies. First, I call a sim version of your script, to see how many adventures I will get from food. Then, based on that, I eat to the appropriate amount of fullness.

Code:
int do_food() {
	int turns_til_sr, cookies_to_eat, food_adv;
	
	if (get_counters("Fortune Cookie", 0, 200) == "") {
		eat(1, $item[fortune cookie]);
	}
	
	turns_til_sr = nextSR() - my_turncount();

	food_adv = eatdrink(fullness_limit() - my_fullness() - 2,0,0,false,adv_val,0,0,0,true);

	cookies_to_eat = max(0,ceil((to_float(my_adventures()) + to_float(food_adv) - to_float(turns_til_sr))/180.0));
	
	eatdrink(fullness_limit() - my_fullness() - cookies_to_eat,0,0,false,adv_val,0,0,0,false);
}

Oh, I also modified EatDrink to return an int of how many adventures it predicts I will get.

The output of the first (simulated) EatDrink is fine, but the second one returns no data, whether it is in sim mode or not. Here is sample output from the second one:

Code:
Internal checkpoint created.
Already updated from http://zachbardon.com/mafiatools/updateprices.php?action=getmap in this session.
Already updated from http://nixietube.info/mallprices.txt in this session.
Refreshing stash contents...
Stash list retrieved.
Starting EatDrink.ash (version 2.4).
Consuming up to 12 food, 0 booze, and 0 spleen as if you were level 30.
Considering food from inventory Hagnk's the mall. Per-item budget cap is 62500.0.
Price will be a factor if you own it already. Hagnk's pulls (if enabled) will cost 0 meat each.
An adventure has the value of 1100 meat. Moxie subpoint is 0. Nonprime stat subpoint is 0.
Loading food records.
Now at fullness of 1, eating to 12.
filtering food based on level & availability
calculating food values
Writing out new food file
Finished.
Spent 0 meat. Gained Fullness: 0. Inebriety: 0. Spleen: 0. Adventures: 0. Muscle: 0. Moxie: 0. Mysticality: 0.
Eating, drinking, and spleening complete. Commence merrymaking (at your own discretion).
******************************************
Now, to recap...
******************************************
Starting EatDrink.ash (version 2.4).
Consuming up to 12 food, 0 booze, and 0 spleen as if you were level 30.
Considering food from inventory Hagnk's the mall. Per-item budget cap is 62500.0.
Price will be a factor if you own it already. Hagnk's pulls (if enabled) will cost 0 meat each.
An adventure has the value of 1100 meat. Moxie subpoint is 0. Nonprime stat subpoint is 0.
Now at fullness of 1, eating to 12.
Finished.
Spent 0 meat. Gained Fullness: 0. Inebriety: 0. Spleen: 0. Adventures: 0. Muscle: 0. Moxie: 0. Mysticality: 0.
Eating, drinking, and spleening complete. Commence merrymaking (at your own discretion).

Again, thanks for the amazing script, and any help you can provide. :)

Edit: Looks like it was my own fault. :) I'm guessing it has to do with the fact that I set the booze and spleen limit to 0, rather than inebriety_limit() and spleen_limit(). In my head, it was "how much more booze and spleen" do you want. I think this is causing the hang up, but I can't try until rollover.

Edit edit: Still not working, no matter what I try. Anyone have an idea what's wrong? Thanks.
 
Last edited:
Great script!:D

I was looking at the session log and have a question/observation.
(Mafia v 7754.jar, EatDrink.ash v2.4, both verbosity print lines commented out)

The log contains the following:
> Now at fullness of 0, eating to 15.
> <b>Boris's key lime pie</b> lev:6 gain:4.0 adv:16.0 musc:30.0 myst:0.0 moxie:0.0 price:8600 own:2 pull:false make:false value:-113
> <b>Brimstone Chicken Sandwich</b> lev:1 gain:3.0 adv:5.0 musc:7.0 myst:0.0 moxie:17.0 price:200 own:0 pull:false make:false value:784
...followed by a few more lines (280) of other edible items.

The "Now at fullness of" is at line 1393
Code:
    verbose("Loading food records.");
    summarize("Now at fullness of "+get_fullness()+", eating to "+foodMax+".");
I do not know which line of code causes the food items to be listed in the log. They are not shown in the CLI.

Upon the first consumption, the following lines are logged:
eat 1 spooky lo mein
You gain 23 Adventures
You gain 34 Sarcasm
> 1: <b>spooky lo mein</b> lev:6 gain:4.0 adv:18.0 musc:0.0 myst:0.0 moxie:33.0 price:1665 own:0 pull:false make:false value:1842
> FAIL: <b>spooky lo mein</b> lev:6 gain:4.0 adv:18.0 musc:0.0 myst:0.0 moxie:33.0 price:1665 own:0 pull:false make:false value:1842
> <b>Boris's key lime pie</b> lev:6 gain:4.0 adv:16.0 musc:30.0 myst:0.0 moxie:0.0 price:8600 own:2 pull:false make:false value:-113
> <b>Brimstone Chicken Sandwich</b> lev:1 gain:3.0 adv:5.0 musc:7.0 myst:0.0 moxie:17.0 price:200 own:0 pull:false make:false value:784
...followed again by a few more lines (280) of other edible items that do not show in the CLI.

The "FAIL" is from line 1487/8
Code:
  print_html("FAIL: "+consume_entry);
	  logprint("FAIL: "+consume_entry);

Drink lines at 1505/6. Spleen lines at 1545/6.

So, a few questions.
1. Why does it say FAIL when it actually consumed the item? What does this FAIL mean?
2. Is there a reason that the log lists the food file again upon each consumption? (does the same for drink and spleen)
3. Can the listing of the consumable items in the session log be covered by one of the verbose options?

I am going to run this again after rollover with both verbose print lines active to see the program flow.
 
Last edited:
I decided to try out this script to see how it worked. The instructions still say to put the data files in your scripts folder when they actually need to be in the data folder. I also had to track down zlib after this script told me it was needed; not hard, but the directions only mention it in passing.
 
http://www.houeland.com/kol/diets is optimal and cannot be beaten as long as the assumptions hold (in aftercore, high enough level/hp to use things, liquid market, same linear utility function, correct market and spading data). It doesn't take any shortcuts or liberties. If you can e.g. make hell ramen cheaply, you should sell it or the components in the mall and use the meat to buy something better to eat, not eat the hell ramen.

The version of this script listed in the first post can be used just fine (~85% of optimal) as an eating/drinking script, but as someone else already pointed out it's really bad as an optimizer. Hopefully the beta version and such is better, but the greedy approach used can't guarantee optimal results even if the bugs are weeded out. It'll probably be much much closer and much better for everyone using it though, so good luck with the fixes =)
 
http://www.houeland.com/kol/diets is optimal and cannot be beaten as long as the assumptions hold...

...the greedy approach used [by eatdrink.ash] can't guarantee optimal results even if the bugs are weeded out.

So my thought is, what are the chances of someone creating a script that parses the public houeland data and automatically executes it? In some sense, it seems like eatdrink.ash is performing a lot of computation that has already been pre-computed by houeland.

[Note: you can't in all cases just go straight down the houeland list and perform each eat/drink in order; some of the more expensive diets rely on (for example) eating something, then drinking something that reduces fullness, then eating more, etc. The houeland list doesn't give that sequential order so the user has to figure it out from the total consumables given.]

Note 2: houeland can't help you in HC (or, I guess, SC ronin) so there is definitely still a place for the compute-on-the-fly approach.

-That's what TH3Y wonder
 
Ok, I had a go at changing a few more things, so that milk of magnesium is better accounted for.

As for houeland being more optimal, I have to agree since this uses a few heuristics and so on. But this is far more flexible, hence trying to bugfix and get it closer to optimal. Moreover, since we know that adventure gains aren't (typically) evenly distributed over the wiki ranges, no tool is perfect.

Things I have changed are:

line 240 simadventures is now a float, not int.
Therefore line 330 returns to_int(simadventures) now.

line 391 features a better milk_adjust calculation.
That requires the calls on lines 983 and 1363 to have a different argument.

line 1317 now returns false if milk is consumed at that stage, so that grub values can be recalculated with milk in effect.
So, line 1592 now does that recalculation, if consumeone returns false.

My current version is attached. I'm going to work on doing the same for ode and tux next...
 

Attachments

My calc is actually very flexible, it's just that it's precomputed when making it available as a webpage since it takes quite a bit of CPU time, so I "only" make 512 different settings available.

It should be doable to compute everything correctly on the fly if you have a bit of local computer time (I've been thinking about writing some javascript webpage actually, but mafia obviously works at least as well) and have the utility function fully determined (specified adv=X, muscle=Y etc. instead of finding all optimal ranges, which is tougher.)

I'm also building an item database with much better advgain accuracy than the wiki data btw (http://www.houeland.com/kol/database/item?name=Ralph IX cognac&mod=all). The data used for the diet page is as good as any publicly known information, which is better than the wiki, and the wiki is better than the epicure.
 
Just tried out the new version:

1) I got the mysterious "FAIL" message for the first time when attempting to consume knob sausage chow mein

2) EatDrink had me consume a bunch of elven moonshine, which I assume is wrong given the abovementioned data error in the eatdrink file. Do I have a stale one because I only updated the .ash to 3.0 and didn't touch any of the data files?
 
First runthru with v3.0. Tuxedo shirt is working. The script wanted 4 Rockin' Wagons, a great dusty, and blackberry schnapps, rather than the usual 9 dustys and a filler. My only comment would be... can the tuxedo shirt be equipped at the beginning of the drinking stage and then switched to prior shirt after the drinking stage is complete, rather than changing shirts for each drink consumption?

Also the first food item mentions a fail, but it goes ahead and gets/consumes the proper amount
 
Just tried out the new version:

1) I got the mysterious "FAIL" message for the first time when attempting to consume knob sausage chow mein

2) EatDrink had me consume a bunch of elven moonshine, which I assume is wrong given the abovementioned data error in the eatdrink file. Do I have a stale one because I only updated the .ash to 3.0 and didn't touch any of the data files?

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!

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!


First runthru with v3.0. Tuxedo shirt is working. The script wanted 4 Rockin' Wagons, a great dusty, and blackberry schnapps, rather than the usual 9 dustys and a filler. My only comment would be... can the tuxedo shirt be equipped at the beginning of the drinking stage and then switched to prior shirt after the drinking stage is complete, rather than changing shirts for each drink consumption?

Also the first food item mentions a fail, but it goes ahead and gets/consumes the proper amount

I think for ode and the Tux, they could be put into effect during the main eatdrink call, rather than each time consumeone is called (in fact milk could probably get away with being there too, with a different heuristic, since it's almost always beneficial).

The first food fail is the same problem as greenriders - ie not a problem, but a misleading message.

It should be doable to compute everything correctly on the fly if you have a bit of local computer time (I've been thinking about writing some javascript webpage actually, but mafia obviously works at least as well) and have the utility function fully determined (specified adv=X, muscle=Y etc. instead of finding all optimal ranges, which is tougher.)

I'm also building an item database with much better advgain accuracy than the wiki data btw (http://www.houeland.com/kol/database/item?name=Ralph IX cognac&mod=all). The data used for the diet page is as good as any publicly known information, which is better than the wiki, and the wiki is better than the epicure.

Your webpage is fantastic, and having it run with user defined input as required would be even more so! Interesting to see your database too - very nice, and reassuring too!
 
Last edited:
Ran v3.0 on one of my alts just now. Mind you, this particular issue probably existed in prior versions, but all I ever did was sim with those, now I'm actually running it.

In this case, I had about 5k meat on hand to start. I am in the habit of starting the day with nothing on hand, collecting meat tree and hippy store reward and going on from there. The script ran find until twinkly wad time... I only had a few on hand and once I ran out of twinkly wads and only had 148 meat on hand remaining, it went into an infinite loop until I stopped it. I'm pretty sure this loop has been mentioned before.

Code:
FAIL: twinkly wad lev:6 gain:1.0 adv:1.0 musc:9.0 myst:9.0 mox:9.0 meat:223 own:13 value:577
Choosing spleen to consume.
Shopping for a twinkly wad in 0 seconds
budgeting 245 for 1 additional twinkly wad. You have 148 meat. You have 0 in inventory already.
That doesn't appear to be enough meat, but maybe it's cheap (or maybe you've got some in the closet). Either way, let's try.
You need 1 more twinkly wad to continue.
retrieve_item returned false and you have 0 of the 1 you requested. You have 148 meat in inventory now.
Failed to get twinkly wad for a max price of 1.1*223=245.3
FAIL: twinkly wad lev:6 gain:1.0 adv:1.0 musc:9.0 myst:9.0 mox:9.0 meat:223 own:13 value:577
Choosing spleen to consume.
KoLmafia declares world peace.

There needs to be something in the code to allow it to break from loops that simply can't be satisfied. Earlier, I ran low on funds while it was trying to buy Rockin' Wagons, so it shifted to great dusty bottles which I had on hand and that was great... but there is no cheaper adventure yielding spleen item so it looped... and in the case of the booze, if I didn't have any, it probably would have looped there as well. In any event, it would be much more graceful if the script could exit cleanly with its recap and an advisory of why the script stopped early rather than having to manually abort and get no recap (without checking the session file and putting the pieces together).

Thanks :)
 
I have been encountering the same thing. The script is going into an infinite loop 3 out of 4 runs for me. Mostly for the reason Spiny pointed out. I love this script; huge time saver for me, but I've had to stop using it as of late due to this fail looping.
 
I had it loop because I had the "pull from clan stash" preference checked but did not have enough karma to cover the pull.
 
Here is a version that includes full ode to booze support. Several changes were required for that, including an expansion of simulation mode ode.

It also now recalculates the value of items BEFORE purchasing suboptimal ones ;) Sorry about that.

Lastly, it now prints a message to explain the FAIL when first using milk/casting ode.

I haven't changed the tux code, because although it's a little clunky changing every time, at least the calculations were already correct for that case.

Use as you desire :)
 

Attachments

I'm pretty slammed right now so QA is light - I'm updating the main post (but not changing version #s) with deathprog's latest, in the hopes that it'll fix the latest bugs he introduced. :)
 
Back
Top