2023: Day 7
parent
5b38cb0f30
commit
15985840a4
|
@ -1,11 +1,284 @@
|
|||
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 {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -6,11 +6,10 @@ import (
|
|||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rpjosh.de/RPJosh/go-logger"
|
||||
)
|
||||
|
||||
// Copies the given string to the clipboard.
|
||||
|
@ -89,7 +88,7 @@ func PrintError(format string, a ...any) {
|
|||
func ToInt(val string) int {
|
||||
value, err := strconv.Atoi(val)
|
||||
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
|
||||
|
@ -135,3 +134,19 @@ func ConvertArrayToInt(values []string) []int {
|
|||
|
||||
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:]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue