package day10 import ( "cmp" "fmt" "math" "slices" "strconv" "strings" "git.bizdoc.ro/gabi-public/Advent-of-Code.git/aoc" "git.bizdoc.ro/private/devkit.git/collections/dsa" "git.bizdoc.ro/private/devkit.git/gg" ) func Part1(ctx aoc.Context) (int, error) { inputLines, err := ParseInput(ctx) if err != nil { return 0, fmt.Errorf("parse input: %w", err) } sum := 0 for _, line := range inputLines { if line.IndicatorLight == 0 { continue // zero by default } cache2 := make([]int, 1< 0 { if steps <= item.step { continue } } cache2[item.indicator] = item.step for _, button := range line.ButtonsNum { if item.step <= solution { stack.Push(Frame{ indicator: item.indicator ^ button, step: item.step + 1, //history: dsa.NewImmutableList(button, item.history), }) } } } sum += solution } return sum, nil } func compare[S ~[]E, E cmp.Ordered](s1, s2 S) (bool, bool) { isSolution := true for i := range len(s1) { canContinue := s1[i] >= s2[i] if !canContinue { return false, false } isSolution = isSolution && (s1[i] == s2[i]) } return true, isSolution } func Part2(ctx aoc.Context) (int, error) { // does not work inputLines, err := ParseInput(ctx) if err != nil { return 0, fmt.Errorf("parse input: %w", err) } var sum int for _, line := range inputLines { type Frame struct { state []byte step int history [][]int } stack := dsa.NewStack[Frame]() startFrameJoltage := make([]byte, len(line.Joltages)) for i, value := range line.Joltages { startFrameJoltage[i] = byte(value) if value > int(startFrameJoltage[i]) { panic("byte out of range") } } stack.Push(Frame{ state: make([]byte, len(line.Joltages)), step: 0, }) solution := math.MaxInt cache := make(map[string]int) for !stack.IsEmpty() { item := stack.Pop() if item.step > solution { continue } key := gg.UnsafeString(item.state) if steps, ok := cache[key]; ok { if steps < item.step { continue } } cache[key] = item.step canContinue, isSolution := compare(startFrameJoltage, item.state) if !canContinue { continue } if isSolution { //fmt.Println(item.state, item.step) solution = min(solution, item.step) //break } for _, button := range line.Buttons { state := slices.Clone(item.state) for _, val := range button { state[val] += 1 } stack.Push(Frame{ state: state, step: item.step + 1, //history: append(slices.Clone(item.history), state), }) } } ctx.Println(solution) sum += solution } return sum, nil } func ParseInput(ctx aoc.Context) ([]InputLine, error) { var inputLines []InputLine scanner := ctx.Scanner() for scanner.Scan() { line := scanner.Text() line = strings.TrimSpace(line) input, err := ParseInputLine([]rune(line)) if err != nil { return nil, fmt.Errorf("parse input: %w", err) } inputLines = append(inputLines, input) } if err := scanner.Err(); err != nil { return nil, fmt.Errorf("scanner error: %w", err) } return inputLines, nil } type InputLine struct { indicatorSize int IndicatorLight uint64 IndicatorLightRaw string Buttons [][]int ButtonsNum []uint64 Joltages []int RawLine string } func ParseInputLine(line []rune) (input InputLine, err error) { // [...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2} for i, ch := range line { input.RawLine = string(line) switch ch { case '[': // indicator light if input.IndicatorLight != 0 { return input, fmt.Errorf("duplicate Indicator Light in line: %s", string(line)) } size := i parseIndicatorLight: for i = i + 1; i < len(line); i++ { switch line[i] { case '#': input.IndicatorLight <<= 1 input.IndicatorLight |= 1 case ']': input.IndicatorLightRaw = string(line[size+1 : i]) size = i - size - 1 input.indicatorSize = size break parseIndicatorLight // done case '.': input.IndicatorLight <<= 1 default: return input, fmt.Errorf("failed to parse Indicator Light. Unexpected character in IndicatorLight: %s", string(line)) } } case '(': i += 1 j := strings.IndexByte(string(line[i:]), ')') if j == -1 { return input, fmt.Errorf("failed to parse button in line: %s", string(line)) } button := make([]int, 0) parts := strings.Split(string(line[i:i+j]), ",") for _, part := range parts { num, err := strconv.Atoi(part) if err != nil { return input, fmt.Errorf("failed to parse button in line: %s", string(line)) } if num < 0 { return input, fmt.Errorf("negative button value in line: %s", string(line)) } if num > input.indicatorSize { return input, fmt.Errorf("too many buttons in line: %s", string(line)) } button = append(button, num) } input.Buttons = append(input.Buttons, button) i = j case '{': i += 1 j := strings.IndexByte(string(line[i:]), '}') if j == -1 { return input, fmt.Errorf("failed to parse joltage in line: %s", string(line)) } joltage := make([]int, 0) parts := strings.Split(string(line[i:i+j]), ",") for _, part := range parts { num, err := strconv.Atoi(part) if err != nil { return input, fmt.Errorf("failed to parse joltage in line: %s", string(line)) } if num < 0 { return input, fmt.Errorf("negative joltage value in line: %s", string(line)) } joltage = append(joltage, num) } input.Joltages = joltage i = j } } input.ButtonsNum = make([]uint64, len(input.Buttons)) for i, button := range input.Buttons { for _, v := range button { input.ButtonsNum[i] |= 1 << uint64(input.indicatorSize-v-1) } } return input, nil }