Day 07

import Solution from "./solution.ts";

const cards = [
  "A",
  "K",
  "Q",
  "J",
  "T",
  "9",
  "8",
  "7",
  "6",
  "5",
  "4",
  "3",
  "2",
  "0",
] as const;
type Card = (typeof cards)[number];
type UndoPartial<T> = T extends Partial<infer R> ? R : T;
type Hand = {
  counts: UndoPartial<ReturnType<typeof Object.groupBy<string, Card>>>;
  hand: string;
};

const order: ((h: Hand) => boolean)[] = [
  // Five of a kind
  (h) => Object.values(h.counts).some((v) => v.length === 5),
  // four of a kind
  (h) => Object.values(h.counts).some((v) => v.length === 4),
  // Full house
  (h) =>
    Object.values(h.counts).some((v) => v.length === 3) &&
    Object.values(h.counts).some((v) => v.length === 2),
  // Three of kind
  (h) => Object.values(h.counts).some((v) => v.length === 3),
  // Two pairs
  (h) =>
    Object.values(h.counts).findIndex((v) => v.length === 2) !==
    Object.values(h.counts).findLastIndex((v) => v.length === 2),
  // one pair
  (h) => Object.values(h.counts).some((v) => v.length === 2),
  // high card
  () => true,
];

const compareHands = (a: Hand, b: Hand) => {
  const aOrder = order.findIndex((f) => f(a));
  const bOrder = order.findIndex((f) => f(b));
  if (aOrder !== bOrder) return aOrder - bOrder;
  for (let i = 0; i < a.hand.length; i++) {
    const comp =
      cards.indexOf(a.hand[i] as Card) - cards.indexOf(b.hand[i] as Card);
    if (comp !== 0) return comp;
  }
  return 0;
};

const modifyCounts = (counts: Hand["counts"]) => {
  if (counts.J) {
    const entries = Object.entries(counts).filter(([key]) => key !== "J");
    const hCount = Math.max(...entries.map(([, value]) => value.length));
    if (hCount === Number.NEGATIVE_INFINITY) {
      return counts;
    }
    entries.find(([, value]) => value.length === hCount)![1].push(...counts.J);
    return Object.fromEntries(entries);
  }
  return counts;
};

const task = new Solution(
  (arr: [Hand, number][]) => {
    const sortedHands = arr.toSorted((a, b) => compareHands(b[0], a[0]));
    return sortedHands.reduce((p, c, i) => p + c[1] * (i + 1), 0);
  },
  (arr: [Hand, number][]) => {
    const modifiedHands = arr.map(
      (h) =>
        [
          {
            hand: h[0].hand.replaceAll("J", "0"),
            counts: modifyCounts(h[0].counts),
          },
          h[1],
        ] as [Hand, number]
    );
    const sortedHands = modifiedHands.toSorted((a, b) =>
      compareHands(b[0], a[0])
    );
    return sortedHands.reduce((p, c, i) => p + c[1] * (i + 1), 0);
  },
  {
    transform: (l) =>
      l
        .split(" ")
        .map((s, i) =>
          i === 0
            ? { counts: Object.groupBy(s.split(""), (s) => s), hand: s }
            : Number.parseInt(s)
        ) as [Hand, number],
    sep: "\n",
  }
);
task.expect(6440, 5905);

export default task;

Last edited 04. April 2025 13:29