pappde / bmai

AI to play Button Men, originally developed to interface with the (now deprecated) unofficial online Button Men website.
MIT License
2 stars 1 forks source link

Turbo - support multiple turbo dice #65

Open danlangford opened 2 weeks ago

danlangford commented 2 weeks ago

im leaving myself a note here to clarify a few things about turbo

1) does bmai support turbo on Option dice as well as Swing? 2) does bmai only specify turbo size if it chooses not to change turbo size?

Turbo: !

After your starting roll, you may change the size of your own Turbo Swing or Option die every time you roll it as part of your attack. Decide on a size first that is valid for the Swing or Option type, then roll the new die as usual.

Interaction with Berserk: Dice with both Berserk and Turbo making a berserk attack will first halve in size and then change to the size specified by the Turbo skill

Interaction with Doppelganger: A Doppelganger die that captures a Turbo die currently does not get the chance to perform an immediate turbo resize

Interaction with Radioactive: Dice with the Turbo skill lose Turbo when they decay due to Radioactive

Interaction with Warrior: A Warrior Turbo die can change size via Turbo after coming into play

there is a game that uses this input

game
fight
player 0 5 42
oH12:8
1/20!-20:10
1/20!-1:1
20:13
o^11:9
player 1 4 26
q20:15
q20:14
8/12-8:6
4:1
ply 3
max_sims 100
min_sims 5
maxbranch 400
surrender off
getaction
quit

and the output is

l1 p0 best move (33.0 points, 100.0% win) attack skill - (0)20:13 + (1800)1:1 -> (4)20:14 stats 3/5-100/400/0.50 Time: 4.000000 s Sim: 2124272 Sims/Sec: 531068.000000 Mvs/Sms | 12.0/33.0 | 4.7/42.5 | 4.4/21.1 = 7355928 action skill 3 2 1

and die idx 2 is a turbo die but it doesn't spit out a turbo size. was that a bug? or a misunderstanding on my part maybe that means it doesn't want to change the size.

pappde commented 2 weeks ago

This is a bug specific to when there are multiple turbo dice. It is only considering m_turbo_option if the first turbo die is involved in the attack. It breaks if there is more than one, and the attack involves one of the subsequent turbo dice.

The problem is in GenerateValidAttacks(), it has code that says "only do m_turbo_option if one of the attacking dice is turbo".

    INT turbo_die = attacker->HasDieWithProperty(BME_PROPERTY_TURBO);
    if (turbo_die>0)
    {
        turbo_die--;    // HasDieWithProperty() returns index+1
...
                case BME_ATTACK_TYPE_N_1:
                {
                    if (!attack->m_attackers.IsSet(turbo_die))
                        continue;
                    break;
                }

If you look at HasDieWithProperty(), it returns the first die that has a that property.

SOLUTION

A quick partial fix would update GenerateValidAttacks like this (pseudocode):

  INT turbo_dice = CountDiceWithProperty(TURBO)
  if (turbo_dice > 0) 
    ...
    foreach move
      ...
      // does move involve a turbo die?
      turbo_die = find first attacking die with property (TURBO)
      if (turbo_die == 0) continue; // next move

BACKLOG The above isn't a complete solution since the code as written only supports one turbo die. Recommend splitting off a new issue to support multiple turbo dice. It doesn't look straightforward since the BMC_MOVE class only supports specifying the option/sides for one turbo die. It would have to be updated to support setting for multiple attacking dice.

Worth noting that in the meantime, an attack that involves multiple turbo option/swing dice could generate an incorrect move. E.g. look at the output code - it reads the same "_move.m_turbo_option" property for all attacking dice.


    // send TURBO
    if (_move.m_turbo_option>=0)
    {
        INT i;
        for (i=0; i<attacker->GetAvailableDice(); i++)
        {
            att_die = attacker->GetDie(i);
            if (!att_die->HasProperty(BME_PROPERTY_TURBO))
                continue;

            if (att_die->HasProperty(BME_PROPERTY_OPTION))
            {
                Send("option %d %d\n", att_die->GetOriginalIndex(), att_die->GetSides(_move.m_turbo_option));
                break;
            }
            else // TURBO SWING
            {
                Send("swing %c %d\n", BMD_FIRST_SWING_CHAR + att_die->GetSwingType(0) - BME_SWING_FIRST, _move.m_turbo_option);
                break;
            }
        }