Files
advent-of-code-2022/2023/07/solution.bak.ts
2024-07-29 00:09:03 +02:00

335 lines
8.1 KiB
TypeScript

const sample = await Deno.readTextFile("sample.txt");
const input = await Deno.readTextFile("input.txt");
const cardsSolution1 = [
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"T",
"J",
"Q",
"K",
"A",
] as const;
const cardsSolution2 = [
"J",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"T",
"Q",
"K",
"A",
] as const;
type CardListSolution1 = typeof cardsSolution1;
type CardListSolution2 = typeof cardsSolution2;
type CardList = CardListSolution1 | CardListSolution2;
type Card = typeof cardsSolution1[number];
type Cards = string;
type Hand = [
[Card, number],
[Card, number],
[Card, number],
[Card, number],
[Card, number],
];
type GroupedHand = Partial<Record<Card, number>>;
type CardCounts = number[];
const getCardValue = (
cards: CardList,
card: Card,
): number => cards.indexOf(card) + 1;
const groupHand = (hand: Hand): GroupedHand =>
hand.reduce(
(acc, [card]) => ({ ...acc, [card]: (acc[card] || 0) + 1 }),
{} as GroupedHand,
);
const countSameCards = (
groupedHand: GroupedHand,
withJokers = false,
): CardCounts => {
if (!withJokers) return Object.values(groupedHand).sort((a, b) => b - a);
const groupedHandWithoutJokers = { ...groupedHand } satisfies GroupedHand;
delete groupedHandWithoutJokers.J;
return Object.values(groupedHandWithoutJokers).sort((a, b) => b - a);
};
class JokerCounter {
constructor(private jokers: number) {}
getMax() {
const jokers = Math.max(0, this.jokers);
this.jokers = this.jokers - jokers;
return jokers;
}
getDelta(max: number, current: number) {
const jokersNeeded = Math.abs(max - current);
const currentNumberOfJokers = this.jokers;
const hasEnoughJokers = currentNumberOfJokers >= jokersNeeded;
if (!hasEnoughJokers) {
this.jokers = 0;
return currentNumberOfJokers + current;
}
this.jokers = this.jokers - jokersNeeded;
return max;
}
get(count = 1) {
const jokers = Math.max(0, this.jokers - count);
this.jokers = this.jokers - jokers;
return jokers;
}
}
const handTypes = [
function fiveOfAKind(
cardCounts: CardCounts,
groupedHand: GroupedHand,
withJokers = false,
): boolean {
const jokers = new JokerCounter(withJokers ? groupedHand.J || 0 : 0);
return jokers.getDelta(5, cardCounts[0]) >= 5;
},
function fourOfAKind(
cardCounts: CardCounts,
groupedHand: GroupedHand,
withJokers = false,
): boolean {
const jokers = new JokerCounter(withJokers ? groupedHand.J || 0 : 0);
return jokers.getDelta(4, cardCounts[0]) >= 4;
},
function fullHouse(
cardCounts: CardCounts,
groupedHand: GroupedHand,
withJokers = false,
): boolean {
const jokers = new JokerCounter(withJokers ? groupedHand.J || 0 : 0);
return (jokers.getDelta(3, cardCounts[0]) === 3 &&
jokers.getDelta(2, cardCounts[1]) === 2);
},
function threeOfAKind(
cardCounts: CardCounts,
groupedHand: GroupedHand,
withJokers = false,
): boolean {
const jokers = new JokerCounter(withJokers ? groupedHand.J || 0 : 0);
return jokers.getDelta(3, cardCounts[0]) === 3 &&
jokers.getDelta(1, cardCounts[1]) === 1 &&
jokers.getDelta(1, cardCounts[2]) === 1;
},
function twoPair(
cardCounts: CardCounts,
groupedHand: GroupedHand,
withJokers = false,
): boolean {
const jokers = new JokerCounter(withJokers ? groupedHand.J || 0 : 0);
const numberOfPairs = cardCounts.filter((count) => count === 2).length;
if (numberOfPairs === 2) return true;
if (numberOfPairs === 1) return jokers.get(2) === 2;
return jokers.get(2) === 2 && jokers.get(2) === 2;
},
function onePair(
cardCounts: CardCounts,
groupedHand: GroupedHand,
withJokers = false,
): boolean {
const jokers = new JokerCounter(withJokers ? groupedHand.J || 0 : 0);
const hasOnePair = cardCounts.filter((count) => count === 2).length === 1;
if (hasOnePair) return true;
return jokers.get(2) === 2;
},
function highCard(
cardCounts: CardCounts,
groupedHand: GroupedHand,
withJokers = false,
): boolean {
const jokers = new JokerCounter(withJokers ? groupedHand.J || 0 : 0);
const length = cardCounts.length;
return jokers.getDelta(5, length) === 5;
},
];
const handTypeName = [
"fiveOfAKind",
"fourOfAKind",
"fullHouse",
"threeOfAKind",
"twoPair",
"onePair",
"highCard",
] as const;
const compareHands = (
cards: CardList,
) =>
(
[, hand1, , handType1]: [Cards, Hand, number, number],
[, hand2, , handType2]: [Cards, Hand, number, number],
): -1 | 0 | 1 => {
if (handType1 < handType2) {
return -1;
} else if (handType1 > handType2) {
return 1;
} else {
const hand1TotalValue = hand1.reduce(
(s, [card]) => s + getCardValue(cards, card),
0,
);
const hand2TotalValue = hand2.reduce(
(s, [card]) => s + getCardValue(cards, card),
0,
);
console.log(
"hand1",
handType1,
hand1,
hand1TotalValue,
);
console.log(
"hand2",
handType2,
hand2,
hand2TotalValue,
);
return hand1TotalValue > hand2TotalValue ? 1 : -1;
}
// for (let i = 0; i < 5; i += 1) {
// console.log(
// "hand1",
// handType1,
// hand1[i][0],
// getCardValue(cardsSolution1, hand1[i][0]),
// );
// console.log(
// "hand2",
// handType2,
// hand2[i][0],
// getCardValue(cardsSolution1, hand2[i][0]),
// );
// if (hand1[i] > hand2[i]) return 1;
// if (hand1[i] < hand2[i]) return -1;
// }
// return 0;
// }
};
const solvePart1 = (data: string): number => {
return data
.split("\n")
.filter(Boolean)
.map((line) => line.split(" "))
// Convert lines to hands and bids
.map((
[hand, bid],
): [Cards, Hand, number] => {
const [card1, card2, card3, card4, card5] = hand.toUpperCase().split("")
.map((
card,
): [Card, number] => [
card as Card,
getCardValue(cardsSolution1, card as Card),
]);
return [
hand,
[card1, card2, card3, card4, card5],
Number(bid),
];
// Determine hand type per hand
}).map((
[cards, hand, bid],
): [Cards, Hand, number, number] => [
cards,
hand,
bid,
handTypes.length -
(handTypes.findIndex((handType) => {
return handType(countSameCards(groupHand(hand)), groupHand(hand));
}) + 1),
])
// Sort the hands by hand type and card value
.sort(compareHands(cardsSolution1)).map((
result,
index,
): [Cards, Hand, number, number, number, number] => [
...result,
index + 1,
(index + 1) * result[2],
])
.reduce((s, [, , , , , v]) => s + v, 0);
};
console.log("Sample:", solvePart1(sample)); // 6440
console.log("Input", solvePart1(input)); // 251927063
const solvePart2 = (data: string): number => {
const r = data
.split("\n")
.filter(Boolean)
.map((line) => line.split(" "))
// Convert lines to hands and bids
.map((
[hand, bid],
): [Cards, Hand, number] => {
const [card1, card2, card3, card4, card5] = hand.toUpperCase().split("")
.map((
card,
): [Card, number] => [
card as Card,
getCardValue(cardsSolution2, card as Card),
]);
return [
hand,
[card1, card2, card3, card4, card5],
Number(bid),
];
// Determine hand type per hand
}).map((
[cards, hand, bid],
): [Cards, Hand, number, number] => [
cards,
hand,
bid,
handTypes.length -
(handTypes.findIndex((handType) => {
return handType(
countSameCards(groupHand(hand), true),
groupHand(hand),
true,
);
}) + 1),
])
// Sort the hands by hand type and card value
.sort(compareHands(cardsSolution2)).map((
result,
index,
): [Cards, Hand, number, number, number, number] => [
...result,
index + 1,
(index + 1) * result[2],
]);
console.log(
"r",
r,
);
return r.reduce((s, [, , , , , v]) => s + v, 0);
};
console.log("Sample:", solvePart2(sample));
// console.log("Input", solvePart2(input));