diff --git a/2023/day07/deno.lock b/2023/day07/deno.lock new file mode 100644 index 0000000..2c1d001 --- /dev/null +++ b/2023/day07/deno.lock @@ -0,0 +1,37 @@ +{ + "version": "3", + "remote": { + "https://deno.land/std@0.208.0/assert/_constants.ts": "8a9da298c26750b28b326b297316cdde860bc237533b07e1337c021379e6b2a9", + "https://deno.land/std@0.208.0/assert/_diff.ts": "58e1461cc61d8eb1eacbf2a010932bf6a05b79344b02ca38095f9b805795dc48", + "https://deno.land/std@0.208.0/assert/_format.ts": "a69126e8a469009adf4cf2a50af889aca364c349797e63174884a52ff75cf4c7", + "https://deno.land/std@0.208.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", + "https://deno.land/std@0.208.0/assert/assert_almost_equals.ts": "e15ca1f34d0d5e0afae63b3f5d975cbd18335a132e42b0c747d282f62ad2cd6c", + "https://deno.land/std@0.208.0/assert/assert_array_includes.ts": "6856d7f2c3544bc6e62fb4646dfefa3d1df5ff14744d1bca19f0cbaf3b0d66c9", + "https://deno.land/std@0.208.0/assert/assert_equals.ts": "d8ec8a22447fbaf2fc9d7c3ed2e66790fdb74beae3e482855d75782218d68227", + "https://deno.land/std@0.208.0/assert/assert_exists.ts": "407cb6b9fb23a835cd8d5ad804e2e2edbbbf3870e322d53f79e1c7a512e2efd7", + "https://deno.land/std@0.208.0/assert/assert_false.ts": "0ccbcaae910f52c857192ff16ea08bda40fdc79de80846c206bfc061e8c851c6", + "https://deno.land/std@0.208.0/assert/assert_greater.ts": "ae2158a2d19313bf675bf7251d31c6dc52973edb12ac64ac8fc7064152af3e63", + "https://deno.land/std@0.208.0/assert/assert_greater_or_equal.ts": "1439da5ebbe20855446cac50097ac78b9742abe8e9a43e7de1ce1426d556e89c", + "https://deno.land/std@0.208.0/assert/assert_instance_of.ts": "3aedb3d8186e120812d2b3a5dea66a6e42bf8c57a8bd927645770bd21eea554c", + "https://deno.land/std@0.208.0/assert/assert_is_error.ts": "c21113094a51a296ffaf036767d616a78a2ae5f9f7bbd464cd0197476498b94b", + "https://deno.land/std@0.208.0/assert/assert_less.ts": "aec695db57db42ec3e2b62e97e1e93db0063f5a6ec133326cc290ff4b71b47e4", + "https://deno.land/std@0.208.0/assert/assert_less_or_equal.ts": "5fa8b6a3ffa20fd0a05032fe7257bf985d207b85685fdbcd23651b70f928c848", + "https://deno.land/std@0.208.0/assert/assert_match.ts": "c4083f80600bc190309903c95e397a7c9257ff8b5ae5c7ef91e834704e672e9b", + "https://deno.land/std@0.208.0/assert/assert_not_equals.ts": "9f1acab95bd1f5fc9a1b17b8027d894509a745d91bac1718fdab51dc76831754", + "https://deno.land/std@0.208.0/assert/assert_not_instance_of.ts": "0c14d3dfd9ab7a5276ed8ed0b18c703d79a3d106102077ec437bfe7ed912bd22", + "https://deno.land/std@0.208.0/assert/assert_not_match.ts": "3796a5b0c57a1ce6c1c57883dd4286be13a26f715ea662318ab43a8491a13ab0", + "https://deno.land/std@0.208.0/assert/assert_not_strict_equals.ts": "4cdef83df17488df555c8aac1f7f5ec2b84ad161b6d0645ccdbcc17654e80c99", + "https://deno.land/std@0.208.0/assert/assert_object_match.ts": "d8fc2867cfd92eeacf9cea621e10336b666de1874a6767b5ec48988838370b54", + "https://deno.land/std@0.208.0/assert/assert_rejects.ts": "45c59724de2701e3b1f67c391d6c71c392363635aad3f68a1b3408f9efca0057", + "https://deno.land/std@0.208.0/assert/assert_strict_equals.ts": "b1f538a7ea5f8348aeca261d4f9ca603127c665e0f2bbfeb91fa272787c87265", + "https://deno.land/std@0.208.0/assert/assert_string_includes.ts": "b821d39ebf5cb0200a348863c86d8c4c4b398e02012ce74ad15666fc4b631b0c", + "https://deno.land/std@0.208.0/assert/assert_throws.ts": "63784e951475cb7bdfd59878cd25a0931e18f6dc32a6077c454b2cd94f4f4bcd", + "https://deno.land/std@0.208.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", + "https://deno.land/std@0.208.0/assert/equal.ts": "9f1a46d5993966d2596c44e5858eec821859b45f783a5ee2f7a695dfc12d8ece", + "https://deno.land/std@0.208.0/assert/fail.ts": "c36353d7ae6e1f7933d45f8ea51e358c8c4b67d7e7502028598fe1fea062e278", + "https://deno.land/std@0.208.0/assert/mod.ts": "37c49a26aae2b254bbe25723434dc28cd7532e444cf0b481a97c045d110ec085", + "https://deno.land/std@0.208.0/assert/unimplemented.ts": "d56fbeecb1f108331a380f72e3e010a1f161baa6956fd0f7cf3e095ae1a4c75a", + "https://deno.land/std@0.208.0/assert/unreachable.ts": "4600dc0baf7d9c15a7f7d234f00c23bca8f3eba8b140286aaca7aa998cf9a536", + "https://deno.land/std@0.208.0/fmt/colors.ts": "34b3f77432925eb72cf0bfb351616949746768620b8e5ead66da532f93d10ba2" + } +} diff --git a/2023/day07/part1.ts b/2023/day07/part1.ts index 5658bc9..c5485d6 100644 --- a/2023/day07/part1.ts +++ b/2023/day07/part1.ts @@ -1,3 +1,102 @@ +export function answer(input: string): number { + const handsAndBids = input.split("\n").map(parseHand); + + handsAndBids.sort(([handA], [handB]) => { + const [typeA, typeB] = [handType(handA), handType(handB)]; + if (typeA !== typeB) { + return HAND_TYPES.indexOf(typeA) > HAND_TYPES.indexOf(typeB) ? 1 : -1; + } else { + for (let i = 0; i < handA.length; i++) { + if (handA[i] !== handB[i]) { + return CARDS.indexOf(handA[i]) > CARDS.indexOf(handB[i]) ? 1 : -1; + } + } + } + throw `hands are the same!: ${handA} ${handB}`; + }); + + return handsAndBids.reduce( + (sum, [_hand, bid], rank) => sum + bid * (rank + 1), + 0, + ); +} + +const CARDS = "23456789TJQKA"; +const HAND_TYPES = [ + "high card", + "1 pair", + "2 pair", + "3 of a kind", + "full house", + "4 of a kind", + "5 of a kind", +]; + +function parseHand(l: string): [string, number] { + const [hand, bidStr] = l.split(" "); + return [hand, parseInt(bidStr)]; +} + +const cardCounts = (hand: string[]) => ({ + "2": hand.filter((c) => c === "2").length, + "3": hand.filter((c) => c === "3").length, + "4": hand.filter((c) => c === "4").length, + "5": hand.filter((c) => c === "5").length, + "6": hand.filter((c) => c === "6").length, + "7": hand.filter((c) => c === "7").length, + "8": hand.filter((c) => c === "8").length, + "9": hand.filter((c) => c === "9").length, + T: hand.filter((c) => c === "T").length, + J: hand.filter((c) => c === "J").length, + Q: hand.filter((c) => c === "Q").length, + K: hand.filter((c) => c === "K").length, + A: hand.filter((c) => c === "A").length, +}); + +const isFiveOfAKind = (cards: string[]): boolean => new Set(cards).size === 1; + +const isFourOfAKind = (cards: string[]): boolean => { + const uniqueCards = new Set(cards); + return ( + uniqueCards.size >= 2 && + [...uniqueCards].some((c) => cards.filter((cc) => cc === c).length === 4) + ); +}; + +const isThreeOfAKind = (cards: string[]): boolean => { + const uniqueCards = new Set(cards); + return ( + uniqueCards.size >= 2 && + [...uniqueCards].some((c) => cards.filter((cc) => cc === c).length === 3) + ); +}; + +const isFullHouse = (cards: string[]): boolean => { + const uniqueCards = new Set(cards); + return ( + uniqueCards.size === 2 && + Object.values(cardCounts(cards)).filter((c) => c > 1).length === 2 + ); +}; + +const pairs = (cards: string[]): number => + Object.values(cardCounts(cards)).filter((c) => c === 2).length; +const isTwoPair = (cards: string[]): boolean => pairs(cards) === 2; +const isOnePair = (cards: string[]): boolean => pairs(cards) === 1; + +function handType(hand: string): string { + const cards = hand + .split("") + .sort((a, b) => CARDS.indexOf(a) - CARDS.indexOf(b)); + if (isFiveOfAKind(cards)) return "5 of a kind"; + if (isFourOfAKind(cards)) return "4 of a kind"; + if (isFullHouse(cards)) return "full house"; + if (isThreeOfAKind(cards)) return "3 of a kind"; + if (isTwoPair(cards)) return "2 pair"; + if (isOnePair(cards)) return "1 pair"; + return "high card"; +} + if (import.meta.main) { const input = ( await Deno.readFile("input").then((bytes) => @@ -6,8 +105,3 @@ if (import.meta.main) { ).trim(); console.log(answer(input)); } - -export function answer(input: string): number { - console.log(input); - return 42; -} diff --git a/2023/day07/test.ts b/2023/day07/test.ts index ef5e047..e2d43ec 100644 --- a/2023/day07/test.ts +++ b/2023/day07/test.ts @@ -3,11 +3,17 @@ import * as p1 from "./part1.ts"; import * as p2 from "./part2.ts"; Deno.test("part1", () => { - const examples = ["abc", "def"].join("\n"); - assertEquals(p1.answer(examples), 42); + const examples = [ + "32T3K 765", + "T55J5 684", + "KK677 28", + "KTJJT 220", + "QQQJA 483", + ].join("\n"); + assertEquals(p1.answer(examples), 6440); }); -Deno.test("part2", () => { - const examples = ["abc", "def"].join("\n"); - assertEquals(p2.answer(examples), 42); -}); +// Deno.test("part2", () => { +// const examples = ["abc", "def"].join("\n"); +// assertEquals(p2.answer(examples), 42); +// });