Skip to content

Commit

Permalink
refactor: simplified 2023 07
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexAegis committed Dec 7, 2023
1 parent aada6dc commit d2c8bc2
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 590 deletions.
318 changes: 23 additions & 295 deletions solutions/typescript/2023/07/src/p1.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import { task } from '@alexaegis/advent-of-code-lib';
import packageJson from '../package.json';
import { HandType, isCard, type Card, type Hand } from './parse.js';

export interface HandWithBid {
cards: Hand;
handType: HandKind;
bid: number;
}
import {
HandType,
getFiveOfAKind,
getFourOfAKind,
getFullHouse,
getHighCards,
getOnePair,
getThreeOfAKind,
getTwoPairs,
inOrderComparator,
parse,
type Card,
type Hand,
} from './parse.js';

const cardPowerMap: Record<Card, number> = {
'2': 2,
Expand All @@ -18,227 +25,14 @@ const cardPowerMap: Record<Card, number> = {
'8': 8,
'9': 9,
T: 10,
J: 20,
Q: 30,
K: 40,
A: 50,
};

export const handTypePowerMap: Record<HandType, number> = {
[HandType.FIVE_OF_A_KIND]: 60,
[HandType.FOUR_OF_A_KIND]: 50,
[HandType.FULL_HOUSE]: 40,
[HandType.THREE_OF_A_KIND]: 30,
[HandType.TWO_PAIRS]: 20,
[HandType.ONE_PAIR]: 10,
[HandType.HIGH_CARD]: 0,
};

export interface FiveOfAKind {
type: HandType.FIVE_OF_A_KIND;
fiveOfAKind: Card;
fiveOfAKindPower: number;
}

export const isFiveOfAKind = (hand: HandKind): hand is FiveOfAKind => {
return hand.type === HandType.FIVE_OF_A_KIND;
};

export interface FourOfAKind {
type: HandType.FOUR_OF_A_KIND;
fourOfAKind: Card;
fourOfAKindPower: number;
highCard: Card;
highCardPower: number;
}

export const isFourOfAKind = (hand: HandKind): hand is FourOfAKind => {
return hand.type === HandType.FOUR_OF_A_KIND;
};
export interface FullHouse {
type: HandType.FULL_HOUSE;
triple: Card;
triplePower: number;
pair: Card;
pairPower: number;
}

export const isFullHouse = (hand: HandKind): hand is FullHouse => {
return hand.type === HandType.FULL_HOUSE;
};

export interface ThreeOfAKind {
type: HandType.THREE_OF_A_KIND;
triple: Card;
triplePower: number;
highCards: [Card, Card];
highCardsPower: number;
}

export const isThreeOfAKind = (hand: HandKind): hand is ThreeOfAKind => {
return hand.type === HandType.THREE_OF_A_KIND;
J: 11,
Q: 12,
K: 13,
A: 14,
};

export interface TwoPairs {
type: HandType.TWO_PAIRS;
pairs: [Card, Card];
pairsPower: number;
highCard: Card;
highCardPower: number;
}

export const isTwoPairs = (hand: HandKind): hand is TwoPairs => {
return hand.type === HandType.TWO_PAIRS;
};

export interface OnePair {
type: HandType.ONE_PAIR;
pair: Card;
pairPower: number;
highCards: [Card, Card, Card];
highCardPower: number;
}

export const isOnePair = (hand: HandKind): hand is OnePair => {
return hand.type === HandType.ONE_PAIR;
};

export interface HighCards {
type: HandType.HIGH_CARD;
highCards: [Card, Card, Card, Card, Card];
highCardPower: number;
}

export const isHighCards = (hand: HandKind): hand is HighCards => {
return hand.type === HandType.HIGH_CARD;
};

export type HandKind =
| FiveOfAKind
| FourOfAKind
| FullHouse
| ThreeOfAKind
| TwoPairs
| OnePair
| HighCards;

export const getFiveOfAKind = (hand: Hand): FiveOfAKind | undefined => {
const first = hand[0];
return hand.every((card) => card === first)
? {
type: HandType.FIVE_OF_A_KIND,
fiveOfAKind: first,
fiveOfAKindPower: cardPowerMap[first],
}
: undefined;
};

export const getFourOfAKind = (hand: Hand): FourOfAKind | undefined => {
const hasFour = hand.find((card) => hand.filter((oc) => card === oc).length === 4);
const highCard = hasFour ? hand.find((card) => card !== hasFour) : undefined;

return hasFour && highCard
? {
type: HandType.FOUR_OF_A_KIND,
fourOfAKind: hasFour,
fourOfAKindPower: cardPowerMap[hasFour],
highCard,
highCardPower: cardPowerMap[highCard],
}
: undefined;
};

export const getFullHouse = (hand: Hand): FullHouse | undefined => {
const hasThree = hand.find((card) => hand.filter((oc) => card === oc).length === 3);
const hasTwo = hand.find(
(card) => card !== hasThree && hand.filter((oc) => card === oc).length === 2,
);

return hasThree && hasTwo
? {
type: HandType.FULL_HOUSE,
triple: hasThree,
triplePower: cardPowerMap[hasThree],
pair: hasTwo,
pairPower: cardPowerMap[hasTwo],
}
: undefined;
};

export const getThreeOfAKind = (hand: Hand): ThreeOfAKind | undefined => {
const hasThree = hand.find((card) => hand.filter((oc) => card === oc).length === 3);
const remaining = hand.filter((card) => card !== hasThree);

return hasThree && remaining.length === 2 && remaining[0] !== remaining[1]
? {
type: HandType.THREE_OF_A_KIND,
triple: hasThree,
triplePower: cardPowerMap[hasThree],
highCards: remaining as [Card, Card],
highCardsPower: remaining.map((r) => cardPowerMap[r]).sum(),
}
: undefined;
};

export const getTwoPairs = (hand: Hand): TwoPairs | undefined => {
const hasPair = hand.find((card) => hand.filter((oc) => card === oc).length === 2);
const hasOtherPair = hand.find(
(card) => card !== hasPair && hand.filter((oc) => card === oc).length === 2,
);
const highCard = hand.find((card) => card !== hasPair && card !== hasOtherPair);

return hasPair && hasOtherPair && highCard
? {
type: HandType.TWO_PAIRS,
pairs: [hasPair, hasOtherPair],
pairsPower: cardPowerMap[hasPair] + cardPowerMap[hasOtherPair],
highCard,
highCardPower: cardPowerMap[highCard],
}
: undefined;
};

export const getOnePair = (hand: Hand): OnePair | undefined => {
const hasPair = hand.find((card) => hand.filter((oc) => card === oc).length === 2);
const remaining = hand.filter((card) => card !== hasPair);

return hasPair &&
remaining.length === 3 &&
// TODO make an isUnique fn
remaining[0] !== remaining[1] &&
remaining[0] !== remaining[2] &&
remaining[1] !== remaining[2]
? {
type: HandType.ONE_PAIR,
pair: hasPair,
pairPower: cardPowerMap[hasPair],
highCards: remaining as [Card, Card, Card],
highCardPower: remaining.map((r) => cardPowerMap[r]).sum(),
}
: undefined;
};

export const getHighCards = (hand: Hand): HighCards | undefined => {
return hand[0] !== hand[1] &&
hand[0] !== hand[2] &&
hand[0] !== hand[3] &&
hand[0] !== hand[4] &&
hand[1] !== hand[2] &&
hand[1] !== hand[3] &&
hand[1] !== hand[4] &&
hand[2] !== hand[3] &&
hand[2] !== hand[4] &&
hand[3] !== hand[4]
? {
type: HandType.HIGH_CARD,
highCards: hand,
highCardPower: hand.map((card) => cardPowerMap[card]).sum(),
}
: undefined;
};

export const getHandType = (hand: Hand): HandKind => {
const handKind =
export const getHandType = (hand: Hand): HandType => {
const handType =
getFiveOfAKind(hand) ??
getFourOfAKind(hand) ??
getFullHouse(hand) ??
Expand All @@ -247,83 +41,17 @@ export const getHandType = (hand: Hand): HandKind => {
getOnePair(hand) ??
getHighCards(hand);

if (!handKind) {
if (!handType) {
throw new Error('cant interpret hand as any kind of hand');
}

return handKind;
};

export const inOrderComparator = (a: HandWithBid, b: HandWithBid): number => {
if (a.handType.type === b.handType.type) {
for (let i = 0; i < a.cards.length; i++) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const ac = cardPowerMap[a.cards[i]!];
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const bc = cardPowerMap[b.cards[i]!];
if (ac > bc) {
return 1;
} else if (bc > ac) {
return -1;
}
}

return 0;
} else {
return handTypePowerMap[a.handType.type] - handTypePowerMap[b.handType.type];
}
};

export const handComparator = (a: HandKind, b: HandKind): number => {
if (isFiveOfAKind(a) && isFiveOfAKind(b)) {
return a.fiveOfAKindPower - b.fiveOfAKindPower;
} else if (isFourOfAKind(a) && isFourOfAKind(b)) {
return a.fourOfAKindPower === b.fourOfAKindPower
? a.highCardPower - b.highCardPower
: a.fourOfAKindPower - b.fourOfAKindPower;
} else if (isFullHouse(a) && isFullHouse(b)) {
return a.triplePower === b.triplePower
? a.pairPower - b.pairPower
: a.triplePower - b.triplePower;
} else if (isThreeOfAKind(a) && isThreeOfAKind(b)) {
return a.triplePower === b.triplePower
? a.highCardsPower - b.highCardsPower
: a.triplePower - b.triplePower;
} else if (isTwoPairs(a) && isTwoPairs(b)) {
return a.pairsPower === b.pairsPower
? a.highCardPower - b.highCardPower
: a.pairsPower - b.pairsPower;
} else if (isOnePair(a) && isOnePair(b)) {
return a.pairPower === b.pairPower
? a.highCardPower - b.highCardPower
: a.pairPower - b.pairPower;
} else if (isHighCards(a) && isHighCards(b)) {
return a.highCardPower - b.highCardPower;
} else {
return handTypePowerMap[a.type] - handTypePowerMap[b.type];
}
};

export const parse = (line: string): HandWithBid => {
const [cards, value] = line.splitIntoStringPair(' ');
const [c1, c2, c3, c4, c5] = [...cards];
const bid = Number.parseInt(value, 10);
if (isCard(c1) && isCard(c2) && isCard(c3) && isCard(c4) && isCard(c5)) {
const cards: Hand = [c1, c2, c3, c4, c5];
return {
handType: getHandType(cards),
cards,
bid,
};
} else {
throw new Error('corrupted line');
}
return handType;
};

export const p1 = (input: string): number =>
input
.lines(false)
.map(parse)
.map(parse(cardPowerMap, getHandType))
.sort(inOrderComparator)
.map((hand, index) => hand.bid * (index + 1))
.sum();
Expand Down
Loading

0 comments on commit d2c8bc2

Please sign in to comment.