MMG toolbox

Veracity

Developer
Staff member
I've been fooling around with the MMG a bit recently. Due to pure RNG winnage, I'm actually substantially up, but I have no illusions about that being anything other than pure luck; there is no strategy which will guarantee winnings. All you can do is control your losses, and given bad enough RNG, you are not guaranteed to be able to do that; it's not written anywhere that you CAN'T lose 10 times (or 20 times - or 50 times) in a row.

It's piqued my interest in doing a couple things:

- Tracking all visits/transactions/events to try and maintain your meat totals in the session log. Note that your meat balance is updated every time we get a char pane refresh, so we're good with that, but it would be interesting to see your net winnings/losings correctly in the session tally, rather than only detecting meat coming in when you take and win bets and not detecting meat going out when you place bets or take and lose bets - and not detecting meat coming in when you offer and win bets.

- I could make a little "MMG toolbox", tied in with the above, to enable ASH scripting of MMG strategies. All of them doomed, of course, but still...

Most of this could be done in pure ASH scripting. However, maintaining the session tally, and interacting closely with events, whether they arrive in chat or via refreshing another page seems beyond ASH, so, some built-in support seems reasonable.

In any case, here's what I'm thinking. I am sure some of you have a lot more experience with the MMG than I have - or want to have. Tell me if I'm missing anything. Thanks!

---

Here's what I observe about KoL's UI for the MMG, and what KoLmafia would have to track whenever you visit an MMG page, either in the relay browser or via a KoLmafia request of some sort:

Data structures KoLmafia needs to maintain:

Map int [int] current;
- Your currently outstanding bets. maps from bet # -> amount

Map boolean [int] hagnks;
- true if bet used meat from Hagnk' storage

Map int [int] resolved;
- Your bets which have been taken but for which we have not received the notification.

Map int [int] events;
- Your bets which have been taken and for which we have received the notification, but for which you have not retrieved the event. If you are not running an MMG script, this could grow without bound...

Map int [int] offered
- Bets offered by others, last time the bet page was visited. maps from bet # -> amount

Map String [int] offerers;
= Who is offering a particular bet number. Not especially useful, unless you wish to ignore bets from certain people, for some reason.

Operations: things you can do from the Relay Browser which KoLmafia watches:

Visit Bets: When you visit the "bets" page

- Parses list of bets offered and replaces/refreshes two maps:
-- offered: bet # -> bet amount
-- offerers: bet # -> bet offerer

- Parses list of your current bets and makes a "temp" map of current bets: bet # -> amount

- Iterates over list of "current" bets
-- Move any bet which is not on "temp" to "resolved"
-- Move "temp" to "current"

Place Bet: When you place a bet for xxx meat

- Your bet is accepted and appears in the page text as bet # yyy on the list of "retract bet" buttons
- Your bet is rejected because you don't have the cash
- Your bet is rejected because you already have 5 bets out.

If bet was accepted, subtract xxx from meat tally (unless from Hagnks) and add to map of "current" bets: bet # -> amount

Retract Bet: When you retract a bet

- You successfully retract it
- It can't find the bet

If you retract it, remove the bet from "current" bets and add xxx to your meat tally (unless from Hagnks).

Take Bet: When you take a bet

- If you fail to take it (retracted or otherwise gone), do nothing
- Otherwise, add winnings or subtract losings to meat tally (unless from Hagnks)

MMG Event: When you receive an MMG "event"
- Remove bet from "resolved" or "current", as appropriate and add to "events"
- Add or subtract winnings/losings to meat

The tricky thing is figuring out which bet was taken; I don't think the chat message gives you the bet number, and people are not guaranteed to take the bets in the order you offered them. I certainly didn't, in my tests!

ASH interface:

void visit_bets();

(calls "Visit Bets" as above)

int place_bet( int amount, boolean hagnks );

(calls "Place Bet" as above)
- If successfully place the bet, return the bet #
- If fail (too many outstanding bets, not enough meat), return 0

boolean retract_bet( int xxx );

(calls "Retract Bet" as above)
- If successful, return true
- If bad bet number (possibly because bet is already taken), return false

int [int] current_bets();

