2023 - Day 7
This commit is contained in:
@@ -0,0 +1,334 @@
|
||||
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));
|
||||
Reference in New Issue
Block a user