Skip to content

Commit

Permalink
day17
Browse files Browse the repository at this point in the history
  • Loading branch information
gamersi committed Dec 17, 2024
1 parent c2d6fc9 commit 6160a0b
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 0 deletions.
74 changes: 74 additions & 0 deletions day17p1/solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package day17p1

import (
"io"
"regexp"
"strconv"
"strings"

"aoc/utils"
)

func Solve(r io.Reader) any {
lines := utils.ReadLines(r)

numberRegexp := regexp.MustCompile(`\d+`)

aStart, _ := strconv.ParseUint(numberRegexp.FindString(lines[0]), 10, 64)

instructionsStr := numberRegexp.FindAllString(lines[4], -1)
instructions := make([]uint64, len(instructionsStr))
for i := 0; i < len(instructions); i++ {
instructions[i], _ = strconv.ParseUint(instructionsStr[i], 10, 64)
}

out := run(instructions, aStart)

return strings.Join(utils.UIntsToStrings(out), ",")
}

func run(instructions []uint64, initialA uint64) []uint64 {
registers := []uint64{initialA, 0, 0}

out := []uint64{}

instrPointer := uint64(0)

for instrPointer < uint64(len(instructions)) {
instruction := instructions[instrPointer]
operand := instructions[instrPointer+1]
switch instruction {
case 0:
registers[0] >>= evalComboOp(operand, registers)
case 1:
registers[1] ^= operand
case 2:
registers[1] = evalComboOp(operand, registers) & 7
case 3:
if registers[0] != 0 {
instrPointer = operand
continue
}
case 4:
registers[1] ^= registers[2]
case 5:
out = append(out, evalComboOp(operand, registers)&7)
case 6:
registers[1] = registers[0] >> evalComboOp(operand, registers)
case 7:
registers[2] = registers[0] >> evalComboOp(operand, registers)
}
instrPointer += 2
}
return out
}

func evalComboOp(instr uint64, registers []uint64) uint64 {
if instr <= 3 {
return instr
}
if instr <= 6 {
return registers[instr-4]
}
panic("Invalid instruction")
}
37 changes: 37 additions & 0 deletions day17p1/solution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package day17p1

import (
"strings"
"testing"

"aoc/utils"
)

var testInput = `Register A: 729
Register B: 0
Register C: 0
Program: 0,1,5,4,3,0`

func TestSolve(t *testing.T) {
tests := []struct {
input string
answer string
}{
{testInput, "4,6,3,5,6,3,5,2,1,0"},
}

if testing.Verbose() {
utils.Verbose = true
}

for _, test := range tests {
r := strings.NewReader(test.input)

result := Solve(r).(string)

if result != test.answer {
t.Errorf("Expected %s, got %s", test.answer, result)
}
}
}
81 changes: 81 additions & 0 deletions day17p2/solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package day17p2

import (
"io"
"regexp"
"slices"
"strconv"

"aoc/utils"
)

func Solve(r io.Reader) any {
lines := utils.ReadLines(r)

numberRegexp := regexp.MustCompile(`\d+`)

instructionsStr := numberRegexp.FindAllString(lines[4], -1)
instructions := make([]uint64, len(instructionsStr))
for i := 0; i < len(instructions); i++ {
instructions[i], _ = strconv.ParseUint(instructionsStr[i], 10, 64)
}

return solve(instructions)
}

func solve(instructions []uint64) uint64 {
aVal := uint64(0)
for i := len(instructions) - 1; i >= 0; i-- {
aVal <<= 3
for !slices.Equal(run(instructions, aVal), instructions[i:]) {
aVal++
}
}
return aVal
}

func run(instructions []uint64, initialA uint64) []uint64 {
registers := []uint64{initialA, 0, 0}

out := []uint64{}

instrPointer := uint64(0)

for instrPointer < uint64(len(instructions)) {
instruction := instructions[instrPointer]
operand := instructions[instrPointer+1]
switch instruction {
case 0:
registers[0] >>= evalComboOp(operand, registers)
case 1:
registers[1] ^= operand
case 2:
registers[1] = evalComboOp(operand, registers) & 7
case 3:
if registers[0] != 0 {
instrPointer = operand
continue
}
case 4:
registers[1] ^= registers[2]
case 5:
out = append(out, evalComboOp(operand, registers)&7)
case 6:
registers[1] = registers[0] >> evalComboOp(operand, registers)
case 7:
registers[2] = registers[0] >> evalComboOp(operand, registers)
}
instrPointer += 2
}
return out
}

func evalComboOp(instr uint64, registers []uint64) uint64 {
if instr <= 3 {
return instr
}
if instr <= 6 {
return registers[instr-4]
}
panic("Invalid instruction")
}
37 changes: 37 additions & 0 deletions day17p2/solution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package day17p2

import (
"strings"
"testing"

"aoc/utils"
)

var testInput = `Register A: 2024
Register B: 0
Register C: 0
Program: 0,3,5,4,3,0`

func TestSolve(t *testing.T) {
tests := []struct {
input string
answer uint64
}{
{testInput, 117440},
}

if testing.Verbose() {
utils.Verbose = true
}

for _, test := range tests {
r := strings.NewReader(test.input)

result := Solve(r).(uint64)

if result != test.answer {
t.Errorf("Expected %d, got %d", test.answer, result)
}
}
}
36 changes: 36 additions & 0 deletions utils/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,39 @@ func Atoi(s string) int {

return result
}

func UIntsToStrings(uints []uint64) []string {
result := make([]string, len(uints))
for i, val := range uints {
result[i] = strconv.FormatUint(val, 10)
}

return result
}

func IntsToStrings(ints []int) []string {
result := make([]string, len(ints))
for i, val := range ints {
result[i] = strconv.Itoa(val)
}

return result
}

func StringsToInts(strings []string) []int {
result := make([]int, len(strings))
for i, str := range strings {
result[i] = Atoi(str)
}

return result
}

func StringsToUInts(strings []string) []uint64 {
result := make([]uint64, len(strings))
for i, str := range strings {
result[i], _ = strconv.ParseUint(str, 10, 64)
}

return result
}

0 comments on commit 6160a0b

Please sign in to comment.