Add day 15 part 2
This commit is contained in:
parent
ef7d3b5f08
commit
6817e25645
139
day15/main.go
139
day15/main.go
|
@ -1,12 +1,83 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"container/list"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type HashMap[V any] []*list.List
|
||||||
|
|
||||||
|
type HashMapItem[V any] struct {
|
||||||
|
key string
|
||||||
|
value V
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operation is some sort of operation we can perform on a hashmap
|
||||||
|
type Operation[V any] func(HashMap[V])
|
||||||
|
|
||||||
|
// makeSetOperation makes an Operation that will set the given key to the given value in the hashmap
|
||||||
|
func makeSetOperation[V any](key string, value V) Operation[V] {
|
||||||
|
return func(hm HashMap[V]) {
|
||||||
|
keyHash := hash(key)
|
||||||
|
|
||||||
|
element := findInList(hm[keyHash], func(item HashMapItem[V]) bool {
|
||||||
|
return item.key == key
|
||||||
|
})
|
||||||
|
|
||||||
|
if element == nil {
|
||||||
|
hm[keyHash].PushBack(HashMapItem[V]{key: key, value: value})
|
||||||
|
} else {
|
||||||
|
element.Value = HashMapItem[V]{value: value, key: key}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeDeleteOperation makes an Operation that will delete the given key from the hashmap
|
||||||
|
func makeDeleteOperation[V any](key string) Operation[V] {
|
||||||
|
return func(hm HashMap[V]) {
|
||||||
|
keyHash := hash(key)
|
||||||
|
element := findInList(hm[keyHash], func(item HashMapItem[V]) bool {
|
||||||
|
return item.key == key
|
||||||
|
})
|
||||||
|
|
||||||
|
if element != nil {
|
||||||
|
hm[keyHash].Remove(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHashMap makes a new hash map with the given value type
|
||||||
|
func NewHashMap[V any]() HashMap[V] {
|
||||||
|
m := make(HashMap[V], 256)
|
||||||
|
for i := range m {
|
||||||
|
m[i] = list.New().Init()
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// EntriesInBox gets all the entries in the hash map box with the given index
|
||||||
|
func (hm HashMap[V]) EntriesInBox(idx int) ([]HashMapItem[V], error) {
|
||||||
|
if idx > len(hm) {
|
||||||
|
return nil, errors.New("out of bounds box id")
|
||||||
|
}
|
||||||
|
|
||||||
|
entryList := hm[idx]
|
||||||
|
res := make([]HashMapItem[V], 0, entryList.Len())
|
||||||
|
for cursor := entryList.Front(); cursor != nil; cursor = cursor.Next() {
|
||||||
|
value := cursor.Value.(HashMapItem[V])
|
||||||
|
res = append(res, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) != 2 && len(os.Args) != 3 {
|
if len(os.Args) != 2 && len(os.Args) != 3 {
|
||||||
fmt.Fprintf(os.Stderr, "Usage: %s inputfile\n", os.Args[0])
|
fmt.Fprintf(os.Stderr, "Usage: %s inputfile\n", os.Args[0])
|
||||||
|
@ -30,6 +101,7 @@ func main() {
|
||||||
inputElements := strings.Split(input, ",")
|
inputElements := strings.Split(input, ",")
|
||||||
|
|
||||||
fmt.Printf("Part 1: %d\n", part1(inputElements))
|
fmt.Printf("Part 1: %d\n", part1(inputElements))
|
||||||
|
fmt.Printf("Part 2: %d\n", part2(inputElements))
|
||||||
}
|
}
|
||||||
|
|
||||||
func part1(inputElements []string) int {
|
func part1(inputElements []string) int {
|
||||||
|
@ -41,6 +113,39 @@ func part1(inputElements []string) int {
|
||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func part2(inputElements []string) int {
|
||||||
|
operations := make([]Operation[int], 0, len(inputElements))
|
||||||
|
for _, element := range inputElements {
|
||||||
|
operation, err := parseOperation(element)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("could not parse operation %q: %s", element, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
operations = append(operations, operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
hm := NewHashMap[int]()
|
||||||
|
for _, operation := range operations {
|
||||||
|
operation(hm)
|
||||||
|
}
|
||||||
|
|
||||||
|
power := 0
|
||||||
|
for i := range hm {
|
||||||
|
boxEntries, err := hm.EntriesInBox(i)
|
||||||
|
if err != nil {
|
||||||
|
// Can't happen since we're iterating over the known array
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
boxNumber := i + 1
|
||||||
|
for j, item := range boxEntries {
|
||||||
|
power += boxNumber * (j + 1) * item.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return power
|
||||||
|
}
|
||||||
|
|
||||||
func hash(s string) int {
|
func hash(s string) int {
|
||||||
res := 0
|
res := 0
|
||||||
for _, char := range s {
|
for _, char := range s {
|
||||||
|
@ -51,3 +156,37 @@ func hash(s string) int {
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// findInList finds the given element in the linked list. The element *MUST* be of the type V, or this will panic
|
||||||
|
func findInList[V any](l *list.List, isEqual func(V) bool) *list.Element {
|
||||||
|
for cursor := l.Front(); cursor != nil; cursor = cursor.Next() {
|
||||||
|
if isEqual(cursor.Value.(V)) {
|
||||||
|
return cursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseOperation(s string) (Operation[int], error) {
|
||||||
|
setPattern := regexp.MustCompile(`^([a-z]+)=(\d+)`)
|
||||||
|
deletePattern := regexp.MustCompile(`^([a-z]+)-$`)
|
||||||
|
|
||||||
|
setMatches := setPattern.FindStringSubmatch(s)
|
||||||
|
deleteMatches := deletePattern.FindStringSubmatch(s)
|
||||||
|
if setMatches != nil {
|
||||||
|
key := setMatches[1]
|
||||||
|
value, err := strconv.Atoi(setMatches[2])
|
||||||
|
if err != nil {
|
||||||
|
// cannot happen, since the pattern says this is a number
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeSetOperation(key, value), nil
|
||||||
|
} else if deleteMatches != nil {
|
||||||
|
key := deleteMatches[1]
|
||||||
|
return makeDeleteOperation[int](key), nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("invalid operation string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue