Skip to content

Commit 5bd293b

Browse files
committed
[AOC2023][Typescript] Added solutions for Day 7.
1 parent 795a5bd commit 5bd293b

File tree

3 files changed

+98
-1
lines changed

3 files changed

+98
-1
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
| [04 - Scratchcards](https://adventofcode.com/2023/day/4) | [Day 04 TypeScript](/typescript/src/2023/day04.ts) |
2626
| [05 - If You Give A Seed A Fertilizer](https://adventofcode.com/2023/day/5) | [Day 05 TypeScript](/typescript/src/2023/day05.ts) |
2727
| [06 - Wait For It](https://adventofcode.com/2023/day/6) | [Day 06 TypeScript](/typescript/src/2023/day06.ts) |
28+
| [07 - Camel Cards](https://adventofcode.com/2023/day/7) | [Day 07 TypeScript](/typescript/src/2023/day07.ts) |
2829

2930
### AoC 2022
3031
| Day | Kotlin | TypeScript |

typescript/src/2023/day07.ts

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import {Aggregates, AocDay, AocDayDecorator, SolutionParts} from "../aoc";
2+
3+
@AocDayDecorator('2023', '7')
4+
export class Day07 extends AocDay {
5+
6+
solveImpl(): SolutionParts {
7+
const CardSymbols = ["A", "K", "Q", "J", "T", "9", "8", "7", "6", "5", "4", "3", "2"] as const;
8+
// eslint-disable-next-line @typescript-eslint/no-redeclare
9+
type CardSymbols = typeof CardSymbols[number];
10+
11+
type CardGameRound = {hand: CardSymbols[], bid: number};
12+
13+
const cardGameRounds: CardGameRound[] = this.input.split("\n").map(r => r.trim()).map(r => {
14+
const [handStr, bidStr] = r.split(" ");
15+
return {hand: handStr.trim().split("") as CardSymbols[], bid: parseInt(bidStr.trim(), 10)};
16+
});
17+
18+
const getCardAmount = (round: CardGameRound) => round.hand.reduce<Record<string, number>>((acc, cur) => {
19+
acc[cur] = (acc[cur] ?? 0) + 1;
20+
return acc;
21+
}, {});
22+
23+
const getHandTypeRank = (round: CardGameRound): number => {
24+
25+
const hasDistinctValues = (amount: number) => Object.keys(getCardAmount(round)).length === amount;
26+
const hasNofAKind = (amount: number) => Object.values(getCardAmount(round)).find((v) => v === amount) !== undefined;
27+
28+
const typeRules: Record<string, () => boolean> = {
29+
isFiveOfAKind: () => hasDistinctValues(1),
30+
isFourOfAKind: () => hasDistinctValues(2) && hasNofAKind(4),
31+
isFullHouse: () => hasDistinctValues(2) && hasNofAKind(3),
32+
isThreeOfAKind: () => hasDistinctValues(3) && hasNofAKind(3),
33+
isTwoPair: () => hasDistinctValues(3) && hasNofAKind(2),
34+
isOnePair: () => hasDistinctValues(4) && hasNofAKind(2),
35+
isHighCard: () => hasDistinctValues(5)
36+
};
37+
38+
return Object.keys(typeRules).length - Object.values(typeRules).findIndex((typeRuleFn) => typeRuleFn()) - 1;
39+
};
40+
41+
const getBesPossibleRoundWithJokers = (round: CardGameRound): CardGameRound => {
42+
let best = {
43+
round,
44+
roundType: getHandTypeRank(round)
45+
};
46+
for (const cardSymbol of CardSymbols.filter(s => s !== "J")) {
47+
const curRound: CardGameRound = {
48+
bid: round.bid,
49+
hand: round.hand.map(c => c === "J" ? cardSymbol : c)
50+
};
51+
const curRoundType = getHandTypeRank(curRound);
52+
if(best.roundType < curRoundType){
53+
best = {
54+
round: curRound,
55+
roundType: curRoundType
56+
};
57+
}
58+
}
59+
60+
return best.round;
61+
};
62+
63+
function createHandSorter(singleCardRankHighestToLowest: CardSymbols[], withJokerUsage: boolean): (a: CardGameRound, b: CardGameRound) => number {
64+
const singleCardRank = Object.fromEntries(singleCardRankHighestToLowest.map((v, idx, arr) => [v, arr.length - idx - 1]));
65+
const byHighestCard = (a: CardGameRound, b: CardGameRound): number => a.hand.map((v, idx) => singleCardRank[b.hand[idx]] - singleCardRank[a.hand[idx]]).find(v => v!==0) ?? 0;
66+
const byHandyTypeRank = (a: CardGameRound, b: CardGameRound): number => {
67+
if(withJokerUsage){
68+
return getHandTypeRank(getBesPossibleRoundWithJokers(b)) - getHandTypeRank(getBesPossibleRoundWithJokers(a));
69+
}
70+
return getHandTypeRank(b) - getHandTypeRank(a);
71+
};
72+
73+
return (a: CardGameRound, b: CardGameRound) => {
74+
const typeDiff = byHandyTypeRank(a, b);
75+
return typeDiff === 0 ? byHighestCard(a, b) : typeDiff;
76+
};
77+
}
78+
79+
const calculateTotalWinnings = (rounds: CardGameRound[],singleCardRankHighestToLowest: CardSymbols[], withJokerUsage: boolean) => {
80+
const byHandOrder = createHandSorter(singleCardRankHighestToLowest, withJokerUsage);
81+
return rounds
82+
.sort(byHandOrder)
83+
.map((game, idx, acc) => game.bid * (acc.length - idx))
84+
.reduce(Aggregates.sum);
85+
};
86+
87+
const part1 = () => calculateTotalWinnings(cardGameRounds, ["A", "K", "Q", "J", "T", "9", "8", "7", "6", "5", "4", "3", "2"], false);
88+
const part2 = () => calculateTotalWinnings(cardGameRounds, ["A", "K", "Q", "T", "9", "8", "7", "6", "5", "4", "3", "2", "J"], true);
89+
90+
return {
91+
part1: part1(),
92+
part2: part2()
93+
};
94+
}
95+
}

typescript/src/2023/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ export * from './day02';
33
export * from './day03';
44
export * from './day04';
55
export * from './day05';
6-
export * from './day06';
6+
export * from './day06';
7+
export * from './day07';

0 commit comments

Comments
 (0)