Advent of code 2015/22
Ajax Direct

Answer

Part 1 :
Part 2 :
// ==================================================
// > DATA
// ==================================================
// Boss stats
[$boss_health, $boss_dmg] = $input->numbers();

// Spells information : cost, dmg, heal, duration, armor, mana
$spells = [
    "Magic Missile" => [53,  4, 0, 0, 0, 0],
    "Drain"         => [73,  2, 2, 0, 0, 0],
    "Shield"        => [113, 0, 0, 6, 7, 0],    // e1
    "Poison"        => [173, 3, 0, 6, 0, 0],    // e2
    "Recharge"      => [229, 0, 0, 5, 0, 101],  // e3
];

// ==================================================
// > EXPLORATION
// ==================================================
$graph = new Graph(function ($graph) use ($boss_dmg, $spells) {
    // Current state
    [$turn, $hp, $mana, $boss, $e1, $e2, $e3] = array_map("intval", explode("|", $graph->current));

    // Apply effects and decrease timers
    if ($e2) $boss -= $spells["Poison"][1];
    if ($e3) $mana += $spells["Recharge"][5];
    $e1 = max(0, $e1 - 1);
    $e2 = max(0, $e2 - 1);
    $e3 = max(0, $e3 - 1);

    // Boss's turn : change current state without any decision or mana cost
    if (!($turn % 2)) {
        $hp -= max(1, $boss_dmg - ($e1 ? $spells["Shield"][4] : 0));
        return [($turn+1)."|$hp|$mana|$boss|$e1|$e2|$e3" => 0];
    }

    // Hard mode : lose 1 hp at the start of each player's turn
    if (!empty($graph->hardMode)) {
        $hp--;
        if ($hp <= 0) return [];
    }

    // Player's turn : cast a spell
    $next_turn = [];

    foreach ($spells as $spell => [$cost, $dmg, $heal, $duration]) {
        // Check if spell is available
        if ($mana < $cost) continue;
        if ($e1 && $spell == "Shield") continue;
        if ($e2 && $spell == "Poison") continue;
        if ($e3 && $spell == "Recharge") continue;

        // Cast spell
        $next_turn[join("|", [
            $turn + 1,
            $hp + $heal,
            $mana - $cost,
            $boss - ($duration ? 0 : $dmg),
            $spell == "Shield" ? $duration : $e1,
            $spell == "Poison" ? $duration : $e2,
            $spell == "Recharge" ? $duration : $e3
        ])] = $cost;
    }

    return $next_turn;
});

// End when boss is dead and player is alive with mana
$graph->defineEnd(function ($graph) {
    $state = explode("|", $graph->current);
    return $state[1] > 0 && $state[2] > 0 && $state[3] <= 0;
});

// ==================================================
// > SOLUTION
// ==================================================
// Start with player health, mana, boss health and effect tracking
$solution_1 = $graph->explore("-1|50|500|$boss_health|0|0|0")[1];

$graph->hardMode = true;
$solution_2 = $graph->explore("-1|50|500|$boss_health|0|0|0")[1];