Prolog how to get max option from many options

Viewed 29

I'm trying to determine max damage done in a Pokémon battle in Prolog. I have the following facts.

pokemon(venusaur).
pokemon(blastoise).
pokemon(charizard).

is_type(venusaur, grass).
is_type(venusaur, poison).
is_type(blastoise, water).
is_type(charizard, fire).
is_type(charizard, flying).

speed(charizard, 100).
speed(blastoise, 78).
speed(venusaur, 80).

attack_of_type(flamethrower, fire).
attack_of_type(scald, water).
attack_of_type(solarbeam, grass).
attack_of_type(earthquake, ground).
attack_of_type(icebeam, ice).
attack_of_type(sludgebomb, poison).
attack_of_type(airslash, flying).
attack_of_type(darkpulse, dark).
attack_of_type(aurasphere, fighting).
attack_of_type(hpfire, fire).

has_attack(charizard, flamethrower).
has_attack(charizard, solarbeam).
has_attack(charizard, airslash).
has_attack(charizard, earthquake).
has_attack(blastoise, scald).
has_attack(blastoise, icebeam).
has_attack(blastoise, darkpulse).
has_attack(blastoise, aurasphere).
has_attack(venusaur, solarbeam).
has_attack(venusaur, sludgebomb).
has_attack(venusaur, earthquake).
has_attack(venusaur, hpfire).

has_power(flamethrower, 90).
has_power(solarbeam, 120).
has_power(airslash, 75).
has_power(earthquake, 100).
has_power(scald, 80).
has_power(icebeam, 90).
has_power(darkpulse, 80).
has_power(aurasphere, 80).
has_power(sludgebomb, 90).
has_power(hpfire, 60).

I am trying to make a rule that gets the maximum amount damage done, but i am unsure as how to go about this. What i have so far is a rule that can determine whether a Pokémon can be killed in the current turn.

hit_supereffectively_by(Pkmn, AtkType) :- 
    is_type(Pkmn, Type), weak(Type, AtkType).

hit_notveryeffectively_by(Pkmn, AtkType) :- 
    is_type(Pkmn, Type), resist(Type, AtkType).

is_immune_to(Pkmn, AtkType) :- 
    is_type(Pkmn, Type), immune(Type, AtkType).

can_kill(Me, You, MyHP, YourHP, MyAttack) :- 
    has_attack(Me, MyAttack), has_power(MyAttack, MyAtkPower), (MyAtkPower / 2) >= YourHP.

can_kill(Me, You, MyHP, YourHP, MyAttack) :- 
    has_attack(Me, MyAttack), attack_of_type(MyAttack, MyAtkType), hit_supereffectively_by(You, MyAtkType), \+ is_immune_to(You, MyAtkType), \+ hit_notveryeffectively_by(You, MyAtkType), 
    has_power(MyAttack, MyAtkPower), MyAtkPower >= YourHP.

best_move(Me, You, MyHP, YourHP, MyAttack) :- 
    is_faster(Me, You), can_kill(Me, You, MyHP, YourHP, MyAttack).

I am trying to extend best_move to the point where, if the first line isn't true (is faster and can kill), then it returns the move that will do the most damage as MyAttack.

Can anyone point me in the right direction as to how to do this? I am new to declarative programming. Tyvm.

1 Answers

It seems from your description that there should be at most a single best move. Thus, you can likely use the if-then-else control construct:

best_move(Me, You, MyHP, YourHP, MyAttack) :- 
    (   is_faster(Me, You),
        can_kill(Me, You, MyHP, YourHP, MyAttack) ->
        true
    ;   % otherwise select move that does most damage
        ...
    ).
Related