From f7aacb86f5f0922b4667feac27cf9a1f38fb22ed Mon Sep 17 00:00:00 2001 From: Stanislas Lange Date: Thu, 7 Dec 2023 23:29:44 +0100 Subject: [PATCH] day 7 part 2 --- 07/07.go | 220 ++++++++++++++++++++++++++++++++++++++++++--- 07/07_test.go | 243 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 435 insertions(+), 28 deletions(-) diff --git a/07/07.go b/07/07.go index fc0dfe1..ba21bcb 100644 --- a/07/07.go +++ b/07/07.go @@ -10,24 +10,33 @@ import ( ) func main() { - input := utils.ParseInput("/Users/stanislaslange/advent-of-code-2023/07/input.txt") + input := utils.ParseInput("input.txt") parsedInput := ConvertRawInputToInput(input) part1Score := parsedInput.ComputeTotalPoints() fmt.Printf("Part 1: %d\n", part1Score) + + parsedInputV2 := ConvertRawInputToInputV2(input) + for i := range parsedInputV2.Hands { + parsedInputV2.Hands[i].ComputeAndAssignHandType() + parsedInputV2.Hands[i].JokerMode() + } + parsedInputV2.SortHands() + part2Score := parsedInputV2.ComputeTotalPoints() + fmt.Printf("Part 2: %d\n", part2Score) } -type Hand struct { +type HandV1 struct { Cards string Bid int } -type Input struct { - Hands []Hand +type InputV1 struct { + Hands []HandV1 } -func ConvertRawInputToInput(rawInput []string) Input { - input := Input{} +func ConvertRawInputToInput(rawInput []string) InputV1 { + input := InputV1{} for _, line := range rawInput { splitLine := strings.Split(line, " ") @@ -37,7 +46,7 @@ func ConvertRawInputToInput(rawInput []string) Input { panic(err) } - hand := Hand{ + hand := HandV1{ Cards: cards, Bid: bid, } @@ -48,7 +57,7 @@ func ConvertRawInputToInput(rawInput []string) Input { return input } -func (input Input) SortHands() { +func (input InputV1) SortHands() { sort.Slice(input.Hands, func(i, j int) bool { occurrencesI := input.Hands[i].Occurrences() occurrencesJ := input.Hands[j].Occurrences() @@ -106,7 +115,7 @@ func (input Input) SortHands() { }) } -func (hand Hand) Occurrences() []int { +func (hand HandV1) Occurrences() []int { occurrences := make([]int, 5) for _, card := range hand.Cards { @@ -129,13 +138,200 @@ func (hand Hand) Occurrences() []int { return occurrences } -func (input Input) ComputeTotalPoints() int { +func (input InputV1) ComputeTotalPoints() int { input.SortHands() - for _, hand := range input.Hands { - fmt.Printf("%s %d\n", hand.Cards, hand.Bid) + totalPoints := 0 + for i, hand := range input.Hands { + totalPoints += hand.Bid * (i + 1) + } + + return totalPoints +} + +/* +============================== + Part 2 +============================== +*/ + +type HandType int + +const ( + HighCard HandType = iota + OnePair + TwoPair + ThreeOfAKind + FullHouse + FourOfAKind + FiveOfAKind +) + +type HandV2 struct { + Cards string + Bid int + HandType HandType +} + +type InputV2 struct { + Hands []HandV2 +} + +func ConvertRawInputToInputV2(rawInput []string) InputV2 { + input := InputV2{} + + for _, line := range rawInput { + splitLine := strings.Split(line, " ") + cards := splitLine[0] + bid, err := strconv.Atoi(splitLine[1]) + if err != nil { + panic(err) + } + + hand := HandV2{ + Cards: cards, + Bid: bid, + } + + input.Hands = append(input.Hands, hand) + } + + return input +} + +func (hand HandV2) ComputeOcurrences() []int { + occurrences := make([]int, 5) + + for _, card := range hand.Cards { + count := strings.Count(hand.Cards, string(card)) + + if count == 0 { + continue + } + indexCount := count - 1 + + if ok := occurrences[indexCount]; ok == 0 { + occurrences[indexCount] = 1 + } else { + occurrences[indexCount]++ + } + + hand.Cards = strings.ReplaceAll(hand.Cards, string(card), "") + } + + return occurrences +} + +func (hand *HandV2) ComputeAndAssignHandType() { + occurrences := hand.ComputeOcurrences() + + if occurrences[5-1] == 1 { + hand.HandType = FiveOfAKind + return } + if occurrences[4-1] == 1 { + hand.HandType = FourOfAKind + return + } + + if occurrences[3-1] == 1 && occurrences[2-1] == 1 { + hand.HandType = FullHouse + return + } + + if occurrences[3-1] == 1 { + hand.HandType = ThreeOfAKind + return + } + + if occurrences[2-1] == 2 { + hand.HandType = TwoPair + return + } + + if occurrences[2-1] == 1 { + hand.HandType = OnePair + return + } + + hand.HandType = HighCard +} + +func (hand *HandV2) JokerMode() { + JCount := strings.Count(hand.Cards, "J") + + if JCount == 0 { + return + } + + for i := 0; i < JCount; i++ { + switch hand.HandType { + case FiveOfAKind: + return + case FourOfAKind: + hand.HandType = FiveOfAKind + if strings.Count(hand.Cards, "J") == 4 { + return + } + case FullHouse: + hand.HandType = FourOfAKind + case ThreeOfAKind: + hand.HandType = FourOfAKind + if strings.Count(hand.Cards, "J") == 3 { + return + } + case TwoPair: + hand.HandType = FullHouse + case OnePair: + hand.HandType = ThreeOfAKind + if strings.Count(hand.Cards, "J") == 2 { + return + } + case HighCard: + hand.HandType = OnePair + } + } +} + +func (input InputV2) SortHands() { + sort.Slice(input.Hands, func(i, j int) bool { + if input.Hands[i].HandType != input.Hands[j].HandType { + return input.Hands[i].HandType < input.Hands[j].HandType + } + + strengths := map[string]int{ + "A": 13, + "K": 12, + "Q": 11, + "T": 10, + "9": 9, + "8": 8, + "7": 7, + "6": 6, + "5": 5, + "4": 4, + "3": 3, + "2": 2, + "J": 1, + } + + for cardIndex := 0; cardIndex < 5; cardIndex++ { + cardJ := string(input.Hands[j].Cards[cardIndex]) + cardI := string(input.Hands[i].Cards[cardIndex]) + + if strengths[cardI] != strengths[cardJ] { + return strengths[cardI] < strengths[cardJ] + } + } + + return true + }) +} + +func (input InputV2) ComputeTotalPoints() int { + input.SortHands() + totalPoints := 0 for i, hand := range input.Hands { totalPoints += hand.Bid * (i + 1) diff --git a/07/07_test.go b/07/07_test.go index c8ca2a7..749fd14 100644 --- a/07/07_test.go +++ b/07/07_test.go @@ -15,8 +15,8 @@ func TestConvertRawInputToInput(t *testing.T) { "QQQJA 483", } - expected := Input{ - Hands: []Hand{ + expected := InputV1{ + Hands: []HandV1{ {Cards: "32T3K", Bid: 765}, {Cards: "T55J5", Bid: 684}, {Cards: "KK677", Bid: 28}, @@ -29,8 +29,8 @@ func TestConvertRawInputToInput(t *testing.T) { } func TestOccurences(t *testing.T) { - input := Input{ - Hands: []Hand{ + input := InputV1{ + Hands: []HandV1{ {Cards: "T55J5", Bid: 684}, {Cards: "32T3K", Bid: 765}, {Cards: "QQQJA", Bid: 483}, @@ -58,14 +58,14 @@ func TestOccurences(t *testing.T) { func TestSortHands(t *testing.T) { type test struct { - input Input - expected Input + input InputV1 + expected InputV1 } tests := []test{ { - input: Input{ - Hands: []Hand{ + input: InputV1{ + Hands: []HandV1{ {Cards: "T55J5", Bid: 684}, {Cards: "32T3K", Bid: 765}, {Cards: "QQQJA", Bid: 483}, @@ -73,8 +73,8 @@ func TestSortHands(t *testing.T) { {Cards: "KTJJT", Bid: 220}, }, }, - expected: Input{ - Hands: []Hand{ + expected: InputV1{ + Hands: []HandV1{ {Cards: "32T3K", Bid: 765}, {Cards: "KTJJT", Bid: 220}, {Cards: "KK677", Bid: 28}, @@ -84,14 +84,14 @@ func TestSortHands(t *testing.T) { }, }, { - input: Input{ - Hands: []Hand{ + input: InputV1{ + Hands: []HandV1{ {Cards: "T3T3J", Bid: 17}, {Cards: "Q2KJJ", Bid: 13}, }, }, - expected: Input{ - Hands: []Hand{ + expected: InputV1{ + Hands: []HandV1{ {Cards: "Q2KJJ", Bid: 13}, {Cards: "T3T3J", Bid: 17}, }, @@ -106,8 +106,8 @@ func TestSortHands(t *testing.T) { } func TestComputeTotalPoints(t *testing.T) { - input := Input{ - Hands: []Hand{ + input := InputV1{ + Hands: []HandV1{ {Cards: "32T3K", Bid: 765}, {Cards: "KTJJT", Bid: 220}, {Cards: "KK677", Bid: 28}, @@ -120,3 +120,214 @@ func TestComputeTotalPoints(t *testing.T) { assert.Equal(t, expected, input.ComputeTotalPoints()) } + +/* +============================== + Part 2 +============================== +*/ + +func TestConvertRawInputToInputV2(t *testing.T) { + input := []string{ + "32T3K 765", + "T55J5 684", + "KK677 28", + "KTJJT 220", + "QQQJA 483", + } + + expected := InputV2{ + Hands: []HandV2{ + {Cards: "32T3K", Bid: 765}, + {Cards: "T55J5", Bid: 684}, + {Cards: "KK677", Bid: 28}, + {Cards: "KTJJT", Bid: 220}, + {Cards: "QQQJA", Bid: 483}, + }, + } + + assert.Equal(t, expected, ConvertRawInputToInputV2(input)) +} + +func TestOccurencesV2(t *testing.T) { + input := InputV2{ + Hands: []HandV2{ + {Cards: "T55J5", Bid: 684}, + {Cards: "32T3K", Bid: 765}, + {Cards: "QQQJA", Bid: 483}, + {Cards: "KK677", Bid: 28}, + {Cards: "KTJJT", Bid: 220}, + {Cards: "T3T3J", Bid: 17}, + {Cards: "Q2KJJ", Bid: 13}, + }, + } + + expected := [][]int{ + {2, 0, 1, 0, 0}, + {3, 1, 0, 0, 0}, + {2, 0, 1, 0, 0}, + {1, 2, 0, 0, 0}, + {1, 2, 0, 0, 0}, + {1, 2, 0, 0, 0}, + {3, 1, 0, 0, 0}, + } + + for i, hand := range input.Hands { + assert.Equal(t, expected[i], hand.ComputeOcurrences()) + } +} + +func TestComputeAndAssignHandType(t *testing.T) { + type test struct { + input []HandV2 + expected []HandV2 + } + + tests := []test{ + { + input: []HandV2{ + {Cards: "T55J5", Bid: 684}, + {Cards: "32T3K", Bid: 765}, + {Cards: "QQQJA", Bid: 483}, + {Cards: "KK677", Bid: 28}, + {Cards: "KTJJT", Bid: 220}, + }, + expected: []HandV2{ + {Cards: "T55J5", Bid: 684, HandType: ThreeOfAKind}, + {Cards: "32T3K", Bid: 765, HandType: OnePair}, + {Cards: "QQQJA", Bid: 483, HandType: ThreeOfAKind}, + {Cards: "KK677", Bid: 28, HandType: TwoPair}, + {Cards: "KTJJT", Bid: 220, HandType: TwoPair}, + }, + }, + { + input: []HandV2{ + {Cards: "T3T3J", Bid: 17}, + {Cards: "Q2KJJ", Bid: 13}, + }, + expected: []HandV2{ + {Cards: "T3T3J", Bid: 17, HandType: TwoPair}, + {Cards: "Q2KJJ", Bid: 13, HandType: OnePair}, + }, + }, + } + + for _, tc := range tests { + for i := range tc.input { + tc.input[i].ComputeAndAssignHandType() + assert.Equal(t, tc.expected[i], tc.input[i]) + } + } +} + +func TestJokerMode(t *testing.T) { + type test struct { + input []HandV2 + expected []HandV2 + } + + tests := []test{ + { + input: []HandV2{ + {Cards: "T55J5", Bid: 684, HandType: ThreeOfAKind}, + {Cards: "32T3K", Bid: 765, HandType: OnePair}, + {Cards: "QQQJA", Bid: 483, HandType: ThreeOfAKind}, + {Cards: "KK677", Bid: 28, HandType: TwoPair}, + {Cards: "KTJJT", Bid: 220, HandType: TwoPair}, + }, + expected: []HandV2{ + {Cards: "T55J5", Bid: 684, HandType: FourOfAKind}, + {Cards: "32T3K", Bid: 765, HandType: OnePair}, + {Cards: "QQQJA", Bid: 483, HandType: FourOfAKind}, + {Cards: "KK677", Bid: 28, HandType: TwoPair}, + {Cards: "KTJJT", Bid: 220, HandType: FourOfAKind}, + }, + }, + { + input: []HandV2{ + {Cards: "T3T3J", Bid: 17, HandType: TwoPair}, + {Cards: "Q2KJJ", Bid: 13, HandType: OnePair}, + {Cards: "JJJQA", Bid: 483, HandType: ThreeOfAKind}, + }, + expected: []HandV2{ + {Cards: "T3T3J", Bid: 17, HandType: FullHouse}, + {Cards: "Q2KJJ", Bid: 13, HandType: ThreeOfAKind}, + {Cards: "JJJQA", Bid: 483, HandType: FourOfAKind}, + }, + }, + } + + for _, tc := range tests { + for i := range tc.input { + tc.input[i].JokerMode() + assert.Equal(t, tc.expected[i], tc.input[i]) + } + } +} + +func TestSortHandsV2(t *testing.T) { + type test struct { + input InputV2 + expected InputV2 + } + + tests := []test{ + { + input: InputV2{ + Hands: []HandV2{ + {Cards: "T55J5", Bid: 684, HandType: FourOfAKind}, + {Cards: "32T3K", Bid: 765, HandType: OnePair}, + {Cards: "QQQJA", Bid: 483, HandType: FourOfAKind}, + {Cards: "KK677", Bid: 28, HandType: TwoPair}, + {Cards: "KTJJT", Bid: 220, HandType: FourOfAKind}, + }, + }, + expected: InputV2{ + Hands: []HandV2{ + {Cards: "32T3K", Bid: 765, HandType: OnePair}, + {Cards: "KK677", Bid: 28, HandType: TwoPair}, + {Cards: "T55J5", Bid: 684, HandType: FourOfAKind}, + {Cards: "QQQJA", Bid: 483, HandType: FourOfAKind}, + {Cards: "KTJJT", Bid: 220, HandType: FourOfAKind}, + }, + }, + }, + { + input: InputV2{ + Hands: []HandV2{ + {Cards: "T3T3J", Bid: 17, HandType: FullHouse}, + {Cards: "Q2KJJ", Bid: 13, HandType: ThreeOfAKind}, + {Cards: "JJJQA", Bid: 483, HandType: FourOfAKind}, + }, + }, + expected: InputV2{ + Hands: []HandV2{ + {Cards: "Q2KJJ", Bid: 13, HandType: ThreeOfAKind}, + {Cards: "T3T3J", Bid: 17, HandType: FullHouse}, + {Cards: "JJJQA", Bid: 483, HandType: FourOfAKind}, + }, + }, + }, + } + + for _, tc := range tests { + tc.input.SortHands() + assert.Equal(t, tc.expected, tc.input) + } +} + +func TestComputeTotalPointsV2(t *testing.T) { + input := InputV2{ + Hands: []HandV2{ + {Cards: "T55J5", Bid: 684, HandType: FourOfAKind}, + {Cards: "32T3K", Bid: 765, HandType: OnePair}, + {Cards: "QQQJA", Bid: 483, HandType: FourOfAKind}, + {Cards: "KK677", Bid: 28, HandType: TwoPair}, + {Cards: "KTJJT", Bid: 220, HandType: FourOfAKind}, + }, + } + + expected := 5905 + + assert.Equal(t, expected, input.ComputeTotalPoints()) +}