Completed both parts of Day 15 puzzle
parent
c7025518ab
commit
08d1136101
@ -0,0 +1,171 @@
|
||||
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
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package day15
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gitea.paas.celticinfo.fr/oabrivard/aoc2023/utils"
|
||||
)
|
||||
|
||||
func TestHash(t *testing.T) {
|
||||
result := hash([]byte("rn=1"))
|
||||
|
||||
if result != 30 {
|
||||
t.Fatalf("expected 30, got %v", result)
|
||||
}
|
||||
|
||||
result = hash([]byte("cm-"))
|
||||
|
||||
if result != 253 {
|
||||
t.Fatalf("expected 253, got %v", result)
|
||||
}
|
||||
|
||||
result = hash([]byte("qp=3"))
|
||||
|
||||
if result != 97 {
|
||||
t.Fatalf("expected 97, got %v", result)
|
||||
}
|
||||
|
||||
result = hash([]byte("cm=2"))
|
||||
|
||||
if result != 47 {
|
||||
t.Fatalf("expected 47, got %v", result)
|
||||
}
|
||||
|
||||
result = hash([]byte("qp-"))
|
||||
|
||||
if result != 14 {
|
||||
t.Fatalf("expected 14, got %v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSumHashes(t *testing.T) {
|
||||
result := SumHashes("rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7,")
|
||||
|
||||
if result != 1320 {
|
||||
t.Fatalf("expected 1320, got %v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSumHashesWithInput(t *testing.T) {
|
||||
lines := utils.ReadLines("input.txt")
|
||||
|
||||
result := SumHashes(lines[0])
|
||||
|
||||
if result != 511416 {
|
||||
t.Fatalf("expected 511416, got %v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSumBoxes(t *testing.T) {
|
||||
result := SumBoxes("rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7,")
|
||||
|
||||
if result != 145 {
|
||||
t.Fatalf("expected 145, got %v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSumBoxesWithInput(t *testing.T) {
|
||||
lines := utils.ReadLines("input.txt")
|
||||
|
||||
result := SumBoxes(lines[0])
|
||||
|
||||
if result != 290779 {
|
||||
t.Fatalf("expected 290779, got %v", result)
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue