summaryrefslogtreecommitdiff
path: root/go/2023/internal/day_07/part_01/part_01.go
diff options
context:
space:
mode:
authorDJ O'Leary <dijitol@proton.me>2026-06-26 18:04:09 +0200
committerDJ O'Leary <dijitol@proton.me>2026-06-26 18:04:09 +0200
commit6d8fb621d1e93b83786890d6d9cb6f0d8defa8ae (patch)
tree17c90d3984c114aa023600cc5bec6f6004b02243 /go/2023/internal/day_07/part_01/part_01.go
parentad4ea5ca4bc9f7540ee1d6a4fa2d881709dc6459 (diff)
refactor!: invert repo directory structure
now is language first
Diffstat (limited to 'go/2023/internal/day_07/part_01/part_01.go')
-rw-r--r--go/2023/internal/day_07/part_01/part_01.go273
1 files changed, 273 insertions, 0 deletions
diff --git a/go/2023/internal/day_07/part_01/part_01.go b/go/2023/internal/day_07/part_01/part_01.go
new file mode 100644
index 0000000..a485dfd
--- /dev/null
+++ b/go/2023/internal/day_07/part_01/part_01.go
@@ -0,0 +1,273 @@
+package part_01
+
+import (
+ "os"
+ "strconv"
+ "strings"
+)
+
+const USE_SAMPLE = false
+
+type handType int
+
+const (
+ HIGH_CARD handType = iota
+ PAIR
+ TWO_PAIR
+ THREE_OF_A_KIND
+ FULL_HOUSE
+ FOUR_OF_A_KIND
+ FIVE_OF_A_KIND
+)
+
+func (h handType) String() string {
+ return [...]string{"HIGH_CARD", "PAIR", "TWO_PAIR", "THREE_OF_A_KIND", "FULL_HOUSE", "FOUR_OF_A_KIND", "FIVE_OF_A_KIND"}[h]
+}
+
+type cardType int
+
+const (
+ TWO cardType = iota
+ THREE
+ FOUR
+ FIVE
+ SIX
+ SEVEN
+ EIGHT
+ NINE
+ TEN
+ JACK
+ QUEEN
+ KING
+ ACE
+)
+
+func (c cardType) String() string {
+ return [...]string{"TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE", "TEN", "JACK", "QUEEN", "KING", "ACE"}[c]
+}
+
+type hand struct {
+ strength handType
+ cards []cardType
+ bet int
+}
+
+/**
+ * Tried:
+ * - 252489894 (too high)
+ * - 229176554 (too low)
+ * - 200253108 (too low)
+ */
+func Solve() {
+ var filePath string
+ if USE_SAMPLE {
+ filePath = "../_input/day_07_part_01_sample.txt"
+ } else {
+ filePath = "../_input/day_07.txt"
+ }
+ contents, err := os.ReadFile(filePath)
+ if err != nil {
+ panic(err)
+ }
+
+ lines := strings.Split(string(contents), "\r\n")
+ var hands []hand
+ for _, line := range lines {
+ if line == "" {
+ continue
+ }
+
+ hands = append(hands, parseLine(line))
+ }
+
+ mappedByStrength := mapByStrength(hands)
+
+ sortedByHighest := make(map[handType][]hand)
+ for _, strength := range []handType{HIGH_CARD, PAIR, TWO_PAIR, THREE_OF_A_KIND, FULL_HOUSE, FOUR_OF_A_KIND, FIVE_OF_A_KIND} {
+ if _, ok := mappedByStrength[strength]; !ok {
+ continue
+ }
+
+ toBeSorted := mappedByStrength[strength]
+ sortedByHighest[strength] = sortByHighest(toBeSorted)
+ }
+
+ flattened := flatten(sortedByHighest)
+
+ answer := calculateWinnings(flattened)
+
+ println("Answer: ", answer)
+}
+
+func parseLine(line string) hand {
+ parts := strings.Split(line, " ")
+
+ unparsedCards := strings.Split(parts[0], "")
+ cards := parseCards(unparsedCards)
+ strength := calculateStrength(cards)
+
+ bet, err := strconv.Atoi(parts[1])
+ if err != nil {
+ panic(err)
+ }
+
+ return hand{
+ strength,
+ cards,
+ bet,
+ }
+}
+
+func parseCards(unparsedCards []string) []cardType {
+ var cards []cardType
+ for _, card := range unparsedCards {
+ switch card {
+ case "2":
+ cards = append(cards, TWO)
+ case "3":
+ cards = append(cards, THREE)
+ case "4":
+ cards = append(cards, FOUR)
+ case "5":
+ cards = append(cards, FIVE)
+ case "6":
+ cards = append(cards, SIX)
+ case "7":
+ cards = append(cards, SEVEN)
+ case "8":
+ cards = append(cards, EIGHT)
+ case "9":
+ cards = append(cards, NINE)
+ case "T":
+ cards = append(cards, TEN)
+ case "J":
+ cards = append(cards, JACK)
+ case "Q":
+ cards = append(cards, QUEEN)
+ case "K":
+ cards = append(cards, KING)
+ case "A":
+ cards = append(cards, ACE)
+ }
+ }
+ return cards
+}
+
+func calculateStrength(cards []cardType) handType {
+ strength := map[cardType]int{}
+ for _, card := range cards {
+ if _, ok := strength[card]; !ok {
+ strength[card] = 0
+ }
+ strength[card]++
+ }
+
+ var pairs int
+ var hasThreeOfAKind bool
+ for _, count := range strength {
+ if count == 5 {
+ return FIVE_OF_A_KIND
+ }
+
+ if count == 4 {
+ return FOUR_OF_A_KIND
+ }
+
+ if count == 3 {
+ hasThreeOfAKind = true
+ }
+
+ if count == 2 {
+ pairs++
+ }
+ }
+
+ if hasThreeOfAKind && pairs == 1 {
+ return FULL_HOUSE
+ }
+
+ if hasThreeOfAKind {
+ return THREE_OF_A_KIND
+ }
+
+ if pairs == 2 {
+ return TWO_PAIR
+ }
+
+ if pairs == 1 {
+ return PAIR
+ }
+
+ return HIGH_CARD
+}
+
+func mapByStrength(hands []hand) map[handType][]hand {
+
+ handsByStrength := make(map[handType][]hand)
+ for _, hand := range hands {
+ handsByStrength[hand.strength] = append(handsByStrength[hand.strength], hand)
+ }
+
+ return handsByStrength
+}
+
+// low to high
+func sortByHighest(hands []hand) []hand {
+ var partition = func(arr []hand, low, high int) ([]hand, int) {
+ pivot := arr[high]
+ index := low
+
+ for i := low; i < high; i++ {
+ // Always 5 cards
+ for j := 0; j < 5; j++ {
+ if arr[i].cards[j] < pivot.cards[j] {
+ arr[i], arr[index] = arr[index], arr[i]
+ index++
+ break
+ }
+
+ if arr[i].cards[j] != pivot.cards[j] {
+ break
+ }
+ }
+ }
+
+ arr[high], arr[index] = arr[index], arr[high]
+
+ return arr, index
+ }
+
+ var quickSort func(arr []hand, low, high int) []hand
+ quickSort = func(arr []hand, low, high int) []hand {
+ if low < high {
+ arr, pivot := partition(arr, low, high)
+
+ quickSort(arr, low, pivot-1)
+ quickSort(arr, pivot+1, high)
+ }
+
+ return arr
+ }
+
+ hands = quickSort(hands, 0, len(hands)-1)
+
+ return hands
+}
+
+func flatten(hands map[handType][]hand) []hand {
+ var flat []hand
+ for _, handType := range []handType{HIGH_CARD, PAIR, TWO_PAIR, THREE_OF_A_KIND, FULL_HOUSE, FOUR_OF_A_KIND, FIVE_OF_A_KIND} {
+ flat = append(flat, hands[handType]...)
+ }
+ return flat
+}
+
+func calculateWinnings(hands []hand) int {
+ var winnings int
+ for i, hand := range hands {
+ earned := hand.bet * (i + 1)
+ winnings += earned
+ println("hand ", i, ": { strength: ", hand.strength.String(), ", cards: [", hand.cards[0], hand.cards[1], hand.cards[2], hand.cards[3], hand.cards[4], "], earned: ", earned, " }")
+ }
+ return winnings
+}