This returns whatever "current" is - the outstanding bets you have offered; it does not call Visit Bets to find out what is currently out there

int current_bet_count();

This returns the number of bets in "current" - from 0 to 5. It does not call "Visit Bets" to see if any have been taken with no notification in yet (i.e., now on "resolved")

int [int] offered_bets();

- this returns whatever "offered" is; it does not call Visit Bets to find out what is currently out there

string bettor( int xxx );

- returns name of player who offered bet # xxx

int take_bet( int xxx )

(calls "Take Bet" as above)
- returns winnings or losings if successfully took the specified bet
- returns 0 if failed to take bet, because bet was not available or you didn't have enough money.

int wait_mmg_event()

- waits for the next MMG event and returns the bet number that is finally resolved.
- returns 0 if you have no outstanding bets, there is nothing on "resolved", and there is nothing on "events"
- otherwise, waits until something is added to "events" and pulls off the first one.

This is the only way something is removed from "events".
 

zarqon

Well-known member
Looks ridiculously well thought-out. I like the easy way this saves server hits.

current_bet_count() seems unnecessary, given count(current_bets()).

And, I may just name my Fuzzy Dice "Bettor" if you don't mind. Or, all caps: BETTOR. Yes.
 

zarqon

Well-known member
Not sure how you pronounce debtor, but I pronounce BETTOR with a long 'o'. And a deep voice. :)
 

Veracity

