Skip to content

Commit 5e636d9

Browse files
committed
feat(day07): part 2
1 parent 1fea7e1 commit 5e636d9

File tree

1 file changed

+175
-97
lines changed

1 file changed

+175
-97
lines changed

day07_test.ts

Lines changed: 175 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -9,81 +9,164 @@ const example = [
99
];
1010

1111
Deno.test("Day 7: Camel Cards", async (t) => {
12-
await t.step("Example", async (t) => {
12+
await t.step("Part 1", async (t) => {
13+
const cardStrengths = [
14+
"A",
15+
"K",
16+
"Q",
17+
"J",
18+
"T",
19+
"9",
20+
"8",
21+
"7",
22+
"6",
23+
"5",
24+
"4",
25+
"3",
26+
"2",
27+
];
28+
29+
await t.step("Example", async (t) => {
30+
await t.step(
31+
"it should solve the example",
32+
() => assertEquals(totalWinnings(cardStrengths, example), 6440),
33+
);
34+
});
35+
36+
await t.step("Solution", async (t) => {
37+
await t.step("it should solve", async () =>
38+
assertEquals(
39+
totalWinnings(
40+
cardStrengths,
41+
(await Deno.readTextFile("./input/day07.txt")).split("\n"),
42+
),
43+
251545216,
44+
));
45+
});
46+
47+
await t.step("handType()", async (t) => {
48+
for (
49+
const [hand, expectedType] of [
50+
["AAAAA", HandType.FiveOfAKind],
51+
["AA8AA", HandType.FourOfAKind],
52+
["23332", HandType.FullHouse],
53+
["TTT98", HandType.ThreeOfAKind],
54+
["23432", HandType.TwoPair],
55+
["A23A4", HandType.OnePair],
56+
["23456", HandType.HighCard],
57+
[`32T3K`, HandType.OnePair],
58+
[`KTJJT`, HandType.TwoPair],
59+
[`KK677`, HandType.TwoPair],
60+
[`T55J5`, HandType.ThreeOfAKind],
61+
[`QQQJA`, HandType.ThreeOfAKind],
62+
] as Array<[string, HandType]>
63+
) {
64+
await t.step(
65+
`${hand} should be type ${expectedType}`,
66+
() => assertEquals(getHandType(hand), expectedType),
67+
);
68+
}
69+
});
70+
71+
await t.step("compare()", async (t) => {
72+
await t.step(
73+
`33332 and 2AAAA are both four of a kind hands, but 33332 is stronger because its first card is stronger`,
74+
() => assertEquals(compareByCards(cardStrengths)("33332", "2AAAA"), 1),
75+
);
76+
await t.step(
77+
`77888 and 77788 are both a full house, but 77888 is stronger because its third card is stronger (and both hands have the same first and second card)`,
78+
() => assertEquals(compareByCards(cardStrengths)("77788", "77888"), -1),
79+
);
80+
await t.step(
81+
`T55J5 and QQQJA are both three of a kind. QQQJA has a stronger first card`,
82+
() => assertEquals(compareByCards(cardStrengths)("QQQJA", "T55J5"), 1),
83+
);
84+
await t.step(
85+
`KK677 and KTJJT are both two pair. Their first cards both have the same label, but the second card of KK677 is stronger (K vs T)`,
86+
() => assertEquals(compareByCards(cardStrengths)("KTJJT", "KK677"), -1),
87+
);
88+
});
89+
1390
await t.step(
14-
"it should solve the example",
15-
() => assertEquals(totalWinnings(example), 6440),
91+
"rank()",
92+
() =>
93+
assertEquals(example.sort(byRankAndCards(cardStrengths)), [
94+
// 32T3K is the only one pair and the other hands are all a stronger type, so it gets rank 1.
95+
`32T3K 765`,
96+
// KK677 and KTJJT are both two pair. Their first cards both have the same label, but the second card of KK677 is stronger (K vs T), so KTJJT gets rank 2 and KK677 gets rank 3.
97+
`KTJJT 220`,
98+
`KK677 28`,
99+
// T55J5 and QQQJA are both three of a kind. QQQJA has a stronger first card, so it gets rank 5 and T55J5 gets rank 4.
100+
`T55J5 684`,
101+
`QQQJA 483`,
102+
]),
16103
);
17104
});
18105

19-
await t.step("Solution", async (t) => {
20-
await t.step("it should solve", async (t) =>
106+
await t.step("Part 2", async (t) => {
107+
const cardStrengths = [
108+
"A",
109+
"K",
110+
"Q",
111+
"T",
112+
"9",
113+
"8",
114+
"7",
115+
"6",
116+
"5",
117+
"4",
118+
"3",
119+
"2",
120+
"J",
121+
];
122+
123+
await t.step("Example", async (t) => {
124+
await t.step(
125+
"it should solve the example",
126+
() =>
127+
assertEquals(totalWinningsWithJoker(cardStrengths, example), 5905),
128+
);
129+
});
130+
131+
await t.step("it should solve", async () =>
21132
assertEquals(
22-
totalWinnings(
133+
totalWinningsWithJoker(
134+
cardStrengths,
23135
(await Deno.readTextFile("./input/day07.txt")).split("\n"),
24136
),
25-
251545216,
137+
250384185,
26138
));
27139
});
140+
});
28141

29-
await t.step("handType()", async (t) => {
30-
for (
31-
const [hand, expectedType] of [
32-
["AAAAA", HandType.FiveOfAKind],
33-
["AA8AA", HandType.FourOfAKind],
34-
["23332", HandType.FullHouse],
35-
["TTT98", HandType.ThreeOfAKind],
36-
["23432", HandType.TwoPair],
37-
["A23A4", HandType.OnePair],
38-
["23456", HandType.HighCard],
39-
[`32T3K`, HandType.OnePair],
40-
[`KTJJT`, HandType.TwoPair],
41-
[`KK677`, HandType.TwoPair],
42-
[`T55J5`, HandType.ThreeOfAKind],
43-
[`QQQJA`, HandType.ThreeOfAKind],
44-
] as Array<[string, HandType]>
45-
) {
46-
await t.step(
47-
`${hand} should be type ${expectedType}`,
48-
() => assertEquals(getHandType(hand), expectedType),
49-
);
50-
}
51-
});
52-
53-
await t.step("compare()", async (t) => {
54-
await t.step(
55-
`33332 and 2AAAA are both four of a kind hands, but 33332 is stronger because its first card is stronger`,
56-
() => assertEquals(compareByCards("33332", "2AAAA"), 1),
57-
);
58-
await t.step(
59-
`77888 and 77788 are both a full house, but 77888 is stronger because its third card is stronger (and both hands have the same first and second card)`,
60-
() => assertEquals(compareByCards("77788", "77888"), -1),
61-
);
62-
await t.step(
63-
`T55J5 and QQQJA are both three of a kind. QQQJA has a stronger first card`,
64-
() => assertEquals(compareByCards("QQQJA", "T55J5"), 1),
65-
);
66-
await t.step(
67-
`KK677 and KTJJT are both two pair. Their first cards both have the same label, but the second card of KK677 is stronger (K vs T)`,
68-
() => assertEquals(compareByCards("KTJJT", "KK677"), -1),
142+
const totalWinnings = (cardStrengths: string[], hands: string[]): number => {
143+
const rankedHands = hands.sort(byRankAndCards(cardStrengths));
144+
return hands
145+
.map(parseHandBids)
146+
.reduce(
147+
(total, [hand, bidAmount]) =>
148+
total + (rankedHands.indexOf(`${hand} ${bidAmount}`) + 1) * bidAmount,
149+
0,
69150
);
70-
});
71-
72-
await t.step("rank()", () =>
73-
assertEquals(example.sort(byRankAndCards), [
74-
// 32T3K is the only one pair and the other hands are all a stronger type, so it gets rank 1.
75-
`32T3K 765`,
76-
// KK677 and KTJJT are both two pair. Their first cards both have the same label, but the second card of KK677 is stronger (K vs T), so KTJJT gets rank 2 and KK677 gets rank 3.
77-
`KTJJT 220`,
78-
`KK677 28`,
79-
// T55J5 and QQQJA are both three of a kind. QQQJA has a stronger first card, so it gets rank 5 and T55J5 gets rank 4.
80-
`T55J5 684`,
81-
`QQQJA 483`,
82-
]));
83-
});
151+
};
84152

85-
const totalWinnings = (hands: string[]): number => {
86-
const rankedHands = hands.sort(byRankAndCards);
153+
const totalWinningsWithJoker = (
154+
cardStrengths: string[],
155+
hands: string[],
156+
): number => {
157+
const rankedHands = hands.sort(
158+
byRankAndCards(cardStrengths, (hand: string) => {
159+
let type = getHandType(hand);
160+
const s = new Set(hand);
161+
if (!s.has("J")) return type; // No Jokers
162+
// Find the best possible hand
163+
for (const card of [...s.values()].filter((c) => c !== "J")) {
164+
let newType = getHandType(hand.replaceAll("J", card));
165+
type = newType < type ? newType : type;
166+
}
167+
return type;
168+
}),
169+
);
87170
return hands
88171
.map(parseHandBids)
89172
.reduce(
@@ -98,30 +181,20 @@ const parseHandBids = (handBid: string): [string, number] => {
98181
return [hand, parseInt(bid, 10)];
99182
};
100183

101-
const cardStrength = [
102-
"A",
103-
"K",
104-
"Q",
105-
"J",
106-
"T",
107-
"9",
108-
"8",
109-
"7",
110-
"6",
111-
"5",
112-
"4",
113-
"3",
114-
"2",
115-
];
116-
117-
const byRankAndCards = (handBid1: string, handBid2: string) => {
118-
const [hand1] = parseHandBids(handBid1);
119-
const [hand2] = parseHandBids(handBid2);
120-
const handType1 = getHandType(hand1);
121-
const handType2 = getHandType(hand2);
122-
if (handType1 < handType2) return 1;
123-
if (handType1 > handType2) return -1;
124-
return compareByCards(hand1, hand2);
184+
const byRankAndCards = (
185+
cardStrengths: string[],
186+
getHandTypeFN?: typeof getHandType,
187+
) => {
188+
const compareStrength = compareByCards(cardStrengths);
189+
return (handBid1: string, handBid2: string) => {
190+
const [hand1] = parseHandBids(handBid1);
191+
const [hand2] = parseHandBids(handBid2);
192+
const handType1 = (getHandTypeFN ?? getHandType)(hand1);
193+
const handType2 = (getHandTypeFN ?? getHandType)(hand2);
194+
if (handType1 < handType2) return 1;
195+
if (handType1 > handType2) return -1;
196+
return compareStrength(hand1, hand2);
197+
};
125198
};
126199

127200
/**
@@ -186,17 +259,22 @@ const cardsInSets = (hand: string): number[] => {
186259
return [...new Set(hand).values()].map(count).sort(desc);
187260
};
188261

189-
const compareByCards = (hand1: string, hand2: string): number => {
190-
for (let i = 0; i < hand1.length; i++) {
191-
const c1 = hand1[i];
192-
const c2 = hand2[i];
193-
if (c1 === c2) continue;
194-
return compareCard(c1, c2);
195-
}
196-
return 0;
197-
};
262+
const compareByCards =
263+
(cardStrength: string[]) => (hand1: string, hand2: string): number => {
264+
for (let i = 0; i < hand1.length; i++) {
265+
const c1 = hand1[i];
266+
const c2 = hand2[i];
267+
if (c1 === c2) continue;
268+
return compareCard(cardStrength, c1, c2);
269+
}
270+
return 0;
271+
};
198272

199-
const compareCard = (card1: string, card2: string): number => {
273+
const compareCard = (
274+
cardStrength: string[],
275+
card1: string,
276+
card2: string,
277+
): number => {
200278
if (cardStrength.indexOf(card1) < cardStrength.indexOf(card2)) return 1;
201279
if (cardStrength.indexOf(card1) > cardStrength.indexOf(card2)) return -1;
202280
return 0;

0 commit comments

Comments
 (0)