adventOfCode/internal/2023/day_07/in.go

285 lines
5.6 KiB
Go
Raw Normal View History

2022-12-06 21:10:52 +00:00
package day_07
2023-12-07 14:30:39 +00:00
import (
"fmt"
"sort"
"strings"
"git.rpjosh.de/RPJosh/go-logger"
"rpjosh.de/adventOfCode/pkg/utils"
)
type Day struct {
hands map[byte]int
}
2022-12-06 21:10:52 +00:00
func (d *Day) Part1(in string) string {
2023-12-07 14:30:39 +00:00
inSplit := strings.Split(in, "\n")
//inSplit := []string{"23332 246"}
hands := map[byte]int{
'A': 0,
'K': 1,
'Q': 2,
'J': 3,
'T': 4,
'9': 5,
'8': 6,
'7': 7,
'6': 8,
'5': 9,
'4': 10,
'3': 11,
'2': 12,
}
sort.SliceStable(inSplit, func(a, b int) bool {
aVal := getTypeOrders(strings.Split(inSplit[a], " ")[0])
bVal := getTypeOrders(strings.Split(inSplit[b], " ")[0])
if aVal > bVal {
return true
} else if aVal == bVal {
// Get first number
aS := strings.Split(inSplit[a], " ")[0]
bS := strings.Split(inSplit[b], " ")[0]
for i := 0; i < 5; i++ {
if hands[aS[i]] > hands[bS[i]] {
return true
} else if hands[aS[i]] == hands[bS[i]] {
continue
} else {
return false
}
}
logger.Error("Two values are the same. What to do?")
return false
} else {
return false
}
})
rtc := 0
for i, val := range inSplit {
if val == "" {
continue
}
logger.Debug("%s == %d", val, getTypeOrders(strings.Split(val, " ")[0]))
rtc += (i + 1) * utils.ToInt(strings.Split(val, " ")[1])
}
return fmt.Sprintf("%d", rtc)
}
type Values struct {
val rune
count int
positions string
}
func getTypeOrders(numbers string) int {
if len(numbers) < 4 {
logger.Error("Received invalid input: %q", numbers)
return 0
}
// Five in a row
if strings.Count(numbers, string(numbers[0])) == 5 {
return 1
}
// Four in a row
if strings.Count(numbers, string(numbers[0])) == 4 || strings.Count(numbers, string(numbers[1])) == 4 {
return 2
}
// Prepare values
numbersSorted := utils.SortRunes(numbers)
runeMap := map[rune]int{}
// Three of a kind or full house
vals := make([]Values, 3)
for i, val := range numbers {
if vals[0].val == val {
vals[0].count += 1
vals[0].positions += fmt.Sprintf("%d", i)
} else if vals[1].val == val {
vals[1].count += 1
vals[1].positions += fmt.Sprintf("%d", i)
} else if vals[2].val == val {
vals[2].count += 1
vals[2].positions += fmt.Sprintf("%d", i)
} else if vals[0].count == 0 {
vals[0].val = val
vals[0].count = 1
vals[0].positions += fmt.Sprintf("%d", i)
} else if vals[1].count == 0 {
vals[1].val = val
vals[1].count = 1
vals[1].positions += fmt.Sprintf("%d", i)
} else if vals[2].count == 0 {
vals[2].val = val
vals[2].count = 1
vals[2].positions += fmt.Sprintf("%d", i)
}
}
// We need three same kinds
threeValid := false
for i := 0; i < 3; i++ {
if vals[i].count == 3 {
threeValid = true
/*
//logger.Debug("==== Having three")
// In order
lastVal := int(vals[i].positions[0])
for _, r := range vals[i].positions[1:] {
//logger.Debug("order: %d %d", lastVal, r-1)
if lastVal == int(r)-1 {
threeValid = true
lastVal = int(r)
} else {
threeValid = false
}
}
*/
}
}
if threeValid && ((vals[0].count == 3 && vals[1].count == 1) || (vals[1].count == 3 && vals[0].count == 1) || vals[2].count == 3 && vals[0].count == 1) {
return 4
} else if threeValid && (vals[1].count == 2 || vals[0].count == 2 || vals[3].count == 2) {
return 3
}
// Two pair
runeMap = map[rune]int{}
for _, val := range numbersSorted {
runeMap[val] += 1
}
pairs := 0
for _, val := range runeMap {
if val == 2 {
pairs += 1
}
}
// Two pairs
if pairs == 2 {
return 5
}
// One pair
if pairs == 1 {
return 6
}
// Do we need to distinct?
areDistinct := true
for _, val := range runeMap {
if val > 1 {
logger.Fatal("Values are not distinct. That's a logic error: %q", numbers)
areDistinct = false
}
}
if areDistinct {
return 7
}
return 10
}
func (d *Day) GetBestJokerValue(numbers string) string {
// Nothing to do here
if !strings.Contains(numbers, "J") {
return numbers
}
// Loop through every 'J'. A 'J' can occur twice -> Brute force with recursion :)
bestNumbers := ""
lastValue := 20
for k := range d.hands {
// Not allowed - endless loop!
if k == 'J' {
continue
}
lastJ := strings.LastIndex(numbers, "J")
numbersNew := utils.ReplaceCharacterInString(numbers, string(k), lastJ)
// Replace any other 'J' value
numbersNew = d.GetBestJokerValue(numbersNew)
// Test the value
result := getTypeOrders(numbersNew)
// Better result
if result < lastValue {
lastValue = result
bestNumbers = numbersNew
}
}
return bestNumbers
2022-12-06 21:10:52 +00:00
}
func (d *Day) Part2(in string) string {
2023-12-07 14:30:39 +00:00
inSplit := strings.Split(in, "\n")
//inSplit := []string{"23332 246"}
d.hands = map[byte]int{
'A': 0,
'K': 1,
'Q': 2,
'T': 4,
'9': 5,
'8': 6,
'7': 7,
'6': 8,
'5': 9,
'4': 10,
'3': 11,
'2': 12,
'J': 13,
}
sort.SliceStable(inSplit, func(a, b int) bool {
aVal := getTypeOrders(d.GetBestJokerValue(strings.Split(inSplit[a], " ")[0]))
bVal := getTypeOrders(d.GetBestJokerValue(strings.Split(inSplit[b], " ")[0]))
if aVal > bVal {
return true
} else if aVal == bVal {
// Get first number
aS := strings.Split(inSplit[a], " ")[0]
bS := strings.Split(inSplit[b], " ")[0]
for i := 0; i < 5; i++ {
if d.hands[aS[i]] > d.hands[bS[i]] {
return true
} else if d.hands[aS[i]] == d.hands[bS[i]] {
continue
} else {
return false
}
}
logger.Error("Two values are the same. What to do?")
return false
} else {
return false
}
})
rtc := 0
for i, val := range inSplit {
if val == "" {
continue
}
logger.Debug("%s == %d", val, getTypeOrders(strings.Split(val, " ")[0]))
rtc += (i + 1) * utils.ToInt(strings.Split(val, " ")[1])
}
return fmt.Sprintf("%d", rtc)
2022-12-06 21:10:52 +00:00
}