149 lines
2.8 KiB
Go
149 lines
2.8 KiB
Go
package day15
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"regexp"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func Run() int {
|
|
fmt.Println("hello day 15")
|
|
log.Println("hello day 15")
|
|
filename := "day15/input"
|
|
bytes, err := os.ReadFile(filename)
|
|
if err != nil {
|
|
panic(fmt.Sprint("error reading file ", filename))
|
|
}
|
|
text := string(bytes)
|
|
text = strings.TrimSpace(text)
|
|
instructions := strings.Split(text, ",")
|
|
|
|
result := 0
|
|
|
|
boxes := make([]Box, 256)
|
|
for i, box := range boxes {
|
|
box.Focals = make(map[string]int)
|
|
boxes[i] = box
|
|
}
|
|
|
|
for _, instructionStr := range instructions {
|
|
i := ReadInstruction(instructionStr)
|
|
box := boxes[i.Box]
|
|
box.Act(i)
|
|
boxes[i.Box] = box
|
|
|
|
// result += ASCIIStringHash(instruction)
|
|
}
|
|
|
|
for i, box := range boxes {
|
|
if len(box.Labels) != 0 {
|
|
log.Printf("%d box %+v final state\n", i, box)
|
|
}
|
|
result += (i + 1) * box.FocusingPower()
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
type Box struct {
|
|
Labels []string
|
|
Focals map[string]int
|
|
}
|
|
|
|
func (b *Box)Act(i Instruction) {
|
|
log.Printf("for box %+v instruction \n%s\n", b, i.String())
|
|
switch i.Action {
|
|
case Put:
|
|
_, found := b.Focals[i.Label]
|
|
if !found {
|
|
b.Labels = append(b.Labels, i.Label)
|
|
}
|
|
b.Focals[i.Label] = i.LensFocal
|
|
|
|
case Remove:
|
|
_, found := b.Focals[i.Label]
|
|
if !found {
|
|
return
|
|
}
|
|
index := slices.Index(b.Labels, i.Label)
|
|
delete(b.Focals, i.Label)
|
|
b.Labels = slices.Delete(b.Labels, index, index+1)
|
|
}
|
|
log.Printf("result : %+v\n", b)
|
|
return
|
|
}
|
|
|
|
func (b *Box)FocusingPower() int {
|
|
result := 0
|
|
for i, label := range b.Labels {
|
|
result += (i + 1) * b.Focals[label]
|
|
}
|
|
return result
|
|
}
|
|
|
|
type Action rune
|
|
|
|
const (
|
|
Put Action = '='
|
|
Remove = '-'
|
|
)
|
|
|
|
type Instruction struct {
|
|
Label string
|
|
Box int
|
|
Action Action
|
|
LensFocal int
|
|
}
|
|
|
|
func (i *Instruction) String() string {
|
|
operation := ""
|
|
switch i.Action {
|
|
case Put:
|
|
operation = "put into"
|
|
case Remove:
|
|
operation = "remove from"
|
|
}
|
|
return fmt.Sprintf("%s\t\t%d of focal %d %s", operation, i.Box, i.LensFocal, i.Label)
|
|
}
|
|
|
|
func ReadInstruction(str string) Instruction {
|
|
result := Instruction{}
|
|
|
|
re := regexp.MustCompile(`(?P<label>\D+)(?P<operation>[=\-])(?P<focal>\d*)`)
|
|
// log.Println("in str ", str)
|
|
fields := re.FindStringSubmatch(str)
|
|
// log.Printf("in %s found %+v", str, fields)
|
|
|
|
operation := fields[2]
|
|
operationRune := []rune(operation)[0]
|
|
result.Action = Action(operationRune)
|
|
|
|
if operationRune == '=' {
|
|
focalStr := fields[3]
|
|
focal, err := strconv.Atoi(focalStr)
|
|
if err != nil {
|
|
panic(fmt.Sprint("error reading focal from ", str))
|
|
}
|
|
result.LensFocal = focal
|
|
}
|
|
|
|
result.Label = fields[1]
|
|
result.Box = ASCIIStringHash(result.Label)
|
|
|
|
return result
|
|
}
|
|
|
|
func ASCIIStringHash(str string) int {
|
|
result := 0
|
|
for _, symb := range str {
|
|
result += int(symb)
|
|
result *= 17
|
|
result %= 256
|
|
}
|
|
return result
|
|
}
|