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.
172 lines
2.6 KiB
Go
172 lines
2.6 KiB
Go
package day15
|
|
|
|
import "strconv"
|
|
|
|
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
|
|
}
|