Kaynağa Gözat

Add day 7 part ii

ApisNecros 1 yıl önce
ebeveyn
işleme
0041ddb9f9
1 değiştirilmiş dosya ile 170 ekleme ve 0 silme
  1. 170 0
      7/7_2.ts

+ 170 - 0
7/7_2.ts

@@ -0,0 +1,170 @@
+import { LoadInput } from "../common.ts";
+import { type CamelCardsHand, CamelCardRanking } from "./7_common.ts";
+
+const tests = [
+    "32T3K 765",
+    "T55J5 684",
+    "KK677 28",
+    "KTJJT 220",
+    "QQQJA 483",
+];
+
+const tests_reddit = [
+    "2345A 1",
+    "Q2KJJ 13",
+    "Q2Q2Q 19",
+    "T3T3J 17",
+    "T3Q33 11",
+    "2345J 3",
+    "J345A 2",
+    "32T3K 5",
+    "T55J5 29",
+    "KK677 7",
+    "KTJJT 34",
+    "QQQJA 31",
+    "JJJJJ 37",
+    "JAAAA 43",
+    "AAAAJ 59",
+    "AAAAA 61",
+    "2AAAA 23",
+    "2JJJJ 53",
+    "JJJJ2 41",
+];
+
+const input = await LoadInput(7);
+
+// Parse the input
+const parsedHands = ParseInput(input);
+// Sort the cards
+const sortedHands = parsedHands.sort(SortHands);
+
+// Find the input
+let totalWinnings = 0;
+sortedHands.forEach((hand, idx) => {
+    totalWinnings += hand.Bid * (idx + 1);
+});
+
+console.log(`The total winnings are $${totalWinnings}`);
+
+/**
+ * Parse the input
+ *
+ * @param {string[]} handList An array of strings represnting hands of Camel Cards and their bids
+ * @returns {CamelCardsHand[]} An array of parsed Camel Card hands
+ */
+function ParseInput(handList: string[]): CamelCardsHand[] {
+    const output: CamelCardsHand[] = [];
+
+    handList.forEach((hand) => {
+        const [handStr, bidStr] = hand.split(" ");
+        output.push({
+            Hand: handStr,
+            Bid: Number(bidStr),
+            Rank: FindCamelCardRank(handStr),
+        });
+    })
+
+    return output;
+}
+
+/**
+ * Assign a base rank to a hand of Camel Cards
+ * 
+ * Assigns a Camel Card Ranking to a hand of cards based on the
+ * strength of the hand on its own.
+ * 
+ * @param {string} hand The hand a player drew
+ * @returns {CamelCardRanking} The ranking of the hand
+ */
+function FindCamelCardRank(hand: string): CamelCardRanking {
+    const cardFacesSorted = ReplaceJokers(hand).split("").sort().join("");
+
+    const fiveOfKind = new RegExp("(.)\\1{4}", "g");
+    const fourOfKind = new RegExp("(.)\\1{3}", "g");
+    const threeOfKind = new RegExp("(.)\\1{2}", "g");
+    const twoOfKind = new RegExp("(.)\\1{1}", "g");
+    // Can't get these two to work in one regex, so I'll split them for now
+    const fullHouse_A = new RegExp("(.)\\1(.)\\2{2}", "g");
+    const fullHouse_B = new RegExp("(.)\\1{2}(.)\\2", "g");
+
+    if (cardFacesSorted.replace(twoOfKind, "").length == 5) {
+        return CamelCardRanking.HIGH_CARD;
+    }
+    else if(cardFacesSorted.replace(fiveOfKind, "").length == 0) {
+        return CamelCardRanking.FIVE_OF_A_KIND;
+    }
+    else if(cardFacesSorted.replace(fourOfKind, "").length == 1) {
+        return CamelCardRanking.FOUR_OF_A_KIND;
+    }
+    else if(cardFacesSorted.replace(fullHouse_A, "").length == 0
+        || cardFacesSorted.replace(fullHouse_B, "").length == 0) {
+        return CamelCardRanking.FULL_HOUSE;
+    }
+    else if(cardFacesSorted.replace(threeOfKind, "").length == 2) {
+        return CamelCardRanking.THREE_OF_A_KIND;
+    }
+    else if(cardFacesSorted.replace(twoOfKind, "").length == 1) {
+        return CamelCardRanking.TWO_PAIR;
+    }
+    else if(cardFacesSorted.replace(twoOfKind, "").length == 3) {
+        return CamelCardRanking.ONE_PAIR;
+    }
+    else {
+        throw new Error(`Unsure how we reached this condition!\nSorted hand was: ${cardFacesSorted}`);
+    }
+}
+
+/**
+ * Compare two hands of Camel Cards for sorting
+ */
+function SortHands(a: CamelCardsHand, b: CamelCardsHand): number {
+    if (a.Rank < b.Rank) { return -1; }
+    if (a.Rank > b.Rank) { return 1;  }
+
+    // Replace the letters with something easier to compare
+    const aHand = a.Hand.replaceAll("A", "Z").replaceAll("K", "Y").replaceAll("Q", "X").replaceAll("J", "0").replaceAll("T", "V");
+    const bHand = b.Hand.replaceAll("A", "Z").replaceAll("K", "Y").replaceAll("Q", "X").replaceAll("J", "0").replaceAll("T", "V");
+
+    for (let i = 0; i < 5; i++) {
+        if (aHand[i] < bHand[i]) {
+            return -1;
+        }
+        if (aHand[i] > bHand[i]) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+function ReplaceJokers(hand: string): string {
+    // Make sure the hand has a joker card, but is not only joker cards, before attempting the replacement
+    if (!/J/.test(hand) && hand != "JJJJJ") { return hand; }
+
+    /** Track how many jokers we need to add back to the hand */
+    const jokerCount = hand.replace(/[^J]/g, "").length;
+    /** An array containing the cards in the hand less any jokers */
+    const handFaces = hand.replaceAll("J", "").split("");
+
+    /** An object for counting the amounts of each face in the hand */
+    const faceMatches: { [face: string]: number; } = {"": -1};
+
+    /* Count the amount of each face in the string */
+    handFaces.forEach((face) => {
+        if (faceMatches[face] == undefined) {
+            faceMatches[face] = 0;
+        }
+
+        faceMatches[face]++;
+    });
+
+    /* Find the most occurring face in the hand */
+    let highestCard:string = "";
+    for (const face in faceMatches) {
+        if (faceMatches[face] > faceMatches[highestCard]) {
+            highestCard = face;
+        }
+    }
+
+    return handFaces.join("") + highestCard.repeat(jokerCount);
+}