mirror of
https://github.com/peter-tanner/advent-of-code-2023.git
synced 2024-11-30 05:50:15 +08:00
Day 7 solutions ☀☀☀
This commit is contained in:
parent
900d67e6ff
commit
4f57e185fe
27
day_7/compare.ts
Normal file
27
day_7/compare.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
export enum RANK {
|
||||
FIVE_OF_A_KIND,
|
||||
FOUR_OF_A_KIND,
|
||||
FULL_HOUSE,
|
||||
THREE_OF_A_KIND,
|
||||
TWO_PAIR,
|
||||
ONE_PAIR,
|
||||
HIGH_CARD,
|
||||
}
|
||||
|
||||
export const cmp_by_card = (
|
||||
hand1: string,
|
||||
hand2: string,
|
||||
strength_order: Map<string, number>
|
||||
) => {
|
||||
for (var i = 0; i < hand1.length; i++) {
|
||||
const s1 = strength_order.get(hand1[i]);
|
||||
const s2 = strength_order.get(hand2[i]);
|
||||
if (undefined === s1 || undefined === s2) {
|
||||
console.error("ERROR", i, hand1[i], hand2[i]);
|
||||
return 0;
|
||||
}
|
||||
if (s1 > s2) return -1;
|
||||
if (s1 < s2) return 1;
|
||||
}
|
||||
return 0;
|
||||
};
|
15
day_7/parser.ts
Normal file
15
day_7/parser.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import * as fs from "fs";
|
||||
|
||||
export interface HandBid {
|
||||
hand: string;
|
||||
bid: number;
|
||||
}
|
||||
|
||||
export const read_file = (): HandBid[] =>
|
||||
fs
|
||||
.readFileSync("input", "ascii")
|
||||
.split("\n")
|
||||
.map((line) => {
|
||||
const [hand, bid] = line.split(" ");
|
||||
return { hand: hand, bid: Number.parseInt(bid) };
|
||||
});
|
65
day_7/part_1.ts
Normal file
65
day_7/part_1.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
import { RANK, cmp_by_card } from "./compare";
|
||||
import { HandBid, read_file } from "./parser";
|
||||
|
||||
const rank_hand = (hand: string) => {
|
||||
const cards = hand.split("");
|
||||
const card_count = cards.reduce((count, char) => {
|
||||
const c = count.get(char);
|
||||
return c ? count.set(char, c + 1) : count.set(char, 1);
|
||||
}, new Map<string, number>());
|
||||
|
||||
const unique_cards = Array.from(card_count.keys());
|
||||
|
||||
if (unique_cards.length === 1) return RANK.FIVE_OF_A_KIND;
|
||||
if (unique_cards.length === 4) return RANK.ONE_PAIR;
|
||||
if (unique_cards.length === 5) return RANK.HIGH_CARD;
|
||||
if (
|
||||
unique_cards.length === 2 &&
|
||||
[1, 4].includes(card_count.get(unique_cards[0]) || 0)
|
||||
)
|
||||
return RANK.FOUR_OF_A_KIND;
|
||||
if (
|
||||
unique_cards.length === 2 &&
|
||||
[2, 3].includes(card_count.get(unique_cards[0]) || 0)
|
||||
)
|
||||
return RANK.FULL_HOUSE;
|
||||
if (
|
||||
unique_cards.length === 3 &&
|
||||
unique_cards.reduce((c, card) => card_count.get(card) === 3 || c, false)
|
||||
)
|
||||
return RANK.THREE_OF_A_KIND;
|
||||
|
||||
return RANK.TWO_PAIR;
|
||||
};
|
||||
|
||||
const STRENGTH = new Map<string, number>(
|
||||
Object.entries({
|
||||
A: 0,
|
||||
K: 1,
|
||||
Q: 2,
|
||||
J: 3,
|
||||
T: 4,
|
||||
"9": 5,
|
||||
"8": 6,
|
||||
"7": 7,
|
||||
"6": 8,
|
||||
"5": 9,
|
||||
"4": 10,
|
||||
"3": 11,
|
||||
"2": 12,
|
||||
})
|
||||
);
|
||||
|
||||
const cmp_hand = (hand_bid1: HandBid, hand_bid2: HandBid) => {
|
||||
if (rank_hand(hand_bid1.hand) > rank_hand(hand_bid2.hand)) return -1;
|
||||
if (rank_hand(hand_bid1.hand) < rank_hand(hand_bid2.hand)) return 1;
|
||||
return cmp_by_card(hand_bid1.hand, hand_bid2.hand, STRENGTH);
|
||||
};
|
||||
|
||||
const hand_bids = read_file();
|
||||
|
||||
console.log(
|
||||
hand_bids
|
||||
.sort(cmp_hand)
|
||||
.reduce((sum, hand_bid, i) => sum + hand_bid.bid * (1 + i), 0)
|
||||
);
|
82
day_7/part_2.ts
Normal file
82
day_7/part_2.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import { RANK, cmp_by_card } from "./compare";
|
||||
import { HandBid, read_file } from "./parser";
|
||||
|
||||
const rank_hand = (hand: string) => {
|
||||
const cards = hand.split("");
|
||||
const card_count = cards.reduce((count, char) => {
|
||||
const c = count.get(char);
|
||||
return c ? count.set(char, c + 1) : count.set(char, 1);
|
||||
}, new Map<string, number>(Object.entries({ J: 0 })));
|
||||
|
||||
// It is always the most optimal choice to greedily substitute J for the card with the most occurrences.
|
||||
var max_card = "?";
|
||||
Array.from(card_count.keys()).forEach((card) => {
|
||||
if (
|
||||
card !== "J" &&
|
||||
(card_count.get(card) || 0) > (card_count.get(max_card) || 0)
|
||||
) {
|
||||
max_card = card;
|
||||
}
|
||||
});
|
||||
|
||||
card_count.set(
|
||||
max_card,
|
||||
(card_count.get(max_card) || 0) + (card_count.get("J") || 0)
|
||||
);
|
||||
card_count.delete("J");
|
||||
|
||||
const unique_cards = Array.from(card_count.keys()).filter(
|
||||
(card) => card !== "J"
|
||||
);
|
||||
|
||||
if (unique_cards.length === 1) return RANK.FIVE_OF_A_KIND;
|
||||
if (unique_cards.length === 4) return RANK.ONE_PAIR;
|
||||
if (unique_cards.length === 5) return RANK.HIGH_CARD;
|
||||
if (
|
||||
unique_cards.length === 2 &&
|
||||
[1, 4].includes(card_count.get(unique_cards[0]) || 0)
|
||||
)
|
||||
return RANK.FOUR_OF_A_KIND;
|
||||
if (
|
||||
unique_cards.length === 2 &&
|
||||
[2, 3].includes(card_count.get(unique_cards[0]) || 0)
|
||||
)
|
||||
return RANK.FULL_HOUSE;
|
||||
if (
|
||||
unique_cards.length === 3 &&
|
||||
unique_cards.reduce((c, card) => card_count.get(card) === 3 || c, false)
|
||||
)
|
||||
return RANK.THREE_OF_A_KIND;
|
||||
|
||||
return RANK.TWO_PAIR;
|
||||
};
|
||||
|
||||
const STRENGTH = new Map<string, number>(
|
||||
Object.entries({
|
||||
A: 0,
|
||||
K: 1,
|
||||
Q: 2,
|
||||
T: 3,
|
||||
"9": 4,
|
||||
"8": 5,
|
||||
"7": 6,
|
||||
"6": 7,
|
||||
"5": 8,
|
||||
"4": 9,
|
||||
"3": 10,
|
||||
"2": 11,
|
||||
J: 12,
|
||||
})
|
||||
);
|
||||
|
||||
const cmp_hand = (hand_bid1: HandBid, hand_bid2: HandBid) => {
|
||||
if (rank_hand(hand_bid1.hand) > rank_hand(hand_bid2.hand)) return -1;
|
||||
if (rank_hand(hand_bid1.hand) < rank_hand(hand_bid2.hand)) return 1;
|
||||
return cmp_by_card(hand_bid1.hand, hand_bid2.hand, STRENGTH);
|
||||
};
|
||||
|
||||
console.log(
|
||||
read_file()
|
||||
.sort(cmp_hand)
|
||||
.reduce((sum, hand_bid, i) => sum + hand_bid.bid * (1 + i), 0)
|
||||
);
|
Loading…
Reference in New Issue
Block a user