Active Time Battle AI :: Am I doing it right?

My game has a similar battle system like Final Fantasy however in my system the player and the AI will only fight with one character at a time.
I’m fairly new to game developing and AI systems so I followed the advice of this article.
It suggests to use formulas to simulate certain desires instead of hard coded values like


if(ammo == 0) {
  reload();
}

I tried my best and the result does look okay-ish. Could someone help me to improve it?
Here is the code of my behavior class. Each time it’s my AI’s turn the method getBehavior(Hero target) will be called.



	private static final String BEHAVIOR_ATTACK = "attack";
	private static final String BEHAVIOR_DEFEND = "defend";
	private static final String BEHAVIOR_REGSTAM = "regstam";
	private static final String BEHAVIOR_SKILL = "skill";
	
	private Enemy host;
	private float attackBias;
	private float skillBias;
	private float defendBias;
	
	private float lastTurnHealth; // currently unused
	private float lastTurnStamina; // currently unused
	
	private Hero target;
	private float lastTurnTargetHealth; // currently unused
	
	public Behavior(Enemy enemy) {
		this.host = enemy;
		this.attackBias = 0.2f;
		this.skillBias = 0.1f;
		this.defendBias = 0.2f;
		
		this.lastTurnHealth = 1;
		this.lastTurnStamina = 1;
		this.lastTurnTargetHealth = 1;
	}
	
	public void reset(){
		this.lastTurnHealth = 1;
		this.lastTurnStamina = 1;
		this.lastTurnTargetHealth = 1;
		this.target = null;
	}
	
	/**
	 *  The desire rises as the target has less health.
	 *  The basic formula is 1/(0.75 + e^(targetHealthPercent / attackBias))
	 * @return the desire to attack the target
	 */
	private double desireOfAttack() {
		return 1/(0.75 + Math.pow(Math.E, (target.getHealthPercent() / attackBias)));
	}
	
	/**
	 * The desire rises as the target has less health but lowers as the host's stamina gets low.
	 * The basic formula is 1 / (0.74 + e^((targetHealthPercent / skillBias) / hostStaminaPercent)) 
	 * @return the desire to attack the target with a skill
	 */
	private double desireOfSkillUse(){
		return 1 / (0.74 + Math.pow(Math.E,((host.getHealthPercent() / skillBias) / host.getStaminaPercent())));
	}
	
	/**
	 * The desire rises as the host has less health.
	 * The basic formula is 1/(1 + e^(10*hostHealthPercent - 10*defendBias)
	 * @return the desire to defend against the targets attacks
	 */
	private double desireOfDefend() {
		return 1/(1 + Math.pow(Math.E, (10 * host.getHealthPercent()) - (10 * defendBias)));
	}
	
	/**
	 * The desire rises as the host has less stamina.
	 * The basic formula is 1/(1 + e^(10 * hostStaminaPercent)
	 * @return the desire to defend and regenerate stamina
	 */
	private double desireOfStaminaRegeneration(){
		return 1/(1 + Math.pow(Math.E, 10*host.getStaminaPercent()));
	}
	
	public CombatAction getBehavior(Hero target) {
		
		TreeMap<Double, String> desireMap = new TreeMap<>();
		
		if(target != this.target) {
			this.target = target;
			this.lastTurnTargetHealth = target.getHealthPercent();
		}
		
		desireMap.put(desireOfAttack(), BEHAVIOR_ATTACK);
		desireMap.put(desireOfDefend(), BEHAVIOR_DEFEND);
		desireMap.put(desireOfStaminaRegeneration(), BEHAVIOR_REGSTAM);
		if(host.getSkills().size() > 0){
			desireMap.put(desireOfSkillUse(), BEHAVIOR_SKILL);
		}
		
		System.out.println("AnxietyMap: "+ desireMap.descendingMap().toString());
		
		this.lastTurnStamina = host.getStaminaPercent();
		this.lastTurnHealth = host.getHealthPercent();
		
		return getBehaviorAction(desireMap.descendingMap().values().toArray()[0].toString());
	}
	
	private CombatAction getBehaviorAction(String behavior){
		CombatAction action = new CombatAction();
		
		switch (behavior) {
		case BEHAVIOR_ATTACK:
			action.skillUse(host, target, SkillBook.Enemy.attack);
			break;

		case BEHAVIOR_REGSTAM:
		case BEHAVIOR_DEFEND:
			host.isDefending(true);
			host.regenerateStamina(true);
			break;
			
		case BEHAVIOR_SKILL:
			action.skillUse(host, target, getRandomSkill());
			break;
			
		default:
			break;
		}
		
		
		
		return action;
	}
	
	private Skill getRandomSkill(){
		return host.getSkills().get(MoreMath.random(0, host.getSkills().size()-1));
	}

I want to extend the methods later to consider the “lastTurnXYZ” variables to simulate hesitation (when the player hits really really hard), euphoria (the player lost a really good chunk of health) and desperation.
Is this approach fine or should I redo it in another way?

This looks pretty good to me. I would be interested to see the final version.

One idea is to think about how you can turn your Behaviors into separate objects, which will come in handy as they get more numerous and more complex. Something like:


public interface Behavior {
   
   float getDesirability();

   CombatAction getAction();
}


public class AttackBehavior implements Behavior { ... }

public class DefendBehavior implements Behavior {...}

// etc

This would also make it easier to do things like evaluate the most desirable Behavior:


Behavior bestChoice = null;
float highestScore = -1;

// Assume a list of behaviors
for (Behavior behavior : behaviors) {
   float score = behavior.getDesirability();
   if  (score > maxScore) {
      bestChoice = behavior;
      maxScore = score;
   }
}

This seems easier than throwing everything in a tree map like you are doing. If there would only be a single instance of each behavior you could look into making them enums.