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
|
|
|
}
|