Advent of code 2023/7
Ajax Direct

Answer

Part 1 :
Part 2 :
function hand_power($cards, $regex) {
    $cards = $cards->sort()->reverse()->join("");
    foreach ($regex as $i=>$r)
        if (preg_match($r, $cards)) return $i;
    return INF;
}

function solve($input, $power_regex, $ranks) {
    return $input->lines->map(function ($line) use ($ranks, $power_regex) {
        [$cards, $bid] = $line->split(" ");
        $cards = $cards->chars()->map(fn ($c) => $ranks[$c]);
        return [
            $cards->join(""),
            hand_power($cards, $power_regex),
            $bid
        ];
    })
    ->sort(fn ($a, $b) =>
        $b[1] <=> $a[1] ?: $a[0] <=> $b[0]
    )->values()->map(fn ($hand, $i) =>
        int($hand[2]) * ($i + 1)
    , true)->sum();
}

// ==================================================
// > PART 1
// ==================================================
$ranks = array_combine(
    ["A","K","Q","J","T","9","8","7","6","5","4","3","2"],
    array_merge(range("D", "A"), range(9, 1))
);

$solution_1 = solve($input, [
    "/(.)\\1{4}/",                  // Five of a kind
    "/(.)\\1{3}/",                  // Four of a kind
    "/^(.)\\1{1,2}(.)\\2{1,2}$/",   // Full house
    "/(.)\\1{2}/",                  // Three of a kind
    "/(.)\\1.?(.)\\2/",             // Two pair
    "/(.)\\1/",                     // One pair
], $ranks);

// ==================================================
// > PART 2
// ==================================================
$ranks["J"] = 0;

$solution_2 = solve($input, [
    "/(.)(?:\\1|0){4}/",
    "/(.)(?:.*(?:\\1|0)){3}/",
    "/^(?:(?:(.)\\1{1,2}(.)\\2{1,2})|(?:(.)\\3(?:(.)\\4)0))$/",
    "/(.)(?:.*(?:\\1|0)){2}/",
    "/(.)\\1.?(.)\\2/",
    "/(.)(?:.*(?:\\1|0)){1}/",
], $ranks);