You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
3.2 KiB
Go

package day15
import (
"strconv"
"strings"
"gitea.paas.celticinfo.fr/oabrivard/aoc2023/utils"
)
func hash(bytes []byte) int {
val := 0
for _, b := range bytes {
val += int(b)
val *= 17
val %= 256
}
return val
}
func SumHashes(line string) int {
result := 0
l := []byte(line)
step := []byte{}
for _, b := range l {
if b == '\n' {
break
}
if b == ',' {
hashValue := hash(step)
result += hashValue
step = []byte{}
} else {
step = append(step, b)
}
}
return result
}
type Lense struct {
label string
focal int
}
type Lenses []*Lense
type LensePresences map[string]int
type Box struct {
lenses Lenses
lensePresences LensePresences
}
func parseStep(bytes []byte) (string, byte, int) {
label := []byte{}
focal := []byte{}
parseFocal := false
for _, b := range bytes {
if b == '-' {
return string(label), '-', -1
}
if b == '=' {
parseFocal = true
continue
}
if parseFocal {
focal = append(focal, b)
} else {
label = append(label, b)
}
}
focalValue, _ := strconv.Atoi(string(focal))
return string(label), '=', focalValue
}
func removeLense(box *Box, label string) {
idx, ok := box.lensePresences[label]
if ok {
delete(box.lensePresences, label)
/*
idx := 0
for i, lense := range box.lenses {
if lense.label == label {
idx = i
break
}
}
*/
for i := idx; i < len(box.lenses)-1; i++ {
box.lenses[i] = box.lenses[i+1]
box.lensePresences[box.lenses[i].label] = i
}
box.lenses = box.lenses[0 : len(box.lenses)-1]
}
}
func addOrChangeLense(box *Box, label string, focal int) {
newLense := &Lense{label, focal}
idx, ok := box.lensePresences[label]
if ok { // change lense
box.lenses[idx] = newLense
} else {
// add lense
box.lenses = append(box.lenses, newLense)
box.lensePresences[label] = len(box.lenses) - 1
}
}
func SumBoxes(line string) int {
l := []byte(line)
boxes := make([]*Box, 256)
step := []byte{}
for _, b := range l {
if b == '\n' {
break
}
if b == ',' {
label, operator, focal := parseStep(step)
labelHash := hash([]byte(label))
box := boxes[labelHash]
if box == nil {
box = &Box{Lenses{}, LensePresences{}}
boxes[labelHash] = box
}
if operator == '-' {
removeLense(box, label)
if len(box.lenses) == 0 {
box = nil
boxes[labelHash] = nil
}
} else {
addOrChangeLense(box, label, focal)
}
step = []byte{}
} else {
step = append(step, b)
}
}
sum := 0
for i, box := range boxes {
if box != nil {
boxNumber := i + 1
for j, lense := range box.lenses {
slotNumber := j + 1
focusingPower := boxNumber * slotNumber * lense.focal
sum += focusingPower
}
}
}
return sum
}
func Hash(bytes []byte) int {
return utils.Reduce(bytes, 0, func(acc int, curr byte) int {
return (acc + int(curr)) * 17 % 256
})
}
func Part1(line string) int {
/*
fmt.Println(utils.Reduce(
utils.Map(strings.Split(line, ","), func(step string) int { return Hash([]byte(step)) }),
0,
func(acc int, curr int) int { return acc + curr }))
*/
hashes := utils.Map(strings.Split(line, ","), func(step string) int { return Hash([]byte(step)) })
return utils.Reduce(hashes, 0, func(acc int, curr int) int { return acc + curr })
}