2023: Day 7

master
Jonas Letzbor 2023-12-07 15:30:39 +01:00
parent 5b38cb0f30
commit 15985840a4
Signed by: RPJosh
GPG Key ID: 46D72F589702E55A
2 changed files with 294 additions and 6 deletions

View File

@ -1,11 +1,284 @@
package day_07 package day_07
type Day struct{} import (
"fmt"
"sort"
"strings"
"git.rpjosh.de/RPJosh/go-logger"
"rpjosh.de/adventOfCode/pkg/utils"
)
type Day struct {
hands map[byte]int
}
func (d *Day) Part1(in string) string { func (d *Day) Part1(in string) string {
return "" 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
} }
func (d *Day) Part2(in string) string { func (d *Day) Part2(in string) string {
return "" 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)
} }

View File

@ -6,11 +6,10 @@ import (
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
"sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"git.rpjosh.de/RPJosh/go-logger"
) )
// Copies the given string to the clipboard. // Copies the given string to the clipboard.
@ -89,7 +88,7 @@ func PrintError(format string, a ...any) {
func ToInt(val string) int { func ToInt(val string) int {
value, err := strconv.Atoi(val) value, err := strconv.Atoi(val)
if err != nil { if err != nil {
logger.Fatal("Failed to convert %q to a number: %s", val, err) panic(fmt.Sprintf("Failed to convert %q to a number: %s", val, err))
} }
return value return value
@ -135,3 +134,19 @@ func ConvertArrayToInt(values []string) []int {
return rtc return rtc
} }
// SortRunes sorts a string based on the rune value
// of every character
func SortRunes(value string) string {
runeSlice := []rune(value)
sort.Slice(runeSlice, func(i, j int) bool {
return runeSlice[i] < runeSlice[j]
})
return string(runeSlice)
}
// ReplaceCharacterInString replaces the character at the given index with
// the provided value
func ReplaceCharacterInString(str, replace string, index int) string {
return str[:index] + replace + str[index+1:]
}