solutions for the Advent of Code 2023
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
6.2 KiB

package main
import (
"bufio"
"fmt"
"io"
"sort"
"strconv"
)
type day07 struct{}
type rank int
const (
highCard rank = iota
onePair
twoPair
threeOfAKind
fullHouse
fourOfAKind
fiveOfAKind
)
type hand struct {
cards []rune
values []int
rank rank
bid int
}
type hands []hand
func (h hands) Len() int {
return len(h)
}
func (h hands) Less(i, j int) bool {
h1 := h[i]
h2 := h[j]
if h1.rank < h2.rank {
return true
} else if h1.rank > h2.rank {
return false
} else {
for k := 0; k < 5; k++ {
if h1.values[k] < h2.values[k] {
return true
} else if h1.values[k] > h2.values[k] {
return false
}
}
panic("not reachable")
}
}
func (h hands) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
}
// returns the rank and values of the hand
func camelrank(hand hand) (rank, []int) {
counts := make([]int, 14)
hand.values = make([]int, len(hand.cards))
for i, r := range hand.cards {
switch r {
case '1':
counts[0] = counts[0] + 1
hand.values[i] = 1
case '2':
counts[1] = counts[1] + 1
hand.values[i] = 2
case '3':
counts[2] = counts[2] + 1
hand.values[i] = 3
case '4':
counts[3] = counts[3] + 1
hand.values[i] = 4
case '5':
counts[4] = counts[4] + 1
hand.values[i] = 5
case '6':
counts[5] = counts[5] + 1
hand.values[i] = 6
case '7':
counts[6] = counts[6] + 1
hand.values[i] = 7
case '8':
counts[7] = counts[7] + 1
hand.values[i] = 8
case '9':
counts[8] = counts[8] + 1
hand.values[i] = 9
case 'T':
counts[9] = counts[9] + 1
hand.values[i] = 10
case 'J':
counts[10] = counts[10] + 1
hand.values[i] = 11
case 'Q':
counts[11] = counts[11] + 1
hand.values[i] = 12
case 'K':
counts[12] = counts[12] + 1
hand.values[i] = 13
case 'A':
counts[13] = counts[13] + 1
hand.values[i] = 14
}
}
var (
seenPair bool
seenThreeOfAKind bool
)
for _, count := range counts {
switch count {
case 0:
case 1:
continue
case 2:
if seenPair {
return twoPair, hand.values
} else if seenThreeOfAKind {
return fullHouse, hand.values
}
seenPair = true
case 3:
if seenPair {
return fullHouse, hand.values
}
seenThreeOfAKind = true
case 4:
return fourOfAKind, hand.values
case 5:
return fiveOfAKind, hand.values
}
}
if seenPair {
return onePair, hand.values
} else if seenThreeOfAKind {
return threeOfAKind, hand.values
}
return highCard, hand.values
}
func camelrankjoker(hand hand) (rank, []int, int) {
counts := make([]int, 14)
jokers := 0
hand.values = make([]int, len(hand.cards))
for i, r := range hand.cards {
switch r {
case '1':
counts[0] = counts[0] + 1
hand.values[i] = 1
case '2':
counts[1] = counts[1] + 1
hand.values[i] = 2
case '3':
counts[2] = counts[2] + 1
hand.values[i] = 3
case '4':
counts[3] = counts[3] + 1
hand.values[i] = 4
case '5':
counts[4] = counts[4] + 1
hand.values[i] = 5
case '6':
counts[5] = counts[5] + 1
hand.values[i] = 6
case '7':
counts[6] = counts[6] + 1
hand.values[i] = 7
case '8':
counts[7] = counts[7] + 1
hand.values[i] = 8
case '9':
counts[8] = counts[8] + 1
hand.values[i] = 9
case 'T':
counts[9] = counts[9] + 1
hand.values[i] = 10
case 'J':
jokers++
hand.values[i] = 1
case 'Q':
counts[11] = counts[11] + 1
hand.values[i] = 12
case 'K':
counts[12] = counts[12] + 1
hand.values[i] = 13
case 'A':
counts[13] = counts[13] + 1
hand.values[i] = 14
}
}
var (
seenPair bool
seenThreeOfAKind bool
)
for _, count := range counts {
switch count {
case 0:
case 1:
continue
case 2:
if seenPair {
return twoPair, hand.values, jokers
} else if seenThreeOfAKind {
return fullHouse, hand.values, jokers
}
seenPair = true
case 3:
if seenPair {
return fullHouse, hand.values, jokers
}
seenThreeOfAKind = true
case 4:
return fourOfAKind, hand.values, jokers
case 5:
return fiveOfAKind, hand.values, jokers
}
}
if seenPair {
return onePair, hand.values , jokers
} else if seenThreeOfAKind {
return threeOfAKind, hand.values, jokers
}
return highCard, hand.values, jokers
}
func upgraderank(hand hand, jokers int) rank {
var upgrades [4]rank
switch hand.rank {
case highCard:
if jokers == 5 {
return fiveOfAKind
}
upgrades = [4]rank{onePair, threeOfAKind, fourOfAKind, fiveOfAKind}
case onePair:
upgrades = [4]rank{threeOfAKind, fourOfAKind, fiveOfAKind, fiveOfAKind}
case twoPair:
upgrades = [4]rank{fullHouse, fullHouse, fullHouse, fullHouse}
case threeOfAKind:
upgrades = [4]rank{fourOfAKind, fiveOfAKind, fiveOfAKind, fiveOfAKind}
case fullHouse:
upgrades = [4]rank{fullHouse, fullHouse, fullHouse, fullHouse}
case fourOfAKind:
upgrades = [4]rank{fiveOfAKind, fiveOfAKind, fiveOfAKind, fiveOfAKind}
case fiveOfAKind:
upgrades = [4]rank{fiveOfAKind, fiveOfAKind, fiveOfAKind, fiveOfAKind}
}
if jokers > 0 {
return upgrades[jokers-1]
}
return hand.rank
}
func (d day07) solve1(r io.Reader) string {
total := 0
var hands hands = make([]hand, 0)
scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanWords)
for i, w := 0, 0; scanner.Scan(); w++ {
word := scanner.Text()
if w%2 == 0 {
hand := hand{cards: []rune(word)}
hand.rank, hand.values = camelrank(hand)
hands = append(hands, hand)
} else {
val, err := strconv.ParseInt(word, 10, 64)
if err != nil {
panic(err)
}
hands[i].bid = int(val)
i++
}
}
sort.Sort(hands)
for i, hand := range hands {
total += hand.bid * (i + 1)
}
return fmt.Sprintf("%d", total)
}
func (d day07) solve2(r io.Reader) string {
total := 0
var hands hands = make([]hand, 0)
scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanWords)
for i, w := 0, 0; scanner.Scan(); w++ {
word := scanner.Text()
if w%2 == 0 {
hand := hand{cards: []rune(word)}
var jokers int
hand.rank, hand.values, jokers = camelrankjoker(hand)
hand.rank = upgraderank(hand, jokers)
hands = append(hands, hand)
} else {
val, err := strconv.ParseInt(word, 10, 64)
if err != nil {
panic(err)
}
hands[i].bid = int(val)
i++
}
}
sort.Sort(hands)
for i, hand := range hands {
total += hand.bid * (i + 1)
}
return fmt.Sprintf("%d", total)
}