Developer
Staff member
I'm going to make my initial release of this. I don't yet support TAKING bets (although I'm close), but everything for receiving bets works nicely enough for tracking multiple chains of bets that you offer and keeping your session tally up-to-date with your net meat gains.

Here's the API for this:

void mmg_visit();

Visits the bet page and remembers which bets you currently have made and which ones are available to take.

int mmg_make_bet( int amount, boolean storage );

Place a bet of the specified amount using meat from inventory (false) or storage (true). Returns the bet ID # if successful, or 0 if unsuccessful. You will be unsuccessful if you try already have 5 bets out or don't have enough meat. Or, presumably, if you don't have a casino pass.

boolean mmg_retract_bet( int bet_id );

Tries to retract the specified bet. Returns true if successful, and false if unsuccessful - presumably because bet was already taken.

int [int] mmg_my_bets();

Returns a map of (index #) to bet ID for your current bets.

int mmg_wait_event( int milliseconds );

Waits for one of your outstanding bets to be taken - and reported by KoL. Returns the bet ID # of the taken bet, or 0 if the call timed out./

string mmg_bet_taker();

The player who took the bet which was just returned by mmg_wait_event().

int mmg_bet_taker_id();

The id # of that player.

int mmg_bet_winnings();

How much money you just won or lost according to that event. ( winnings - amount bet ) is the net change to your purse.

I also have the following API, which works, but which won't be useful until I provide mmg_take_bet() and do the corresponding tracking of meat gains/losses:

int [int] mmg_offered_bets();

Returns a map of (index #) to bet ID for bets currently offered by other people.

string mmg_bet_owner( int bet_id );

The player name who offered the bet.

string mmg_bet_owner_id( int bet_id );

The player id # who offered the bet.

int mmg_bet_amount( int bet_id );

The amount of the bet.

I attach two files for your amusement:

mmg2.ash - a Martingale script that runs multiple chains at once. You specify the initial bet amount, the multiplication factor when you lose, the number of chains, and the number of iterations per chain.

mmg.out.txt - a sample run of this script with (1000, 2.0,
 

Attachments

  • mmg.out.txt
    3.9 KB · Views: 155
  • mmg2.ash
    2 KB · Views: 169
Last edited:

halfvoid

Member
i dig the output of the sample script. i've edited it to add the dump to closet functionality of that other MMG script in the turn burning forum. will upload soonly.
 

Attachments

  • mmg2closet.ash
    2.6 KB · Views: 100
Last edited:

Veracity

Developer
Staff member
I've added support for taking bets in the MMG, now. In addition to accurately tracking meat taken from/added to inventory/storage, there is an ASH interface.

int mmg_take_bet( int bet_id, boolean storage );

Returns -(bet price) if you lost and (winnings - bet price) if you won. I.e., the change to your purse.

I have no clue what "strategy" people would use for this, but obviously people ARE taking bets. Here's a sample of using this. It uses mmg_search to find bets that are less than some percentage of your available meat, and then takes the first bet offered. If it doesn't find one, it uses wait() and tries again in a second.

Note that if you are also making bets, you can use mmg_wait_event() to do your waiting.

Code:
void main( float fraction, int bets )
{
  int total = 0;
  while ( bets > 0 )
  {
    int max = round( to_float( my_meat() ) * fraction );
    mmg_search( 0, max );
    int [ int ] offered = mmg_offered_bets();
    if ( count( offered ) == 0 )
    {
      wait( 1 );
      continue;
    }
    int bet_id = offered[0];
    string owner = mmg_bet_owner( bet_id );
    int amount = mmg_bet_amount( bet_id );
    print( "Taking bet #" + bet_id + " from " + owner + " for " + amount );
    int winnings = mmg_take_bet( bet_id, false );
    if ( winnings == 0 )
    {
      continue;
    }
    print( "Net change to purse = " + winnings );
    total = total + winnings;
    bets = bets - 1;
  }
  print( "Total change to purse = " + total );
}
 

Veracity

Developer
Staff member
FWIW, I attach an update to my earlier posted MMG script.

- As suggested, can move meat to closet when you exceed a threshold
- Can use meat from storage, rather than from inventory

Control of both of the above is via a configuration variable, rather than a parameter to main

- If a chain fails (due to lack of meat, presumably), save it, and continue with other chains (which you might have sufficient meat for). When all chains have either finished or failed, print any failed chains before your final results.
- For each bet, include chain, iteration, and now also try #; try 7 is the bet you make when you've lost 6 times in a row on a chain.

Unless I get feedback on how to improve ASH support for this - or bug reports - I think I'm done with the MMG. Good luck! :D
 

Attachments

  • mmg2.ash
    2.8 KB · Views: 128

halfvoid

Member
well i might just like this one better.

(edit: actually, after looking through the code to see exactly what it does and/or what had changed, i think this might be the perfect MMG script.)
 
Last edited:

codster62

Member
Ok, I am trying to use this script, and right off the bat, I get an error.

Undefined reference to function 'mmg_make_bet' (mmg2.ash, line 25)

Please help me out. I am really wanting to use this. ;)
 

Veracity

Developer
Staff member
Get a current build.

Here's another update, by the way:

- I added another configurable option: loss_threshold. After you've lost this many times in a row, it gives up and restarts at your initial bet amount. If it scares you to see more than half your Meat go out in a single bet, after you've lost 7 in a row, you could use this to cut and run earlier. (Considering that it's the MMG, there is no winning strategy possible, but consider this to be Yet Another Tool to slow down your inevitable bankruptcy. ;))
- Improved logging. Consider the following from my session log:

Betting 3002 meat from inventory
> Bet 1/41/1: for 3002 Meat -> bet #58652461
> Waiting for MMG event...
> Bet 1/41/1 (#58652461) taken by Magus53: -3002 / -3002 / 118648
Betting 6064 meat from inventory
> Bet 1/41/2: for 6064 Meat -> bet #58652469
> Waiting for MMG event...
> Bet 1/41/2 (#58652469) taken by bup: -6064 / -9066 / 112584
Betting 12249 meat from inventory
> Bet 1/41/3: for 12249 Meat -> bet #58652474
> Waiting for MMG event...
> Bet 1/41/3 (#58652474) taken by andreaes: 12224 / 3158 / 124808

The bet annotation - 1/41/2 - says "chain 1, bet 41, try 2".
The meat annotation - -6064 / -9066 / 112584 - says "I lost 6064 from this bet, have lost 9066 so far on this sequence, but am up 112584 for the run.
The following bet was won. The result - 12224 / 3158 / 124808 - shows that that particular bet brought in 12224 Meat, but the net gain for the series was only 3158 Meat (considering that the first two bets were pure loss), and the run's profit is up to 124808 Meat.
 

Attachments

  • mmg2.ash
    3.2 KB · Views: 127
Top