Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
7c4033a8d1
|
|||
060cfeb610
|
|||
46cb381e8d
|
|||
b29ea5d936
|
|||
20a7e892ab
|
|||
e289bd9f54
|
|||
dd5af1f2cc
|
|||
0b3cdc2331
|
|||
2d6150e318
|
|||
1784ab77c8
|
|||
9a4fb7c734
|
|||
52737dd7c3
|
28
days/02.go
28
days/02.go
@ -18,19 +18,20 @@ func (d Day02) Num() int {
|
||||
return 2
|
||||
}
|
||||
|
||||
func (d *Day02) getProgramWithParams(param1, param2 int64) utilities.IntcodeProgram {
|
||||
program := make(utilities.IntcodeProgram, len(d.program))
|
||||
copy(program, d.program)
|
||||
program[1] = param1
|
||||
program[2] = param2
|
||||
return program
|
||||
func (d *Day02) setParams(param1, param2 int64) {
|
||||
d.program.Reset()
|
||||
d.program.SetMemory(1, param1)
|
||||
d.program.SetMemory(2, param2)
|
||||
}
|
||||
|
||||
func (d *Day02) Part1() string {
|
||||
program := d.getProgramWithParams(12, 2)
|
||||
program.Run()
|
||||
d.setParams(12, 2)
|
||||
d.program.Run()
|
||||
|
||||
return fmt.Sprintf("Position 0 = %s%d%s", utilities.TextBold, program[0], utilities.TextReset)
|
||||
if d.program.GetMemory(0) != 4138658 {
|
||||
panic("")
|
||||
}
|
||||
return fmt.Sprintf("Position 0 = %s%d%s", utilities.TextBold, d.program.GetMemory(0), utilities.TextReset)
|
||||
}
|
||||
|
||||
func (d *Day02) Part2() string {
|
||||
@ -41,10 +42,10 @@ func (d *Day02) Part2() string {
|
||||
found := false
|
||||
for noun = 0; noun <= 99; noun++ {
|
||||
for verb = 0; verb <= 99; verb++ {
|
||||
program := d.getProgramWithParams(noun, verb)
|
||||
program.Run()
|
||||
d.setParams(noun, verb)
|
||||
d.program.Run()
|
||||
|
||||
if program[0] == sentinel {
|
||||
if d.program.GetMemory(0) == sentinel {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
@ -58,6 +59,9 @@ func (d *Day02) Part2() string {
|
||||
if !found {
|
||||
panic("!found")
|
||||
}
|
||||
if noun != 72 || verb != 64 {
|
||||
panic("")
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%d created by noun=%d, verb=%d. 100 * noun + verb = %s%d%s",
|
||||
sentinel,
|
||||
|
99
days/03.go
99
days/03.go
@ -6,29 +6,24 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"parnic.com/aoc2019/utilities"
|
||||
u "parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type Pair[T, U any] struct {
|
||||
a T
|
||||
b U
|
||||
}
|
||||
|
||||
type Day03 struct {
|
||||
line1 []Pair[byte, int]
|
||||
line2 []Pair[byte, int]
|
||||
visited map[Pair[int, int]]int
|
||||
overlaps []Pair[Pair[int, int], int]
|
||||
line1 []u.Pair[byte, int]
|
||||
line2 []u.Pair[byte, int]
|
||||
visited map[u.Pair[int, int]]int
|
||||
overlaps []u.Pair[u.Pair[int, int], int]
|
||||
}
|
||||
|
||||
func (d *Day03) Parse() {
|
||||
lines := utilities.GetStringLines("03p")
|
||||
lines := u.GetStringLines("03p")
|
||||
|
||||
line1data := strings.Split(lines[0], ",")
|
||||
line2data := strings.Split(lines[1], ",")
|
||||
|
||||
d.line1 = make([]Pair[byte, int], len(line1data))
|
||||
d.line2 = make([]Pair[byte, int], len(line2data))
|
||||
d.line1 = make([]u.Pair[byte, int], len(line1data))
|
||||
d.line2 = make([]u.Pair[byte, int], len(line2data))
|
||||
|
||||
for idx, instr := range line1data {
|
||||
dir := instr[0]
|
||||
@ -38,7 +33,7 @@ func (d *Day03) Parse() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
d.line1[idx] = Pair[byte, int]{a: dir, b: iAmt}
|
||||
d.line1[idx] = u.Pair[byte, int]{First: dir, Second: iAmt}
|
||||
}
|
||||
|
||||
for idx, instr := range line2data {
|
||||
@ -49,7 +44,7 @@ func (d *Day03) Parse() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
d.line2[idx] = Pair[byte, int]{a: dir, b: iAmt}
|
||||
d.line2[idx] = u.Pair[byte, int]{First: dir, Second: iAmt}
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,96 +53,96 @@ func (d Day03) Num() int {
|
||||
}
|
||||
|
||||
func (d *Day03) Part1() string {
|
||||
d.visited = make(map[Pair[int, int]]int)
|
||||
d.visited = make(map[u.Pair[int, int]]int)
|
||||
var x int
|
||||
var y int
|
||||
var steps int
|
||||
for _, inst := range d.line1 {
|
||||
switch inst.a {
|
||||
switch inst.First {
|
||||
case 'R':
|
||||
for i := 1; i <= inst.b; i++ {
|
||||
for i := 1; i <= inst.Second; i++ {
|
||||
steps++
|
||||
d.visited[Pair[int, int]{a: x + i, b: y}] = steps
|
||||
d.visited[u.Pair[int, int]{First: x + i, Second: y}] = steps
|
||||
}
|
||||
x += inst.b
|
||||
x += inst.Second
|
||||
case 'U':
|
||||
for i := 1; i <= inst.b; i++ {
|
||||
for i := 1; i <= inst.Second; i++ {
|
||||
steps++
|
||||
d.visited[Pair[int, int]{a: x, b: y + i}] = steps
|
||||
d.visited[u.Pair[int, int]{First: x, Second: y + i}] = steps
|
||||
}
|
||||
y += inst.b
|
||||
y += inst.Second
|
||||
case 'L':
|
||||
for i := 1; i <= inst.b; i++ {
|
||||
for i := 1; i <= inst.Second; i++ {
|
||||
steps++
|
||||
d.visited[Pair[int, int]{a: x - i, b: y}] = steps
|
||||
d.visited[u.Pair[int, int]{First: x - i, Second: y}] = steps
|
||||
}
|
||||
x -= inst.b
|
||||
x -= inst.Second
|
||||
case 'D':
|
||||
for i := 1; i <= inst.b; i++ {
|
||||
for i := 1; i <= inst.Second; i++ {
|
||||
steps++
|
||||
d.visited[Pair[int, int]{a: x, b: y - i}] = steps
|
||||
d.visited[u.Pair[int, int]{First: x, Second: y - i}] = steps
|
||||
}
|
||||
y -= inst.b
|
||||
y -= inst.Second
|
||||
}
|
||||
}
|
||||
|
||||
x = 0
|
||||
y = 0
|
||||
steps = 0
|
||||
d.overlaps = make([]Pair[Pair[int, int], int], 0)
|
||||
d.overlaps = make([]u.Pair[u.Pair[int, int], int], 0)
|
||||
for _, inst := range d.line2 {
|
||||
switch inst.a {
|
||||
switch inst.First {
|
||||
case 'R':
|
||||
for i := 1; i <= inst.b; i++ {
|
||||
for i := 1; i <= inst.Second; i++ {
|
||||
steps++
|
||||
if _, exists := d.visited[Pair[int, int]{x + i, y}]; exists {
|
||||
d.overlaps = append(d.overlaps, Pair[Pair[int, int], int]{a: Pair[int, int]{x + i, y}, b: steps})
|
||||
if _, exists := d.visited[u.Pair[int, int]{First: x + i, Second: y}]; exists {
|
||||
d.overlaps = append(d.overlaps, u.Pair[u.Pair[int, int], int]{First: u.Pair[int, int]{First: x + i, Second: y}, Second: steps})
|
||||
}
|
||||
}
|
||||
x += inst.b
|
||||
x += inst.Second
|
||||
case 'U':
|
||||
for i := 1; i <= inst.b; i++ {
|
||||
for i := 1; i <= inst.Second; i++ {
|
||||
steps++
|
||||
if _, exists := d.visited[Pair[int, int]{x, y + i}]; exists {
|
||||
d.overlaps = append(d.overlaps, Pair[Pair[int, int], int]{a: Pair[int, int]{x, y + i}, b: steps})
|
||||
if _, exists := d.visited[u.Pair[int, int]{First: x, Second: y + i}]; exists {
|
||||
d.overlaps = append(d.overlaps, u.Pair[u.Pair[int, int], int]{First: u.Pair[int, int]{First: x, Second: y + i}, Second: steps})
|
||||
}
|
||||
}
|
||||
y += inst.b
|
||||
y += inst.Second
|
||||
case 'L':
|
||||
for i := 1; i <= inst.b; i++ {
|
||||
for i := 1; i <= inst.Second; i++ {
|
||||
steps++
|
||||
if _, exists := d.visited[Pair[int, int]{x - i, y}]; exists {
|
||||
d.overlaps = append(d.overlaps, Pair[Pair[int, int], int]{a: Pair[int, int]{x - i, y}, b: steps})
|
||||
if _, exists := d.visited[u.Pair[int, int]{First: x - i, Second: y}]; exists {
|
||||
d.overlaps = append(d.overlaps, u.Pair[u.Pair[int, int], int]{First: u.Pair[int, int]{First: x - i, Second: y}, Second: steps})
|
||||
}
|
||||
}
|
||||
x -= inst.b
|
||||
x -= inst.Second
|
||||
case 'D':
|
||||
for i := 1; i <= inst.b; i++ {
|
||||
for i := 1; i <= inst.Second; i++ {
|
||||
steps++
|
||||
if _, exists := d.visited[Pair[int, int]{x, y - i}]; exists {
|
||||
d.overlaps = append(d.overlaps, Pair[Pair[int, int], int]{a: Pair[int, int]{x, y - i}, b: steps})
|
||||
if _, exists := d.visited[u.Pair[int, int]{First: x, Second: y - i}]; exists {
|
||||
d.overlaps = append(d.overlaps, u.Pair[u.Pair[int, int], int]{First: u.Pair[int, int]{First: x, Second: y - i}, Second: steps})
|
||||
}
|
||||
}
|
||||
y -= inst.b
|
||||
y -= inst.Second
|
||||
}
|
||||
}
|
||||
|
||||
minDist := math.MaxInt
|
||||
for _, overlap := range d.overlaps {
|
||||
dist := int(math.Abs(float64(overlap.a.a))) + int(math.Abs(float64(overlap.a.b)))
|
||||
dist := int(math.Abs(float64(overlap.First.First))) + int(math.Abs(float64(overlap.First.Second)))
|
||||
if dist < minDist {
|
||||
minDist = dist
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Closest overlap manhattan distance = %s%d%s", utilities.TextBold, minDist, utilities.TextReset)
|
||||
return fmt.Sprintf("Closest overlap manhattan distance = %s%d%s", u.TextBold, minDist, u.TextReset)
|
||||
}
|
||||
|
||||
func (d *Day03) Part2() string {
|
||||
minOverlap := math.MaxInt
|
||||
for _, overlap := range d.overlaps {
|
||||
line1Steps := d.visited[overlap.a]
|
||||
line2Steps := overlap.b
|
||||
line1Steps := d.visited[overlap.First]
|
||||
line2Steps := overlap.Second
|
||||
|
||||
totalSteps := line1Steps + line2Steps
|
||||
if totalSteps < minOverlap {
|
||||
@ -155,5 +150,5 @@ func (d *Day03) Part2() string {
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Minimum steps to overlap = %s%d%s", utilities.TextBold, minOverlap, utilities.TextReset)
|
||||
return fmt.Sprintf("Minimum steps to overlap = %s%d%s", u.TextBold, minOverlap, u.TextReset)
|
||||
}
|
||||
|
188
days/05.go
Normal file
188
days/05.go
Normal file
@ -0,0 +1,188 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type Day05 struct {
|
||||
program utilities.IntcodeProgram
|
||||
}
|
||||
|
||||
func (d *Day05) Parse() {
|
||||
d.program = utilities.LoadIntcodeProgram("05p")
|
||||
d.test()
|
||||
}
|
||||
|
||||
func (d Day05) Num() int {
|
||||
return 5
|
||||
}
|
||||
|
||||
func (d Day05) test() {
|
||||
// Using position mode, consider whether the input is equal to 8; output 1 (if it is) or 0 (if it is not).
|
||||
program := utilities.ParseIntcodeProgram("3,9,8,9,10,9,4,9,99,-1,8")
|
||||
program.RunIn(func(int) int64 {
|
||||
return 0
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 0 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
program.Reset()
|
||||
program.RunIn(func(int) int64 {
|
||||
return 8
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 1 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
|
||||
// Using position mode, consider whether the input is less than 8; output 1 (if it is) or 0 (if it is not).
|
||||
program = utilities.ParseIntcodeProgram("3,9,7,9,10,9,4,9,99,-1,8")
|
||||
program.RunIn(func(int) int64 {
|
||||
return 0
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 1 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
program.Reset()
|
||||
program.RunIn(func(int) int64 {
|
||||
return 8
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 0 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
|
||||
// Using immediate mode, consider whether the input is equal to 8; output 1 (if it is) or 0 (if it is not).
|
||||
program = utilities.ParseIntcodeProgram("3,3,1108,-1,8,3,4,3,99")
|
||||
program.RunIn(func(int) int64 {
|
||||
return 0
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 0 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
program.Reset()
|
||||
program.RunIn(func(int) int64 {
|
||||
return 8
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 1 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
|
||||
// Using immediate mode, consider whether the input is less than 8; output 1 (if it is) or 0 (if it is not).
|
||||
program = utilities.ParseIntcodeProgram("3,3,1107,-1,8,3,4,3,99")
|
||||
program.RunIn(func(int) int64 {
|
||||
return 0
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 1 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
program.Reset()
|
||||
program.RunIn(func(int) int64 {
|
||||
return 8
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 0 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
|
||||
// jump tests that take an input, then output 0 if the input was zero or 1 if the input was non-zero
|
||||
// position mode
|
||||
program = utilities.ParseIntcodeProgram("3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9")
|
||||
program.RunIn(func(int) int64 {
|
||||
return 0
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 0 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
program.Reset()
|
||||
program.RunIn(func(int) int64 {
|
||||
return 8
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 1 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
|
||||
// jump tests that take an input, then output 0 if the input was zero or 1 if the input was non-zero
|
||||
// immediate mode
|
||||
program = utilities.ParseIntcodeProgram("3,3,1105,-1,9,1101,0,0,12,4,12,99,1")
|
||||
program.RunIn(func(int) int64 {
|
||||
return 0
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 0 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
program.Reset()
|
||||
program.RunIn(func(int) int64 {
|
||||
return 8
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 1 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
|
||||
// uses an input instruction to ask for a single number. The program will then output 999 if the input value is below 8, output 1000 if the input value is equal to 8, or output 1001 if the input value is greater than 8.
|
||||
program = utilities.ParseIntcodeProgram("3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99")
|
||||
program.RunIn(func(int) int64 {
|
||||
return 0
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 999 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
program.Reset()
|
||||
program.RunIn(func(int) int64 {
|
||||
return 8
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 1000 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
program.Reset()
|
||||
program.RunIn(func(int) int64 {
|
||||
return 9
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if val != 1001 {
|
||||
panic("")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (d *Day05) Part1() string {
|
||||
diagCode := int64(-1)
|
||||
d.program.RunIn(func(int) int64 {
|
||||
return 1
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if state.IsHalting() {
|
||||
diagCode = val
|
||||
} else if val != 0 {
|
||||
panic("test failed")
|
||||
}
|
||||
})
|
||||
|
||||
return fmt.Sprintf("Diagnostic code: %d", diagCode)
|
||||
}
|
||||
|
||||
func (d *Day05) Part2() string {
|
||||
d.program.Reset()
|
||||
diagCode := int64(-1)
|
||||
d.program.RunIn(func(int) int64 {
|
||||
return 5
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
if !state.IsHalting() {
|
||||
panic("unexpected output received")
|
||||
}
|
||||
diagCode = val
|
||||
})
|
||||
|
||||
return fmt.Sprintf("Diagnostic code: %d", diagCode)
|
||||
}
|
114
days/06.go
Normal file
114
days/06.go
Normal file
@ -0,0 +1,114 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type body struct {
|
||||
orbits *body
|
||||
obj string
|
||||
}
|
||||
|
||||
type Day06 struct {
|
||||
allBodies []*body
|
||||
}
|
||||
|
||||
func (d *Day06) Parse() {
|
||||
d.allBodies = make([]*body, 0)
|
||||
|
||||
getOrAddBody := func(obj string) *body {
|
||||
target := d.findBody(obj)
|
||||
if target == nil {
|
||||
target = &body{
|
||||
obj: obj,
|
||||
}
|
||||
d.allBodies = append(d.allBodies, target)
|
||||
}
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
lines := utilities.GetStringLines("06p")
|
||||
for _, line := range lines {
|
||||
bodies := strings.Split(line, ")")
|
||||
newBody := getOrAddBody(bodies[1])
|
||||
|
||||
target := getOrAddBody(bodies[0])
|
||||
newBody.orbits = target
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Day06) findBody(obj string) *body {
|
||||
for _, checkBody := range d.allBodies {
|
||||
if checkBody.obj == obj {
|
||||
return checkBody
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d Day06) Num() int {
|
||||
return 6
|
||||
}
|
||||
|
||||
func (d *Day06) Part1() string {
|
||||
orbits := 0
|
||||
for _, obj := range d.allBodies {
|
||||
next := obj.orbits
|
||||
for next != nil {
|
||||
next = next.orbits
|
||||
orbits++
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Total orbits: %s%d%s", utilities.TextBold, orbits, utilities.TextReset)
|
||||
}
|
||||
|
||||
func (d *Day06) Part2() string {
|
||||
you := d.findBody("YOU")
|
||||
san := d.findBody("SAN")
|
||||
|
||||
youChildren := make([]*body, 0)
|
||||
next := you.orbits
|
||||
for next != nil {
|
||||
youChildren = append(youChildren, next)
|
||||
next = next.orbits
|
||||
}
|
||||
|
||||
var linkingNode *body
|
||||
next = san.orbits
|
||||
for next != nil {
|
||||
if utilities.ArrayContains(youChildren, next) {
|
||||
linkingNode = next
|
||||
break
|
||||
}
|
||||
next = next.orbits
|
||||
}
|
||||
|
||||
if linkingNode == nil {
|
||||
panic("")
|
||||
}
|
||||
|
||||
getDistToLinking := func(start *body) int {
|
||||
dist := 0
|
||||
next = start.orbits
|
||||
for next != nil {
|
||||
if next == linkingNode {
|
||||
break
|
||||
}
|
||||
dist++
|
||||
next = next.orbits
|
||||
}
|
||||
|
||||
return dist
|
||||
}
|
||||
|
||||
distYouToLinking := getDistToLinking(you)
|
||||
distSanToLinking := getDistToLinking(san)
|
||||
|
||||
return fmt.Sprintf("Transfers to get to Santa: %s%d%s", utilities.TextBold, distYouToLinking+distSanToLinking, utilities.TextReset)
|
||||
}
|
116
days/07.go
Normal file
116
days/07.go
Normal file
@ -0,0 +1,116 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type Day07 struct {
|
||||
program utilities.IntcodeProgram
|
||||
amps []utilities.IntcodeProgram
|
||||
}
|
||||
|
||||
func (d *Day07) Parse() {
|
||||
d.program = utilities.LoadIntcodeProgram("07p")
|
||||
d.amps = make([]utilities.IntcodeProgram, 5)
|
||||
for i := range d.amps {
|
||||
d.amps[i] = d.program.Copy()
|
||||
}
|
||||
}
|
||||
|
||||
func (d Day07) Num() int {
|
||||
return 7
|
||||
}
|
||||
|
||||
func (d *Day07) Part1() string {
|
||||
var highestVal int64
|
||||
var highestSequence []int64
|
||||
|
||||
allSequences := utilities.GetPermutations([]int64{0, 1, 2, 3, 4})
|
||||
for _, sequence := range allSequences {
|
||||
if len(sequence) != len(d.amps) {
|
||||
panic("input sequence does not match up to number of amplifiers")
|
||||
}
|
||||
|
||||
input := int64(0)
|
||||
var output int64
|
||||
for i, amp := range d.amps {
|
||||
amp.RunIn(func(step int) int64 {
|
||||
if step == 1 {
|
||||
return sequence[i]
|
||||
} else if step == 2 {
|
||||
return input
|
||||
}
|
||||
|
||||
panic("hit more input instructions than expected")
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
output = val
|
||||
})
|
||||
|
||||
input = output
|
||||
}
|
||||
|
||||
if output > highestVal {
|
||||
highestVal = output
|
||||
if highestSequence == nil {
|
||||
highestSequence = make([]int64, len(sequence))
|
||||
}
|
||||
copy(highestSequence, sequence)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Max thruster signal: %s%d%s (produced by %v)", utilities.TextBold, highestVal, utilities.TextReset, highestSequence)
|
||||
}
|
||||
|
||||
func (d *Day07) Part2() string {
|
||||
var highestVal int64
|
||||
var highestSequence []int64
|
||||
|
||||
allSequences := utilities.GetPermutations([]int64{5, 6, 7, 8, 9})
|
||||
for _, sequence := range allSequences {
|
||||
if len(sequence) != len(d.amps) {
|
||||
panic("input sequence does not match up to number of amplifiers")
|
||||
}
|
||||
|
||||
inputs := make([]chan int64, len(d.amps))
|
||||
for i := range d.amps {
|
||||
d.amps[i].Reset()
|
||||
inputs[i] = make(chan int64, 1)
|
||||
inputs[i] <- sequence[i]
|
||||
}
|
||||
|
||||
var finalOutput int64
|
||||
var wg sync.WaitGroup
|
||||
for i := range d.amps {
|
||||
wg.Add(1)
|
||||
go func(idx int) {
|
||||
d.amps[idx].RunIn(func(step int) int64 {
|
||||
input := <-inputs[idx]
|
||||
return input
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
finalOutput = val
|
||||
inputIdx := idx + 1
|
||||
if inputIdx == len(inputs) {
|
||||
inputIdx = 0
|
||||
}
|
||||
inputs[inputIdx] <- val
|
||||
})
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
inputs[0] <- 0
|
||||
wg.Wait()
|
||||
|
||||
if finalOutput > highestVal {
|
||||
highestVal = finalOutput
|
||||
if highestSequence == nil {
|
||||
highestSequence = make([]int64, len(sequence))
|
||||
}
|
||||
copy(highestSequence, sequence)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Max thruster signal: %s%d%s (produced by %v)", utilities.TextBold, highestVal, utilities.TextReset, highestSequence)
|
||||
}
|
100
days/08.go
Normal file
100
days/08.go
Normal file
@ -0,0 +1,100 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type Day08 struct {
|
||||
img [][]int
|
||||
}
|
||||
|
||||
const (
|
||||
imgWidth = 25
|
||||
imgHeight = 6
|
||||
)
|
||||
|
||||
func (d *Day08) Parse() {
|
||||
contents := utilities.GetStringContents("08p")
|
||||
imgSize := imgWidth * imgHeight
|
||||
layers := len(contents) / imgSize
|
||||
d.img = make([][]int, layers)
|
||||
for layer := 0; layer < layers; layer++ {
|
||||
d.img[layer] = make([]int, imgSize)
|
||||
for i := 0; i < imgSize; i++ {
|
||||
d.img[layer][i] = int(contents[(layer*imgSize)+i] - '0')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d Day08) Num() int {
|
||||
return 8
|
||||
}
|
||||
|
||||
func (d *Day08) Part1() string {
|
||||
fewestZeroes := math.MaxInt
|
||||
var layerFewestZeroes int
|
||||
for layer := range d.img {
|
||||
zeroes := 0
|
||||
for i := range d.img[layer] {
|
||||
if d.img[layer][i] == 0 {
|
||||
zeroes++
|
||||
}
|
||||
}
|
||||
|
||||
if zeroes < fewestZeroes {
|
||||
fewestZeroes = zeroes
|
||||
layerFewestZeroes = layer
|
||||
}
|
||||
}
|
||||
|
||||
numOne := 0
|
||||
numTwo := 0
|
||||
for i := range d.img[layerFewestZeroes] {
|
||||
if d.img[layerFewestZeroes][i] == 1 {
|
||||
numOne++
|
||||
} else if d.img[layerFewestZeroes][i] == 2 {
|
||||
numTwo++
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Fewest zeroes on layer %d, #1s * #2s = %d * %d = %s%d%s",
|
||||
layerFewestZeroes,
|
||||
numOne,
|
||||
numTwo,
|
||||
utilities.TextBold,
|
||||
numOne*numTwo,
|
||||
utilities.TextReset,
|
||||
)
|
||||
}
|
||||
|
||||
func (d *Day08) Part2() string {
|
||||
imgSize := imgWidth * imgHeight
|
||||
finalImg := make([]int, imgSize)
|
||||
for i := 0; i < imgSize; i++ {
|
||||
for layer := 0; layer < len(d.img); layer++ {
|
||||
if d.img[layer][i] != 2 {
|
||||
finalImg[i] = d.img[layer][i]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outStr := strings.Builder{}
|
||||
outStr.WriteRune('\n')
|
||||
for y := 0; y < imgHeight; y++ {
|
||||
for x := 0; x < imgWidth; x++ {
|
||||
if finalImg[(y*imgWidth)+x] == 0 {
|
||||
outStr.WriteRune(' ')
|
||||
} else {
|
||||
outStr.WriteRune('█')
|
||||
}
|
||||
}
|
||||
outStr.WriteRune('\n')
|
||||
}
|
||||
|
||||
return outStr.String()
|
||||
}
|
42
days/09.go
Normal file
42
days/09.go
Normal file
@ -0,0 +1,42 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type Day09 struct {
|
||||
program utilities.IntcodeProgram
|
||||
}
|
||||
|
||||
func (d *Day09) Parse() {
|
||||
d.program = utilities.LoadIntcodeProgram("09p")
|
||||
}
|
||||
|
||||
func (d Day09) Num() int {
|
||||
return 9
|
||||
}
|
||||
|
||||
func (d *Day09) Part1() string {
|
||||
var code int64
|
||||
d.program.RunIn(func(inputStep int) int64 {
|
||||
return 1
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
code = val
|
||||
})
|
||||
|
||||
return fmt.Sprintf("BOOST keycode: %s%d%s", utilities.TextBold, code, utilities.TextReset)
|
||||
}
|
||||
|
||||
func (d *Day09) Part2() string {
|
||||
var coordinates int64
|
||||
d.program.Reset()
|
||||
d.program.RunIn(func(inputStep int) int64 {
|
||||
return 2
|
||||
}, func(val int64, state utilities.IntcodeProgramState) {
|
||||
coordinates = val
|
||||
})
|
||||
|
||||
return fmt.Sprintf("Coordinates: %s%d%s", utilities.TextBold, coordinates, utilities.TextReset)
|
||||
}
|
171
days/10.go
Normal file
171
days/10.go
Normal file
@ -0,0 +1,171 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
u "parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type Day10 struct {
|
||||
asteroids [][]bool
|
||||
idealLocation u.Vec2[int]
|
||||
}
|
||||
|
||||
func (d *Day10) Parse() {
|
||||
lines := u.GetStringLines("10p")
|
||||
d.asteroids = make([][]bool, len(lines))
|
||||
for i, line := range lines {
|
||||
d.asteroids[i] = make([]bool, len(line))
|
||||
for j, ch := range line {
|
||||
d.asteroids[i][j] = ch == '#'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d Day10) Num() int {
|
||||
return 10
|
||||
}
|
||||
|
||||
// func (d Day10) draw() {
|
||||
// for i := range d.asteroids {
|
||||
// for j := range d.asteroids[i] {
|
||||
// if !d.asteroids[i][j].First {
|
||||
// fmt.Print(".")
|
||||
// } else {
|
||||
// num := d.asteroids[i][j].Second
|
||||
// ch := rune('0') + rune(num)
|
||||
// if num >= 10 {
|
||||
// ch = '+'
|
||||
// }
|
||||
// fmt.Printf("%c", ch)
|
||||
// }
|
||||
// }
|
||||
// fmt.Println()
|
||||
// }
|
||||
// }
|
||||
|
||||
func (d Day10) getVisibleAsteroids(i1, j1 int) []u.Vec2[int] {
|
||||
visited := make([]u.Vec2[int], 0)
|
||||
foundAsteroids := make([]u.Vec2[int], 0)
|
||||
|
||||
findNext := func(startX, startY, incX, incY int) *u.Vec2[int] {
|
||||
var found *u.Vec2[int]
|
||||
if incX == 0 && incY == 0 {
|
||||
return found
|
||||
}
|
||||
|
||||
x := startX + incX
|
||||
y := startY + incY
|
||||
for x < len(d.asteroids) && x >= 0 && y < len(d.asteroids[x]) && y >= 0 {
|
||||
currPair := u.Vec2[int]{X: x, Y: y}
|
||||
if !u.ArrayContains(visited, currPair) {
|
||||
visited = append(visited, currPair)
|
||||
|
||||
if d.asteroids[x][y] {
|
||||
if found == nil {
|
||||
found = &currPair
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x += incX
|
||||
y += incY
|
||||
}
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
for incX := 0; ; {
|
||||
plusXValid := i1+incX < len(d.asteroids)
|
||||
minusXValid := i1-incX >= 0
|
||||
if !plusXValid && !minusXValid {
|
||||
break
|
||||
}
|
||||
|
||||
for incY := 0; ; {
|
||||
plusYValid := j1+incY < len(d.asteroids[0])
|
||||
minusYValid := j1-incY >= 0
|
||||
if !plusYValid && !minusYValid {
|
||||
break
|
||||
}
|
||||
|
||||
if found := findNext(i1, j1, incX, incY); found != nil {
|
||||
foundAsteroids = append(foundAsteroids, *found)
|
||||
}
|
||||
if found := findNext(i1, j1, incX, -incY); found != nil {
|
||||
foundAsteroids = append(foundAsteroids, *found)
|
||||
}
|
||||
if found := findNext(i1, j1, -incX, incY); found != nil {
|
||||
foundAsteroids = append(foundAsteroids, *found)
|
||||
}
|
||||
if found := findNext(i1, j1, -incX, -incY); found != nil {
|
||||
foundAsteroids = append(foundAsteroids, *found)
|
||||
}
|
||||
|
||||
incY++
|
||||
}
|
||||
|
||||
incX++
|
||||
}
|
||||
|
||||
return foundAsteroids
|
||||
}
|
||||
|
||||
func (d Day10) numVisibleAsteroids(i1, j1 int) int {
|
||||
return len(d.getVisibleAsteroids(i1, j1))
|
||||
}
|
||||
|
||||
func (d *Day10) removeAsteroids(locs ...u.Vec2[int]) {
|
||||
for _, loc := range locs {
|
||||
if !d.asteroids[loc.X][loc.Y] {
|
||||
panic("tried to remove non-asteroid")
|
||||
}
|
||||
|
||||
d.asteroids[loc.X][loc.Y] = false
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Day10) Part1() string {
|
||||
mostAsteroids := 0
|
||||
for i := range d.asteroids {
|
||||
for j := range d.asteroids[i] {
|
||||
if d.asteroids[i][j] {
|
||||
numVisible := d.numVisibleAsteroids(i, j)
|
||||
if numVisible > mostAsteroids {
|
||||
mostAsteroids = numVisible
|
||||
d.idealLocation = u.Vec2[int]{X: i, Y: j}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Most visible asteroids: %s%d%s at (%d,%d)", u.TextBold, mostAsteroids, u.TextReset, d.idealLocation.Y, d.idealLocation.X)
|
||||
}
|
||||
|
||||
func (d *Day10) Part2() string {
|
||||
findNumVaporized := 200
|
||||
var targetLocation u.Vec2[int]
|
||||
|
||||
vaporized := 0
|
||||
for vaporized < findNumVaporized {
|
||||
visibleAsteroids := d.getVisibleAsteroids(d.idealLocation.X, d.idealLocation.Y)
|
||||
if len(visibleAsteroids) == 0 {
|
||||
panic("no more asteroids to vaporize")
|
||||
}
|
||||
|
||||
if vaporized+len(visibleAsteroids) < findNumVaporized {
|
||||
vaporized += len(visibleAsteroids)
|
||||
d.removeAsteroids(visibleAsteroids...)
|
||||
continue
|
||||
}
|
||||
|
||||
sort.Slice(visibleAsteroids, func(i, j int) bool {
|
||||
return d.idealLocation.AngleBetween(visibleAsteroids[i]) > d.idealLocation.AngleBetween(visibleAsteroids[j])
|
||||
})
|
||||
targetLocation = visibleAsteroids[findNumVaporized-1-vaporized]
|
||||
break
|
||||
}
|
||||
|
||||
return fmt.Sprintf("#%d asteroid to be vaporized is at (%d,%d), transformed: %s%d%s", findNumVaporized, targetLocation.Y, targetLocation.X, u.TextBold, (targetLocation.Y*100)+targetLocation.X, u.TextReset)
|
||||
}
|
116
days/11.go
Normal file
116
days/11.go
Normal file
@ -0,0 +1,116 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
u "parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type Day11 struct {
|
||||
program u.IntcodeProgram
|
||||
painted map[u.Pair[int, int]]int
|
||||
}
|
||||
|
||||
func (d *Day11) Parse() {
|
||||
d.program = u.LoadIntcodeProgram("11p")
|
||||
}
|
||||
|
||||
func (d Day11) Num() int {
|
||||
return 11
|
||||
}
|
||||
|
||||
func (d *Day11) paintHull() (int, u.Pair[int, int], u.Pair[int, int]) {
|
||||
pos := u.Pair[int, int]{First: 0, Second: 0}
|
||||
facing := 0
|
||||
|
||||
min := pos
|
||||
max := pos
|
||||
|
||||
outputState := 0
|
||||
numPainted := 1
|
||||
d.program.RunIn(func(inputStep int) int64 {
|
||||
return int64(d.painted[pos])
|
||||
}, func(val int64, state u.IntcodeProgramState) {
|
||||
if outputState == 0 {
|
||||
outputState++
|
||||
color := int(val)
|
||||
if _, exists := d.painted[pos]; !exists {
|
||||
numPainted++
|
||||
}
|
||||
d.painted[pos] = color
|
||||
} else {
|
||||
outputState = 0
|
||||
direction := val
|
||||
|
||||
if direction == 0 {
|
||||
facing--
|
||||
if facing == -1 {
|
||||
facing = 3
|
||||
}
|
||||
} else {
|
||||
facing++
|
||||
if facing == 4 {
|
||||
facing = 0
|
||||
}
|
||||
}
|
||||
|
||||
switch facing {
|
||||
case 0:
|
||||
pos.First--
|
||||
if pos.First < min.First {
|
||||
min.First = pos.First
|
||||
}
|
||||
case 1:
|
||||
pos.Second++
|
||||
if pos.Second > max.Second {
|
||||
max.Second = pos.Second
|
||||
}
|
||||
case 2:
|
||||
pos.First++
|
||||
if pos.First > max.First {
|
||||
max.First = pos.First
|
||||
}
|
||||
case 3:
|
||||
pos.Second--
|
||||
if pos.Second < min.Second {
|
||||
min.Second = pos.Second
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return numPainted, min, max
|
||||
}
|
||||
|
||||
func (d *Day11) Part1() string {
|
||||
d.painted = map[u.Pair[int, int]]int{
|
||||
{First: 0, Second: 0}: 0,
|
||||
}
|
||||
numPainted, _, _ := d.paintHull()
|
||||
|
||||
return fmt.Sprintf("Unique panels painted: %s%d%s", u.TextBold, numPainted, u.TextReset)
|
||||
}
|
||||
|
||||
func (d *Day11) Part2() string {
|
||||
d.painted = map[u.Pair[int, int]]int{
|
||||
{First: 0, Second: 0}: 1,
|
||||
}
|
||||
_, min, max := d.paintHull()
|
||||
|
||||
outStr := strings.Builder{}
|
||||
outStr.WriteRune('\n')
|
||||
for x := min.First; x <= max.First; x++ {
|
||||
for y := min.Second; y <= max.Second; y++ {
|
||||
val, exists := d.painted[u.Pair[int, int]{First: x, Second: y}]
|
||||
if exists && val == 1 {
|
||||
outStr.WriteRune('█')
|
||||
} else {
|
||||
outStr.WriteRune(' ')
|
||||
}
|
||||
}
|
||||
outStr.WriteRune('\n')
|
||||
}
|
||||
|
||||
return outStr.String()
|
||||
}
|
156
days/12.go
Normal file
156
days/12.go
Normal file
@ -0,0 +1,156 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
u "parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type moonData struct {
|
||||
pos u.Vec3[int]
|
||||
vel u.Vec3[int]
|
||||
}
|
||||
|
||||
func (m *moonData) applyGravity(other *moonData) {
|
||||
applyGravityAxis := func(pos1, pos2, vel1, vel2 *int) {
|
||||
if *pos1 < *pos2 {
|
||||
*vel1++
|
||||
*vel2--
|
||||
} else if *pos1 > *pos2 {
|
||||
*vel1--
|
||||
*vel2++
|
||||
}
|
||||
}
|
||||
|
||||
applyGravityAxis(&m.pos.X, &other.pos.X, &m.vel.X, &other.vel.X)
|
||||
applyGravityAxis(&m.pos.Y, &other.pos.Y, &m.vel.Y, &other.vel.Y)
|
||||
applyGravityAxis(&m.pos.Z, &other.pos.Z, &m.vel.Z, &other.vel.Z)
|
||||
}
|
||||
|
||||
func (m *moonData) applyVelocity() {
|
||||
m.pos.Add(m.vel)
|
||||
}
|
||||
|
||||
func (m moonData) getPotentialEnergy() int {
|
||||
return int(math.Abs(float64(m.pos.X))) +
|
||||
int(math.Abs(float64(m.pos.Y))) +
|
||||
int(math.Abs(float64(m.pos.Z)))
|
||||
}
|
||||
|
||||
func (m moonData) getKineticEnergy() int {
|
||||
return int(math.Abs(float64(m.vel.X))) +
|
||||
int(math.Abs(float64(m.vel.Y))) +
|
||||
int(math.Abs(float64(m.vel.Z)))
|
||||
}
|
||||
|
||||
func (m moonData) getTotalEnergy() int {
|
||||
return m.getPotentialEnergy() * m.getKineticEnergy()
|
||||
}
|
||||
|
||||
type Day12 struct {
|
||||
moons []*moonData
|
||||
}
|
||||
|
||||
func (d *Day12) Parse() {
|
||||
lines := u.GetStringLines("12p")
|
||||
d.moons = make([]*moonData, len(lines))
|
||||
for i, line := range lines {
|
||||
trimmed := line[1 : len(line)-1]
|
||||
vals := strings.Split(trimmed, ", ")
|
||||
x, _ := strconv.Atoi(vals[0][2:])
|
||||
y, _ := strconv.Atoi(vals[1][2:])
|
||||
z, _ := strconv.Atoi(vals[2][2:])
|
||||
d.moons[i] = &moonData{
|
||||
pos: u.Vec3[int]{X: x, Y: y, Z: z},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d Day12) Num() int {
|
||||
return 12
|
||||
}
|
||||
|
||||
func (d Day12) copyMoons() []*moonData {
|
||||
moons := make([]*moonData, len(d.moons))
|
||||
for i, moon := range d.moons {
|
||||
moonCopy := *moon
|
||||
moons[i] = &moonCopy
|
||||
}
|
||||
|
||||
return moons
|
||||
}
|
||||
|
||||
func getAllEnergy(moons ...*moonData) int {
|
||||
energy := 0
|
||||
for _, moon := range moons {
|
||||
energy += moon.getTotalEnergy()
|
||||
}
|
||||
return energy
|
||||
}
|
||||
|
||||
func (d *Day12) Part1() string {
|
||||
moons := d.copyMoons()
|
||||
|
||||
numSteps := 1000
|
||||
|
||||
for i := 0; i < numSteps; i++ {
|
||||
for i, moon1 := range moons {
|
||||
for _, moon2 := range moons[i+1:] {
|
||||
moon1.applyGravity(moon2)
|
||||
}
|
||||
|
||||
moon1.applyVelocity()
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Total energy after %d steps: %s%d%s", numSteps, u.TextBold, getAllEnergy(moons...), u.TextReset)
|
||||
}
|
||||
|
||||
func (d *Day12) Part2() string {
|
||||
moons := d.copyMoons()
|
||||
|
||||
orig := make([]u.Vec3[int], len(moons))
|
||||
for i, moon := range moons {
|
||||
orig[i] = moon.pos
|
||||
}
|
||||
period := u.Vec3[int]{}
|
||||
|
||||
for loops := 0; period.X == 0 || period.Y == 0 || period.Z == 0; loops++ {
|
||||
for i, moon1 := range moons {
|
||||
for _, moon2 := range moons[i+1:] {
|
||||
moon1.applyGravity(moon2)
|
||||
}
|
||||
moon1.applyVelocity()
|
||||
}
|
||||
|
||||
foundX := true
|
||||
foundY := true
|
||||
foundZ := true
|
||||
for i, moon := range moons {
|
||||
if moon.pos.X != orig[i].X || moon.vel.X != 0 {
|
||||
foundX = false
|
||||
}
|
||||
if moon.pos.Y != orig[i].Y || moon.vel.Y != 0 {
|
||||
foundY = false
|
||||
}
|
||||
if moon.pos.Z != orig[i].Z || moon.vel.Z != 0 {
|
||||
foundZ = false
|
||||
}
|
||||
}
|
||||
if foundX && period.X == 0 {
|
||||
period.X = loops + 1
|
||||
}
|
||||
if foundY && period.Y == 0 {
|
||||
period.Y = loops + 1
|
||||
}
|
||||
if foundZ && period.Z == 0 {
|
||||
period.Z = loops + 1
|
||||
}
|
||||
}
|
||||
|
||||
stepsRequired := u.LCM(period.X, period.Y, period.Z)
|
||||
return fmt.Sprintf("Iterations to reach a previous state: %s%d%s", u.TextBold, stepsRequired, u.TextReset)
|
||||
}
|
147
days/13.go
Normal file
147
days/13.go
Normal file
@ -0,0 +1,147 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
u "parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
const (
|
||||
tileEmpty = 0
|
||||
tileWall = 1
|
||||
tileBlock = 2
|
||||
tileHPaddle = 3
|
||||
tileBall = 4
|
||||
)
|
||||
|
||||
type tile struct {
|
||||
pos u.Vec2[int]
|
||||
id int
|
||||
}
|
||||
|
||||
type Day13 struct {
|
||||
program u.IntcodeProgram
|
||||
tiles []tile
|
||||
gameBoard [24][45]int
|
||||
}
|
||||
|
||||
func (d *Day13) Parse() {
|
||||
d.program = u.LoadIntcodeProgram("13p")
|
||||
d.tiles = make([]tile, 0, 1080)
|
||||
}
|
||||
|
||||
func (d Day13) Num() int {
|
||||
return 13
|
||||
}
|
||||
|
||||
func (d Day13) getNumBlocks() int {
|
||||
blockTiles := 0
|
||||
for _, tile := range d.tiles {
|
||||
if tile.id == tileBlock {
|
||||
blockTiles++
|
||||
}
|
||||
}
|
||||
|
||||
return blockTiles
|
||||
}
|
||||
|
||||
// func (d Day13) drawGameBoard() {
|
||||
// s := strings.Builder{}
|
||||
// for x := range d.gameBoard {
|
||||
// for y := range d.gameBoard[x] {
|
||||
// block := d.gameBoard[x][y]
|
||||
// if block == tileBlock {
|
||||
// s.WriteString(u.ColorBlue)
|
||||
// s.WriteRune('█')
|
||||
// s.WriteString(u.TextReset)
|
||||
// } else if block == tileBall {
|
||||
// s.WriteString(u.ColorGreen)
|
||||
// s.WriteRune('█')
|
||||
// s.WriteString(u.TextReset)
|
||||
// } else if block == tileWall {
|
||||
// s.WriteString(u.ColorWhite)
|
||||
// s.WriteRune('█')
|
||||
// s.WriteString(u.TextReset)
|
||||
// } else if block == tileHPaddle {
|
||||
// s.WriteString(u.ColorRed)
|
||||
// s.WriteRune('█')
|
||||
// s.WriteString(u.TextReset)
|
||||
// } else if block == tileEmpty {
|
||||
// s.WriteRune(' ')
|
||||
// }
|
||||
// }
|
||||
// s.WriteRune('\n')
|
||||
// }
|
||||
|
||||
// fmt.Print(s.String())
|
||||
// }
|
||||
|
||||
func (d *Day13) Part1() string {
|
||||
outputStep := 0
|
||||
var newTilePos u.Vec2[int]
|
||||
d.program.RunIn(func(inputStep int) int64 {
|
||||
return 0
|
||||
}, func(val int64, state u.IntcodeProgramState) {
|
||||
if outputStep == 0 {
|
||||
newTilePos.X = int(val)
|
||||
outputStep++
|
||||
} else if outputStep == 1 {
|
||||
newTilePos.Y = int(val)
|
||||
outputStep++
|
||||
} else {
|
||||
d.tiles = append(d.tiles, tile{
|
||||
pos: newTilePos,
|
||||
id: int(val),
|
||||
})
|
||||
outputStep = 0
|
||||
}
|
||||
})
|
||||
|
||||
return fmt.Sprintf("# block tiles: %s%d%s (%d total tiles)", u.TextBold, d.getNumBlocks(), u.TextReset, len(d.tiles))
|
||||
}
|
||||
|
||||
func (d *Day13) Part2() string {
|
||||
d.program.Reset()
|
||||
d.program.SetMemory(0, 2)
|
||||
|
||||
outputStep := 0
|
||||
newTilePos := u.Vec2[int]{}
|
||||
var ball u.Vec2[int]
|
||||
var paddle u.Vec2[int]
|
||||
var score int64
|
||||
d.program.RunIn(func(inputStep int) int64 {
|
||||
if ball.X < paddle.X {
|
||||
return -1
|
||||
} else if ball.X > paddle.X {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}, func(val int64, state u.IntcodeProgramState) {
|
||||
if outputStep == 0 {
|
||||
newTilePos.X = int(val)
|
||||
outputStep++
|
||||
} else if outputStep == 1 {
|
||||
newTilePos.Y = int(val)
|
||||
outputStep++
|
||||
} else {
|
||||
if newTilePos.Equals(u.Vec2[int]{X: -1, Y: 0}) {
|
||||
score = val
|
||||
} else {
|
||||
d.gameBoard[newTilePos.Y][newTilePos.X] = int(val)
|
||||
|
||||
if val == tileBall {
|
||||
ball = newTilePos
|
||||
} else if val == tileHPaddle {
|
||||
paddle = newTilePos
|
||||
// d.drawGameBoard()
|
||||
// time.Sleep(time.Millisecond * 33)
|
||||
}
|
||||
}
|
||||
|
||||
outputStep = 0
|
||||
}
|
||||
})
|
||||
|
||||
return fmt.Sprintf("Game over! Score: %s%d%s", u.TextBold, score, u.TextReset)
|
||||
}
|
127
days/14.go
Normal file
127
days/14.go
Normal file
@ -0,0 +1,127 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
u "parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type reaction struct {
|
||||
inputs map[string]int
|
||||
output u.Pair[string, int]
|
||||
}
|
||||
|
||||
type Day14 struct {
|
||||
reactions []reaction
|
||||
leftovers map[string]int
|
||||
}
|
||||
|
||||
func (d *Day14) Parse() {
|
||||
d.leftovers = make(map[string]int)
|
||||
|
||||
lines := u.GetStringLines("14p")
|
||||
d.reactions = make([]reaction, len(lines))
|
||||
for i, line := range lines {
|
||||
sides := strings.Split(line, " => ")
|
||||
inputs := strings.Split(sides[0], ", ")
|
||||
output := sides[1]
|
||||
|
||||
outPair := strings.Split(output, " ")
|
||||
outAmt, _ := strconv.Atoi(outPair[0])
|
||||
d.reactions[i].output = u.Pair[string, int]{First: outPair[1], Second: outAmt}
|
||||
d.reactions[i].inputs = make(map[string]int)
|
||||
for _, input := range inputs {
|
||||
pair := strings.Split(input, " ")
|
||||
d.reactions[i].inputs[pair[1]], _ = strconv.Atoi(pair[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d Day14) getReactionProducing(chem string) *reaction {
|
||||
for _, reaction := range d.reactions {
|
||||
if reaction.output.First == chem {
|
||||
return &reaction
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d Day14) Num() int {
|
||||
return 14
|
||||
}
|
||||
|
||||
func (d *Day14) oreRequiredStock(qty int64) int64 {
|
||||
oreRequired := int64(0)
|
||||
needs := map[string]int64{
|
||||
"FUEL": qty,
|
||||
}
|
||||
excess := make(map[string]int64)
|
||||
|
||||
getFromExcess := func(qty int64, chemical string) int64 {
|
||||
inStock := excess[chemical]
|
||||
qty -= inStock
|
||||
excess[chemical] = int64(math.Min(math.Abs(float64(qty)), 0))
|
||||
return inStock - excess[chemical]
|
||||
}
|
||||
|
||||
for len(needs) > 0 {
|
||||
keys := u.MapKeys(needs)
|
||||
chemical := keys[len(keys)-1]
|
||||
qtyRequired := needs[chemical]
|
||||
delete(needs, chemical)
|
||||
|
||||
fromExcess := getFromExcess(qtyRequired, chemical)
|
||||
qtyRequired -= fromExcess
|
||||
|
||||
reaction := d.getReactionProducing(chemical)
|
||||
qtyProduced := int64(reaction.output.Second)
|
||||
ingredients := reaction.inputs
|
||||
|
||||
n := int64(math.Ceil(float64(qtyRequired) / float64(qtyProduced)))
|
||||
|
||||
excess[chemical] = (qtyProduced * n) - qtyRequired
|
||||
for ingredient, qtyIngredient := range ingredients {
|
||||
if ingredient == "ORE" {
|
||||
oreRequired += int64(int64(qtyIngredient) * n)
|
||||
} else {
|
||||
needs[ingredient] += int64(qtyIngredient) * n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return oreRequired
|
||||
}
|
||||
|
||||
func (d *Day14) Part1() string {
|
||||
neededOre := d.oreRequiredStock(1)
|
||||
return fmt.Sprintf("%s%d%s", u.TextBold, neededOre, u.TextReset)
|
||||
}
|
||||
|
||||
func (d *Day14) Part2() string {
|
||||
oreAvailable := int64(1000000000000)
|
||||
estimate := oreAvailable / d.oreRequiredStock(1)
|
||||
|
||||
high := estimate * 2
|
||||
low := estimate
|
||||
|
||||
lastSuccess := low
|
||||
lastFailure := high
|
||||
fuelProduced := low
|
||||
|
||||
for math.Abs(float64(lastFailure)-float64(lastSuccess)) > 1 {
|
||||
oreConsumed := d.oreRequiredStock(fuelProduced)
|
||||
if oreConsumed < oreAvailable {
|
||||
lastSuccess = fuelProduced
|
||||
fuelProduced += (lastFailure - lastSuccess) / 2
|
||||
} else {
|
||||
lastFailure = fuelProduced
|
||||
fuelProduced -= (lastFailure - lastSuccess) / 2
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s%d%s", u.TextBold, lastSuccess, u.TextReset)
|
||||
}
|
1
inputs/05p.txt
Normal file
1
inputs/05p.txt
Normal file
@ -0,0 +1 @@
|
||||
3,225,1,225,6,6,1100,1,238,225,104,0,1102,78,40,225,1102,52,43,224,1001,224,-2236,224,4,224,102,8,223,223,101,4,224,224,1,224,223,223,1,191,61,224,1001,224,-131,224,4,224,102,8,223,223,101,4,224,224,1,223,224,223,1101,86,74,225,1102,14,76,225,1101,73,83,224,101,-156,224,224,4,224,102,8,223,223,101,6,224,224,1,224,223,223,1102,43,82,225,2,196,13,224,101,-6162,224,224,4,224,102,8,223,223,101,5,224,224,1,223,224,223,1001,161,51,224,101,-70,224,224,4,224,102,8,223,223,1001,224,1,224,1,224,223,223,102,52,187,224,1001,224,-832,224,4,224,102,8,223,223,101,1,224,224,1,224,223,223,1102,19,79,225,101,65,92,224,1001,224,-147,224,4,224,1002,223,8,223,101,4,224,224,1,223,224,223,1102,16,90,225,1102,45,44,225,1102,92,79,225,1002,65,34,224,101,-476,224,224,4,224,102,8,223,223,1001,224,5,224,1,224,223,223,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,107,226,226,224,1002,223,2,223,1005,224,329,1001,223,1,223,1007,226,226,224,102,2,223,223,1005,224,344,101,1,223,223,1008,226,226,224,102,2,223,223,1005,224,359,1001,223,1,223,8,226,677,224,102,2,223,223,1006,224,374,101,1,223,223,1107,226,677,224,1002,223,2,223,1006,224,389,101,1,223,223,1108,226,677,224,102,2,223,223,1005,224,404,101,1,223,223,107,677,677,224,102,2,223,223,1006,224,419,1001,223,1,223,7,677,226,224,102,2,223,223,1005,224,434,101,1,223,223,1007,677,677,224,102,2,223,223,1005,224,449,1001,223,1,223,108,226,677,224,102,2,223,223,1005,224,464,1001,223,1,223,108,226,226,224,102,2,223,223,1006,224,479,101,1,223,223,107,226,677,224,102,2,223,223,1006,224,494,1001,223,1,223,7,226,226,224,1002,223,2,223,1006,224,509,101,1,223,223,1108,677,226,224,102,2,223,223,1005,224,524,101,1,223,223,1107,677,226,224,102,2,223,223,1005,224,539,101,1,223,223,1008,677,226,224,102,2,223,223,1005,224,554,101,1,223,223,1008,677,677,224,1002,223,2,223,1006,224,569,101,1,223,223,1107,677,677,224,102,2,223,223,1006,224,584,1001,223,1,223,1108,226,226,224,1002,223,2,223,1006,224,599,101,1,223,223,7,226,677,224,102,2,223,223,1006,224,614,101,1,223,223,108,677,677,224,1002,223,2,223,1006,224,629,101,1,223,223,1007,677,226,224,102,2,223,223,1006,224,644,101,1,223,223,8,677,677,224,1002,223,2,223,1006,224,659,101,1,223,223,8,677,226,224,102,2,223,223,1005,224,674,101,1,223,223,4,223,99,226
|
1013
inputs/06p.txt
Normal file
1013
inputs/06p.txt
Normal file
File diff suppressed because it is too large
Load Diff
11
inputs/06s1.txt
Normal file
11
inputs/06s1.txt
Normal file
@ -0,0 +1,11 @@
|
||||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
13
inputs/06s2.txt
Normal file
13
inputs/06s2.txt
Normal file
@ -0,0 +1,13 @@
|
||||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
||||
K)YOU
|
||||
I)SAN
|
1
inputs/07p.txt
Normal file
1
inputs/07p.txt
Normal file
@ -0,0 +1 @@
|
||||
3,8,1001,8,10,8,105,1,0,0,21,38,47,64,85,106,187,268,349,430,99999,3,9,1002,9,4,9,1001,9,4,9,1002,9,4,9,4,9,99,3,9,1002,9,4,9,4,9,99,3,9,1001,9,3,9,102,5,9,9,1001,9,5,9,4,9,99,3,9,101,3,9,9,102,5,9,9,1001,9,4,9,102,4,9,9,4,9,99,3,9,1002,9,3,9,101,2,9,9,102,4,9,9,101,2,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,99,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,2,9,9,4,9,3,9,101,1,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,101,1,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,99
|
1
inputs/07s1.txt
Normal file
1
inputs/07s1.txt
Normal file
@ -0,0 +1 @@
|
||||
3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0
|
1
inputs/07s2.txt
Normal file
1
inputs/07s2.txt
Normal file
@ -0,0 +1 @@
|
||||
3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0
|
1
inputs/07s3.txt
Normal file
1
inputs/07s3.txt
Normal file
@ -0,0 +1 @@
|
||||
3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0
|
1
inputs/07s4.txt
Normal file
1
inputs/07s4.txt
Normal file
@ -0,0 +1 @@
|
||||
3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5
|
1
inputs/07s5.txt
Normal file
1
inputs/07s5.txt
Normal file
@ -0,0 +1 @@
|
||||
3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10
|
1
inputs/08p.txt
Normal file
1
inputs/08p.txt
Normal file
File diff suppressed because one or more lines are too long
1
inputs/08s1.txt
Normal file
1
inputs/08s1.txt
Normal file
@ -0,0 +1 @@
|
||||
123456789012
|
1
inputs/09p.txt
Normal file
1
inputs/09p.txt
Normal file
@ -0,0 +1 @@
|
||||
1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1101,3,0,1000,109,988,209,12,9,1000,209,6,209,3,203,0,1008,1000,1,63,1005,63,65,1008,1000,2,63,1005,63,904,1008,1000,0,63,1005,63,58,4,25,104,0,99,4,0,104,0,99,4,17,104,0,99,0,0,1102,1,31,1018,1102,352,1,1023,1101,0,1,1021,1101,0,33,1003,1102,1,36,1007,1102,21,1,1005,1101,359,0,1022,1101,0,787,1024,1102,1,24,1011,1101,30,0,1014,1101,22,0,1016,1101,0,0,1020,1102,1,29,1000,1101,778,0,1025,1102,23,1,1017,1102,1,28,1002,1101,38,0,1019,1102,1,27,1013,1102,1,32,1012,1101,0,37,1006,1101,444,0,1027,1102,1,20,1009,1101,0,447,1026,1101,0,39,1008,1101,35,0,1010,1102,559,1,1028,1102,26,1,1004,1102,1,25,1015,1102,1,34,1001,1101,0,554,1029,109,-3,2101,0,9,63,1008,63,34,63,1005,63,205,1001,64,1,64,1105,1,207,4,187,1002,64,2,64,109,23,21107,40,39,-7,1005,1013,227,1001,64,1,64,1106,0,229,4,213,1002,64,2,64,109,-17,1202,-2,1,63,1008,63,36,63,1005,63,249,1106,0,255,4,235,1001,64,1,64,1002,64,2,64,109,-6,1202,10,1,63,1008,63,36,63,1005,63,277,4,261,1106,0,281,1001,64,1,64,1002,64,2,64,109,-2,1208,9,26,63,1005,63,303,4,287,1001,64,1,64,1106,0,303,1002,64,2,64,109,32,1206,-7,321,4,309,1001,64,1,64,1106,0,321,1002,64,2,64,109,-29,1207,7,20,63,1005,63,337,1105,1,343,4,327,1001,64,1,64,1002,64,2,64,109,27,2105,1,-2,1001,64,1,64,1106,0,361,4,349,1002,64,2,64,109,-25,2108,39,7,63,1005,63,377,1106,0,383,4,367,1001,64,1,64,1002,64,2,64,109,1,1201,6,0,63,1008,63,36,63,1005,63,409,4,389,1001,64,1,64,1105,1,409,1002,64,2,64,109,1,2102,1,1,63,1008,63,33,63,1005,63,435,4,415,1001,64,1,64,1105,1,435,1002,64,2,64,109,28,2106,0,-3,1106,0,453,4,441,1001,64,1,64,1002,64,2,64,109,-13,21101,41,0,1,1008,1018,44,63,1005,63,477,1001,64,1,64,1106,0,479,4,459,1002,64,2,64,109,4,21108,42,42,-2,1005,1019,501,4,485,1001,64,1,64,1106,0,501,1002,64,2,64,109,-21,2101,0,2,63,1008,63,28,63,1005,63,523,4,507,1105,1,527,1001,64,1,64,1002,64,2,64,109,26,1205,-5,545,4,533,1001,64,1,64,1105,1,545,1002,64,2,64,109,3,2106,0,-1,4,551,1106,0,563,1001,64,1,64,1002,64,2,64,109,-33,1201,4,0,63,1008,63,28,63,1005,63,583,1105,1,589,4,569,1001,64,1,64,1002,64,2,64,109,11,2107,27,-3,63,1005,63,609,1001,64,1,64,1106,0,611,4,595,1002,64,2,64,109,8,21102,43,1,3,1008,1018,43,63,1005,63,637,4,617,1001,64,1,64,1105,1,637,1002,64,2,64,109,-5,21108,44,41,0,1005,1010,653,1105,1,659,4,643,1001,64,1,64,1002,64,2,64,109,-13,2108,21,8,63,1005,63,681,4,665,1001,64,1,64,1106,0,681,1002,64,2,64,109,6,1207,0,34,63,1005,63,703,4,687,1001,64,1,64,1105,1,703,1002,64,2,64,109,7,1208,-7,35,63,1005,63,723,1001,64,1,64,1106,0,725,4,709,1002,64,2,64,109,-13,2102,1,7,63,1008,63,23,63,1005,63,745,1105,1,751,4,731,1001,64,1,64,1002,64,2,64,109,13,1205,10,767,1001,64,1,64,1105,1,769,4,757,1002,64,2,64,109,14,2105,1,0,4,775,1001,64,1,64,1106,0,787,1002,64,2,64,109,-20,21107,45,46,7,1005,1011,809,4,793,1001,64,1,64,1105,1,809,1002,64,2,64,109,-3,2107,25,3,63,1005,63,827,4,815,1106,0,831,1001,64,1,64,1002,64,2,64,109,13,1206,7,847,1001,64,1,64,1106,0,849,4,837,1002,64,2,64,109,-11,21101,46,0,7,1008,1010,46,63,1005,63,871,4,855,1106,0,875,1001,64,1,64,1002,64,2,64,109,15,21102,47,1,-4,1008,1014,48,63,1005,63,895,1106,0,901,4,881,1001,64,1,64,4,64,99,21102,27,1,1,21101,0,915,0,1106,0,922,21201,1,63208,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21102,1,942,0,1106,0,922,21202,1,1,-1,21201,-2,-3,1,21101,957,0,0,1105,1,922,22201,1,-1,-2,1106,0,968,21201,-2,0,-2,109,-3,2106,0,0
|
1
inputs/09s1.txt
Normal file
1
inputs/09s1.txt
Normal file
@ -0,0 +1 @@
|
||||
109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99
|
1
inputs/09s2.txt
Normal file
1
inputs/09s2.txt
Normal file
@ -0,0 +1 @@
|
||||
1102,34915192,34915192,7,4,7,99,0
|
1
inputs/09s3.txt
Normal file
1
inputs/09s3.txt
Normal file
@ -0,0 +1 @@
|
||||
104,1125899906842624,99
|
33
inputs/10p.txt
Normal file
33
inputs/10p.txt
Normal file
@ -0,0 +1,33 @@
|
||||
.#......##.#..#.......#####...#..
|
||||
...#.....##......###....#.##.....
|
||||
..#...#....#....#............###.
|
||||
.....#......#.##......#.#..###.#.
|
||||
#.#..........##.#.#...#.##.#.#.#.
|
||||
..#.##.#...#.......#..##.......##
|
||||
..#....#.....#..##.#..####.#.....
|
||||
#.............#..#.........#.#...
|
||||
........#.##..#..#..#.#.....#.#..
|
||||
.........#...#..##......###.....#
|
||||
##.#.###..#..#.#.....#.........#.
|
||||
.#.###.##..##......#####..#..##..
|
||||
.........#.......#.#......#......
|
||||
..#...#...#...#.#....###.#.......
|
||||
#..#.#....#...#.......#..#.#.##..
|
||||
#.....##...#.###..#..#......#..##
|
||||
...........#...#......#..#....#..
|
||||
#.#.#......#....#..#.....##....##
|
||||
..###...#.#.##..#...#.....#...#.#
|
||||
.......#..##.#..#.............##.
|
||||
..###........##.#................
|
||||
###.#..#...#......###.#........#.
|
||||
.......#....#.#.#..#..#....#..#..
|
||||
.#...#..#...#......#....#.#..#...
|
||||
#.#.........#.....#....#.#.#.....
|
||||
.#....#......##.##....#........#.
|
||||
....#..#..#...#..##.#.#......#.#.
|
||||
..###.##.#.....#....#.#......#...
|
||||
#.##...#............#..#.....#..#
|
||||
.#....##....##...#......#........
|
||||
...#...##...#.......#....##.#....
|
||||
.#....#.#...#.#...##....#..##.#.#
|
||||
.#.#....##.......#.....##.##.#.##
|
5
inputs/10s1.txt
Normal file
5
inputs/10s1.txt
Normal file
@ -0,0 +1,5 @@
|
||||
.#..#
|
||||
.....
|
||||
#####
|
||||
....#
|
||||
...##
|
10
inputs/10s2.txt
Normal file
10
inputs/10s2.txt
Normal file
@ -0,0 +1,10 @@
|
||||
......#.#.
|
||||
#..#.#....
|
||||
..#######.
|
||||
.#.#.###..
|
||||
.#..#.....
|
||||
..#....#.#
|
||||
#..#....#.
|
||||
.##.#..###
|
||||
##...#..#.
|
||||
.#....####
|
10
inputs/10s3.txt
Normal file
10
inputs/10s3.txt
Normal file
@ -0,0 +1,10 @@
|
||||
#.#...#.#.
|
||||
.###....#.
|
||||
.#....#...
|
||||
##.#.#.#.#
|
||||
....#.#.#.
|
||||
.##..###.#
|
||||
..#...##..
|
||||
..##....##
|
||||
......#...
|
||||
.####.###.
|
10
inputs/10s4.txt
Normal file
10
inputs/10s4.txt
Normal file
@ -0,0 +1,10 @@
|
||||
.#..#..###
|
||||
####.###.#
|
||||
....###.#.
|
||||
..###.##.#
|
||||
##.##.#.#.
|
||||
....###..#
|
||||
..#.#..#.#
|
||||
#..#.#.###
|
||||
.##...##.#
|
||||
.....#.#..
|
20
inputs/10s5.txt
Normal file
20
inputs/10s5.txt
Normal file
@ -0,0 +1,20 @@
|
||||
.#..##.###...#######
|
||||
##.############..##.
|
||||
.#.######.########.#
|
||||
.###.#######.####.#.
|
||||
#####.##.#.##.###.##
|
||||
..#####..#.#########
|
||||
####################
|
||||
#.####....###.#.#.##
|
||||
##.#################
|
||||
#####.##.###..####..
|
||||
..######..##.#######
|
||||
####.##.####...##..#
|
||||
.#####..#.######.###
|
||||
##...#.##########...
|
||||
#.##########.#######
|
||||
.####.#.###.###.#.##
|
||||
....##.##.###..#####
|
||||
.#.#.###########.###
|
||||
#.#.#.#####.####.###
|
||||
###.##.####.##.#..##
|
5
inputs/10s6.txt
Normal file
5
inputs/10s6.txt
Normal file
@ -0,0 +1,5 @@
|
||||
.#....#####...#..
|
||||
##...##.#####..##
|
||||
##...#...#.#####.
|
||||
..#.....#...###..
|
||||
..#.#.....#....##
|
1
inputs/11p.txt
Normal file
1
inputs/11p.txt
Normal file
@ -0,0 +1 @@
|
||||
3,8,1005,8,330,1106,0,11,0,0,0,104,1,104,0,3,8,102,-1,8,10,101,1,10,10,4,10,1008,8,0,10,4,10,102,1,8,29,3,8,1002,8,-1,10,1001,10,1,10,4,10,1008,8,0,10,4,10,101,0,8,51,1,1103,2,10,1006,0,94,1006,0,11,1,1106,13,10,3,8,1002,8,-1,10,101,1,10,10,4,10,1008,8,1,10,4,10,1001,8,0,87,3,8,102,-1,8,10,101,1,10,10,4,10,1008,8,0,10,4,10,1001,8,0,109,2,1105,5,10,2,103,16,10,1,1103,12,10,2,105,2,10,3,8,102,-1,8,10,1001,10,1,10,4,10,108,1,8,10,4,10,1001,8,0,146,1006,0,49,2,1,12,10,2,1006,6,10,1,1101,4,10,3,8,1002,8,-1,10,1001,10,1,10,4,10,108,0,8,10,4,10,1001,8,0,183,1,6,9,10,1006,0,32,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,1,10,4,10,101,0,8,213,2,1101,9,10,3,8,1002,8,-1,10,1001,10,1,10,4,10,1008,8,1,10,4,10,101,0,8,239,1006,0,47,1006,0,4,2,6,0,10,1006,0,58,3,8,1002,8,-1,10,1001,10,1,10,4,10,1008,8,0,10,4,10,102,1,8,274,2,1005,14,10,1006,0,17,1,104,20,10,1006,0,28,3,8,102,-1,8,10,1001,10,1,10,4,10,108,1,8,10,4,10,1002,8,1,309,101,1,9,9,1007,9,928,10,1005,10,15,99,109,652,104,0,104,1,21101,0,937263411860,1,21102,347,1,0,1105,1,451,21101,932440724376,0,1,21102,1,358,0,1105,1,451,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,21101,0,29015167015,1,21101,0,405,0,1106,0,451,21102,1,3422723163,1,21101,0,416,0,1106,0,451,3,10,104,0,104,0,3,10,104,0,104,0,21101,0,868389376360,1,21101,0,439,0,1105,1,451,21102,825544712960,1,1,21102,1,450,0,1106,0,451,99,109,2,21201,-1,0,1,21101,0,40,2,21102,482,1,3,21102,1,472,0,1106,0,515,109,-2,2106,0,0,0,1,0,0,1,109,2,3,10,204,-1,1001,477,478,493,4,0,1001,477,1,477,108,4,477,10,1006,10,509,1101,0,0,477,109,-2,2106,0,0,0,109,4,2101,0,-1,514,1207,-3,0,10,1006,10,532,21102,1,0,-3,22101,0,-3,1,22102,1,-2,2,21102,1,1,3,21101,551,0,0,1106,0,556,109,-4,2105,1,0,109,5,1207,-3,1,10,1006,10,579,2207,-4,-2,10,1006,10,579,22102,1,-4,-4,1106,0,647,21201,-4,0,1,21201,-3,-1,2,21202,-2,2,3,21102,1,598,0,1106,0,556,22101,0,1,-4,21101,1,0,-1,2207,-4,-2,10,1006,10,617,21102,0,1,-1,22202,-2,-1,-2,2107,0,-3,10,1006,10,639,21201,-1,0,1,21102,639,1,0,105,1,514,21202,-2,-1,-2,22201,-4,-2,-4,109,-5,2105,1,0
|
4
inputs/12p.txt
Normal file
4
inputs/12p.txt
Normal file
@ -0,0 +1,4 @@
|
||||
<x=-6, y=-5, z=-8>
|
||||
<x=0, y=-3, z=-13>
|
||||
<x=-15, y=10, z=-11>
|
||||
<x=-3, y=-8, z=3>
|
4
inputs/12s1.txt
Normal file
4
inputs/12s1.txt
Normal file
@ -0,0 +1,4 @@
|
||||
<x=-1, y=0, z=2>
|
||||
<x=2, y=-10, z=-7>
|
||||
<x=4, y=-8, z=8>
|
||||
<x=3, y=5, z=-1>
|
4
inputs/12s2.txt
Normal file
4
inputs/12s2.txt
Normal file
@ -0,0 +1,4 @@
|
||||
<x=-8, y=-10, z=0>
|
||||
<x=5, y=5, z=10>
|
||||
<x=2, y=-7, z=3>
|
||||
<x=9, y=-8, z=-3>
|
1
inputs/13p.txt
Normal file
1
inputs/13p.txt
Normal file
File diff suppressed because one or more lines are too long
60
inputs/14p.txt
Normal file
60
inputs/14p.txt
Normal file
@ -0,0 +1,60 @@
|
||||
11 RVCS => 8 CBMDT
|
||||
29 QXPB, 8 QRGRH => 8 LGMKD
|
||||
3 VPRVD => 6 PMFZG
|
||||
1 CNWNQ, 11 MJVXS => 6 SPLM
|
||||
13 SPDRZ, 13 PMFZG => 2 BLFM
|
||||
8 QWPFN => 7 LWVB
|
||||
1 SPLM => 8 TKWQ
|
||||
2 QRGRH, 6 CNWNQ => 7 DTZW
|
||||
2 DMLT, 1 SPLM, 1 TMDK => 9 NKNS
|
||||
1 MJVXS, 1 HLBV => 7 PQCQH
|
||||
1 JZHZP, 9 LWVB => 7 MJSCQ
|
||||
29 DGFR => 7 QRGRH
|
||||
14 XFLKQ, 2 NKNS, 4 KMNJF, 3 MLZGQ, 7 TKWQ, 24 WTDW, 11 CBMDT => 4 GJKX
|
||||
4 TKWQ, 1 WLCFR => 4 PDKGT
|
||||
2 NKNS => 4 GDKL
|
||||
4 WRZST => 9 XFLKQ
|
||||
19 DGFR => 4 VPRVD
|
||||
10 MJSCQ, 4 QWPFN, 4 QXPB => 2 MLZGQ
|
||||
1 JZHZP => 7 QWPFN
|
||||
1 XFLKQ => 9 FQGVL
|
||||
3 GQGXC => 9 VHGP
|
||||
3 NQZTV, 1 JZHZP => 2 NVZWL
|
||||
38 WLCFR, 15 GJKX, 44 LGMKD, 2 CBVXG, 2 GDKL, 77 FQGVL, 10 MKRCZ, 29 WJQD, 33 BWXGC, 19 PQCQH, 24 BKXD => 1 FUEL
|
||||
102 ORE => 5 DGFR
|
||||
17 NWKLB, 1 SBPLK => 5 HRQM
|
||||
3 BWXGC => 8 TQDP
|
||||
1 TQDP => 2 PSZDZ
|
||||
2 MJVXS => 9 WNXG
|
||||
2 NBTW, 1 HRQM => 2 SVHBH
|
||||
8 CNWNQ, 1 DTZW => 4 RVCS
|
||||
4 VHGP, 20 WNXG, 2 SVHBH => 3 SPDRZ
|
||||
110 ORE => 5 TXMC
|
||||
10 QRGRH => 5 NWKLB
|
||||
1 SBPLK => 3 MJVXS
|
||||
9 DGFR => 5 RFSRL
|
||||
5 LBTV => 3 DMLT
|
||||
1 NWKLB, 1 KMNJF, 1 HDQXB, 6 LBTV, 2 PSZDZ, 34 PMFZG, 2 SVHBH => 2 WJQD
|
||||
1 RVCS => 5 MKRCZ
|
||||
14 NQZTV, 3 FPLT, 1 SJMS => 2 GQGXC
|
||||
18 RFSRL, 13 VHGP, 23 NBTW => 5 WTDW
|
||||
1 VHGP, 6 TKWQ => 7 QXPB
|
||||
1 JZHZP, 1 CNWNQ => 5 KMNJF
|
||||
109 ORE => 9 BWXGC
|
||||
2 CNWNQ, 1 PDKGT, 2 KMNJF => 5 HDQXB
|
||||
1 PDKGT, 18 WRZST, 9 MJSCQ, 3 VHGP, 1 BLFM, 1 LGMKD, 7 WLCFR => 2 BKXD
|
||||
11 MLJK => 6 FPLT
|
||||
8 DGFR, 2 TXMC, 3 WJRC => 9 SJMS
|
||||
2 SBPLK => 1 LBTV
|
||||
22 QWPFN => 4 WRZST
|
||||
5 WRZST, 22 WNXG, 1 VHGP => 7 NBTW
|
||||
7 RVCS => 9 TMDK
|
||||
1 DGFR, 14 TXMC => 5 JZHZP
|
||||
2 JZHZP => 3 SBPLK
|
||||
19 PDKGT => 8 HLBV
|
||||
195 ORE => 6 WJRC
|
||||
6 GQGXC => 8 CNWNQ
|
||||
1 NVZWL, 4 GQGXC => 2 CBVXG
|
||||
1 NVZWL, 1 KMNJF => 8 WLCFR
|
||||
153 ORE => 4 MLJK
|
||||
1 BWXGC => 6 NQZTV
|
6
inputs/14s1.txt
Normal file
6
inputs/14s1.txt
Normal file
@ -0,0 +1,6 @@
|
||||
10 ORE => 10 A
|
||||
1 ORE => 1 B
|
||||
7 A, 1 B => 1 C
|
||||
7 A, 1 C => 1 D
|
||||
7 A, 1 D => 1 E
|
||||
7 A, 1 E => 1 FUEL
|
7
inputs/14s2.txt
Normal file
7
inputs/14s2.txt
Normal file
@ -0,0 +1,7 @@
|
||||
9 ORE => 2 A
|
||||
8 ORE => 3 B
|
||||
7 ORE => 5 C
|
||||
3 A, 4 B => 1 AB
|
||||
5 B, 7 C => 1 BC
|
||||
4 C, 1 A => 1 CA
|
||||
2 AB, 3 BC, 4 CA => 1 FUEL
|
9
inputs/14s3.txt
Normal file
9
inputs/14s3.txt
Normal file
@ -0,0 +1,9 @@
|
||||
157 ORE => 5 NZVS
|
||||
165 ORE => 6 DCFZ
|
||||
44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL
|
||||
12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ
|
||||
179 ORE => 7 PSHF
|
||||
177 ORE => 5 HKGWZ
|
||||
7 DCFZ, 7 PSHF => 2 XJWVT
|
||||
165 ORE => 2 GPVTF
|
||||
3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT
|
12
inputs/14s4.txt
Normal file
12
inputs/14s4.txt
Normal file
@ -0,0 +1,12 @@
|
||||
2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG
|
||||
17 NVRVD, 3 JNWZP => 8 VPVL
|
||||
53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL
|
||||
22 VJHF, 37 MNCFX => 5 FWMGM
|
||||
139 ORE => 4 NVRVD
|
||||
144 ORE => 7 JNWZP
|
||||
5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC
|
||||
5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV
|
||||
145 ORE => 6 MNCFX
|
||||
1 NVRVD => 8 CXFTF
|
||||
1 VJHF, 6 MNCFX => 4 RFSQX
|
||||
176 ORE => 6 VJHF
|
17
inputs/14s5.txt
Normal file
17
inputs/14s5.txt
Normal file
@ -0,0 +1,17 @@
|
||||
171 ORE => 8 CNZTR
|
||||
7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL
|
||||
114 ORE => 4 BHXH
|
||||
14 VRPVC => 6 BMBT
|
||||
6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL
|
||||
6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT
|
||||
15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW
|
||||
13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW
|
||||
5 BMBT => 4 WPTQ
|
||||
189 ORE => 9 KTJDG
|
||||
1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP
|
||||
12 VRPVC, 27 CNZTR => 2 XDBXC
|
||||
15 KTJDG, 12 BHXH => 5 XCVML
|
||||
3 BHXH, 2 VRPVC => 7 MZWV
|
||||
121 ORE => 7 VRPVC
|
||||
7 XCVML => 6 RJRHP
|
||||
5 BHXH, 4 VRPVC => 5 LTCX
|
10
main.go
10
main.go
@ -35,6 +35,16 @@ var dayMap = []day{
|
||||
&days.Day02{},
|
||||
&days.Day03{},
|
||||
&days.Day04{},
|
||||
&days.Day05{},
|
||||
&days.Day06{},
|
||||
&days.Day07{},
|
||||
&days.Day08{},
|
||||
&days.Day09{},
|
||||
&days.Day10{},
|
||||
&days.Day11{},
|
||||
&days.Day12{},
|
||||
&days.Day13{},
|
||||
&days.Day14{},
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
12
utilities/array.go
Normal file
12
utilities/array.go
Normal file
@ -0,0 +1,12 @@
|
||||
package utilities
|
||||
|
||||
// ArrayContains returns whether the specified array contains the specified value
|
||||
func ArrayContains[T comparable](array []T, val T) bool {
|
||||
for _, v := range array {
|
||||
if v == val {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
29
utilities/constraints.go
Normal file
29
utilities/constraints.go
Normal file
@ -0,0 +1,29 @@
|
||||
package utilities
|
||||
|
||||
type Ordered interface {
|
||||
Integer | Float | ~string
|
||||
}
|
||||
|
||||
type Signed interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64
|
||||
}
|
||||
|
||||
type Unsigned interface {
|
||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
|
||||
}
|
||||
|
||||
type Integer interface {
|
||||
Signed | Unsigned
|
||||
}
|
||||
|
||||
type Float interface {
|
||||
~float32 | ~float64
|
||||
}
|
||||
|
||||
type Complex interface {
|
||||
~complex64 | ~complex128
|
||||
}
|
||||
|
||||
type Number interface {
|
||||
Integer | Float
|
||||
}
|
@ -1,52 +1,250 @@
|
||||
package utilities
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
opAdd = 1
|
||||
opMul = 2
|
||||
opEnd = 99
|
||||
opAdd = 1
|
||||
opMultiply = 2
|
||||
opInput = 3
|
||||
opOutput = 4
|
||||
opJumpIfTrue = 5
|
||||
opJumpIfFalse = 6
|
||||
opLessThan = 7
|
||||
opEquals = 8
|
||||
opRelativeBase = 9
|
||||
opHalt = 99
|
||||
|
||||
modePosition = 0
|
||||
modeImmediate = 1
|
||||
modeRelative = 2
|
||||
)
|
||||
|
||||
type IntcodeProgram []int64
|
||||
type IntcodeProgram struct {
|
||||
memory []int64
|
||||
program []int64
|
||||
relativeBase int
|
||||
}
|
||||
|
||||
type IntcodeProgramState struct {
|
||||
program *IntcodeProgram
|
||||
CurrentInstruction int
|
||||
NextInstruction int
|
||||
}
|
||||
|
||||
func (s IntcodeProgramState) IsHalting() bool {
|
||||
return s.program.GetMemory(s.NextInstruction) == opHalt
|
||||
}
|
||||
|
||||
type ProvideInputFunc func(inputStep int) int64
|
||||
type ReceiveOutputFunc func(val int64, state IntcodeProgramState)
|
||||
|
||||
func ParseIntcodeProgram(programStr string) IntcodeProgram {
|
||||
nums := strings.Split(programStr, ",")
|
||||
program := make(IntcodeProgram, len(nums))
|
||||
program := IntcodeProgram{
|
||||
program: make([]int64, len(nums)),
|
||||
}
|
||||
for idx, num := range nums {
|
||||
iNum, err := strconv.ParseInt(num, 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
program[idx] = iNum
|
||||
program.program[idx] = iNum
|
||||
}
|
||||
|
||||
return program
|
||||
}
|
||||
|
||||
func (program IntcodeProgram) Run() {
|
||||
for instructionPointer := 0; instructionPointer < len(program); {
|
||||
opcode := program[instructionPointer]
|
||||
func (p *IntcodeProgram) makeState(instructionPointer int) IntcodeProgramState {
|
||||
return IntcodeProgramState{
|
||||
program: p,
|
||||
CurrentInstruction: instructionPointer,
|
||||
NextInstruction: instructionPointer + 1,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *IntcodeProgram) Copy() IntcodeProgram {
|
||||
ret := IntcodeProgram{
|
||||
program: make([]int64, len(p.program)),
|
||||
}
|
||||
copy(ret.program, p.program)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p *IntcodeProgram) init() {
|
||||
if p.memory == nil {
|
||||
p.memory = make([]int64, len(p.program))
|
||||
copy(p.memory, p.program)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *IntcodeProgram) getParamValue(param, mode int) int64 {
|
||||
switch mode {
|
||||
case modePosition:
|
||||
return p.GetMemory(param)
|
||||
|
||||
case modeImmediate:
|
||||
return int64(param)
|
||||
|
||||
case modeRelative:
|
||||
return p.GetMemory(param + p.relativeBase)
|
||||
}
|
||||
|
||||
panic("unhandled param mode")
|
||||
}
|
||||
|
||||
func (p *IntcodeProgram) GetMemory(idx int) int64 {
|
||||
p.ensureMemoryCapacity(idx)
|
||||
return p.memory[idx]
|
||||
}
|
||||
|
||||
func (p *IntcodeProgram) SetMemory(idx int, val int64) {
|
||||
p.init()
|
||||
p.ensureMemoryCapacity(idx)
|
||||
p.memory[idx] = val
|
||||
}
|
||||
|
||||
func (p *IntcodeProgram) setMemory(idx int, val int64, mode int) {
|
||||
if mode == modeImmediate {
|
||||
panic("exception executing program - write parameter must never be in immediate mode")
|
||||
}
|
||||
if mode == modeRelative {
|
||||
idx = idx + p.relativeBase
|
||||
}
|
||||
|
||||
p.SetMemory(idx, val)
|
||||
}
|
||||
|
||||
func (p *IntcodeProgram) ensureMemoryCapacity(address int) {
|
||||
if len(p.memory) > address {
|
||||
return
|
||||
}
|
||||
|
||||
p.memory = append(p.memory, make([]int64, address+1-len(p.memory))...)
|
||||
}
|
||||
|
||||
func (p *IntcodeProgram) Reset() {
|
||||
p.memory = nil
|
||||
p.init()
|
||||
copy(p.memory, p.program)
|
||||
p.relativeBase = 0
|
||||
}
|
||||
|
||||
func (p *IntcodeProgram) Run() {
|
||||
p.RunIn(func(int) int64 { return 0 }, func(int64, IntcodeProgramState) {})
|
||||
}
|
||||
|
||||
func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOutputFunc) {
|
||||
p.init()
|
||||
|
||||
inputsRequested := 0
|
||||
for instructionPointer := 0; instructionPointer < len(p.program); {
|
||||
instruction := p.GetMemory(instructionPointer)
|
||||
instructionPointer++
|
||||
|
||||
paramModes := [3]int{
|
||||
modePosition,
|
||||
modePosition,
|
||||
modePosition,
|
||||
}
|
||||
modes := instruction / 100
|
||||
for i := 0; modes > 0; i++ {
|
||||
paramModes[i] = int(modes % 10)
|
||||
modes = modes / 10
|
||||
}
|
||||
|
||||
opcode := instruction % 100
|
||||
switch opcode {
|
||||
case opAdd:
|
||||
param1 := program[instructionPointer+1]
|
||||
param2 := program[instructionPointer+2]
|
||||
param3 := program[instructionPointer+3]
|
||||
program[param3] = program[param1] + program[param2]
|
||||
param1 := p.GetMemory(instructionPointer)
|
||||
param2 := p.GetMemory(instructionPointer + 1)
|
||||
param3 := p.GetMemory(instructionPointer + 2)
|
||||
p.setMemory(int(param3), p.getParamValue(int(param1), paramModes[0])+p.getParamValue(int(param2), paramModes[1]), paramModes[2])
|
||||
|
||||
instructionPointer += 4
|
||||
case opMul:
|
||||
param1 := program[instructionPointer+1]
|
||||
param2 := program[instructionPointer+2]
|
||||
param3 := program[instructionPointer+3]
|
||||
program[param3] = program[param1] * program[param2]
|
||||
instructionPointer += 3
|
||||
|
||||
instructionPointer += 4
|
||||
case opEnd:
|
||||
instructionPointer = len(program)
|
||||
case opMultiply:
|
||||
param1 := p.GetMemory(instructionPointer)
|
||||
param2 := p.GetMemory(instructionPointer + 1)
|
||||
param3 := p.GetMemory(instructionPointer + 2)
|
||||
p.setMemory(int(param3), p.getParamValue(int(param1), paramModes[0])*p.getParamValue(int(param2), paramModes[1]), paramModes[2])
|
||||
|
||||
instructionPointer += 3
|
||||
|
||||
case opInput:
|
||||
inputsRequested++
|
||||
param1 := p.GetMemory(instructionPointer)
|
||||
p.setMemory(int(param1), inputFunc(inputsRequested), paramModes[0])
|
||||
|
||||
instructionPointer += 1
|
||||
|
||||
case opOutput:
|
||||
param1 := p.GetMemory(instructionPointer)
|
||||
outputFunc(p.getParamValue(int(param1), paramModes[0]), p.makeState(instructionPointer))
|
||||
|
||||
instructionPointer += 1
|
||||
|
||||
case opJumpIfTrue:
|
||||
param1 := p.GetMemory(instructionPointer)
|
||||
param2 := p.GetMemory(instructionPointer + 1)
|
||||
|
||||
if p.getParamValue(int(param1), paramModes[0]) != 0 {
|
||||
instructionPointer = int(p.getParamValue(int(param2), paramModes[1]))
|
||||
} else {
|
||||
instructionPointer += 2
|
||||
}
|
||||
|
||||
case opJumpIfFalse:
|
||||
param1 := p.GetMemory(instructionPointer)
|
||||
param2 := p.GetMemory(instructionPointer + 1)
|
||||
|
||||
if p.getParamValue(int(param1), paramModes[0]) == 0 {
|
||||
instructionPointer = int(p.getParamValue(int(param2), paramModes[1]))
|
||||
} else {
|
||||
instructionPointer += 2
|
||||
}
|
||||
|
||||
case opLessThan:
|
||||
param1 := p.GetMemory(instructionPointer)
|
||||
param2 := p.GetMemory(instructionPointer + 1)
|
||||
param3 := p.GetMemory(instructionPointer + 2)
|
||||
|
||||
if p.getParamValue(int(param1), paramModes[0]) < p.getParamValue(int(param2), paramModes[1]) {
|
||||
p.setMemory(int(param3), 1, paramModes[2])
|
||||
} else {
|
||||
p.setMemory(int(param3), 0, paramModes[2])
|
||||
}
|
||||
|
||||
instructionPointer += 3
|
||||
|
||||
case opEquals:
|
||||
param1 := p.GetMemory(instructionPointer)
|
||||
param2 := p.GetMemory(instructionPointer + 1)
|
||||
param3 := p.GetMemory(instructionPointer + 2)
|
||||
|
||||
if p.getParamValue(int(param1), paramModes[0]) == p.getParamValue(int(param2), paramModes[1]) {
|
||||
p.setMemory(int(param3), 1, paramModes[2])
|
||||
} else {
|
||||
p.setMemory(int(param3), 0, paramModes[2])
|
||||
}
|
||||
|
||||
instructionPointer += 3
|
||||
|
||||
case opRelativeBase:
|
||||
param1 := p.GetMemory(instructionPointer)
|
||||
|
||||
p.relativeBase += int(p.getParamValue(int(param1), paramModes[0]))
|
||||
|
||||
instructionPointer += 1
|
||||
|
||||
case opHalt:
|
||||
instructionPointer = len(p.program)
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("exception executing program - unhandled opcode %d", opcode))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
utilities/map.go
Normal file
17
utilities/map.go
Normal file
@ -0,0 +1,17 @@
|
||||
package utilities
|
||||
|
||||
func MapKeys[T comparable, U any](m map[T]U) []T {
|
||||
r := make([]T, 0, len(m))
|
||||
for k := range m {
|
||||
r = append(r, k)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func MapValues[T comparable, U any](m map[T]U) []U {
|
||||
r := make([]U, 0, len(m))
|
||||
for _, v := range m {
|
||||
r = append(r, v)
|
||||
}
|
||||
return r
|
||||
}
|
27
utilities/math.go
Normal file
27
utilities/math.go
Normal file
@ -0,0 +1,27 @@
|
||||
package utilities
|
||||
|
||||
func GCD[T Integer](a, b T) T {
|
||||
if b == 0 {
|
||||
return a
|
||||
}
|
||||
return GCD(b, a%b)
|
||||
}
|
||||
|
||||
func LCM[T Integer](nums ...T) uint64 {
|
||||
num := len(nums)
|
||||
if num == 0 {
|
||||
return 0
|
||||
} else if num == 1 {
|
||||
return uint64(nums[0])
|
||||
}
|
||||
|
||||
ret := lcm(nums[0], nums[1])
|
||||
for i := 2; i < len(nums); i++ {
|
||||
ret = lcm(uint64(nums[i]), ret)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func lcm[T Integer](a, b T) uint64 {
|
||||
return uint64(a*b) / uint64(GCD(a, b))
|
||||
}
|
6
utilities/pair.go
Normal file
6
utilities/pair.go
Normal file
@ -0,0 +1,6 @@
|
||||
package utilities
|
||||
|
||||
type Pair[T, U any] struct {
|
||||
First T
|
||||
Second U
|
||||
}
|
34
utilities/permutations.go
Normal file
34
utilities/permutations.go
Normal file
@ -0,0 +1,34 @@
|
||||
package utilities
|
||||
|
||||
type Permutable interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
|
||||
}
|
||||
|
||||
func GetPermutations[T Permutable](arr []T) [][]T {
|
||||
var helper func([]T, int)
|
||||
res := [][]T{}
|
||||
|
||||
helper = func(arr []T, n int) {
|
||||
if n == 1 {
|
||||
tmp := make([]T, len(arr))
|
||||
copy(tmp, arr)
|
||||
res = append(res, tmp)
|
||||
} else {
|
||||
for i := 0; i < n; i++ {
|
||||
helper(arr, n-1)
|
||||
if n%2 == 1 {
|
||||
tmp := arr[i]
|
||||
arr[i] = arr[n-1]
|
||||
arr[n-1] = tmp
|
||||
} else {
|
||||
tmp := arr[0]
|
||||
arr[0] = arr[n-1]
|
||||
arr[n-1] = tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
helper(arr, len(arr))
|
||||
return res
|
||||
}
|
74
utilities/vector.go
Normal file
74
utilities/vector.go
Normal file
@ -0,0 +1,74 @@
|
||||
package utilities
|
||||
|
||||
import "math"
|
||||
|
||||
type Vec2[T Number] struct {
|
||||
X T
|
||||
Y T
|
||||
}
|
||||
|
||||
type Vec3[T Number] struct {
|
||||
X T
|
||||
Y T
|
||||
Z T
|
||||
}
|
||||
|
||||
func (v Vec2[T]) Dot(other Vec2[T]) T {
|
||||
return (v.X * other.X) + (v.Y * other.Y)
|
||||
}
|
||||
|
||||
func (v Vec2[T]) Len() T {
|
||||
return T(math.Sqrt(float64(v.LenSquared())))
|
||||
}
|
||||
|
||||
func (v Vec2[T]) LenSquared() T {
|
||||
return (v.X * v.X) + (v.Y * v.Y)
|
||||
}
|
||||
|
||||
func (v Vec2[T]) To(other Vec2[T]) Vec2[T] {
|
||||
return Vec2[T]{
|
||||
X: v.X - other.X,
|
||||
Y: v.Y - other.Y,
|
||||
}
|
||||
}
|
||||
|
||||
func (v Vec2[T]) AngleBetween(other Vec2[T]) float64 {
|
||||
rad := math.Atan2(float64(other.Y-v.Y), float64(other.X-v.X))
|
||||
return rad * 180 / math.Pi
|
||||
}
|
||||
|
||||
func (v Vec2[T]) Equals(other Vec2[T]) bool {
|
||||
return v.X == other.X &&
|
||||
v.Y == other.Y
|
||||
}
|
||||
|
||||
func VecBetween[T Number](a, b Vec2[T]) Vec2[T] {
|
||||
return Vec2[T]{
|
||||
X: a.X - b.X,
|
||||
Y: a.Y - b.Y,
|
||||
}
|
||||
}
|
||||
|
||||
func (v Vec3[T]) Dot(other Vec3[T]) T {
|
||||
return (v.X * other.X) + (v.Y * other.Y) + (v.Z * other.Z)
|
||||
}
|
||||
|
||||
func (v Vec3[T]) Len() T {
|
||||
return T(math.Sqrt(float64(v.LenSquared())))
|
||||
}
|
||||
|
||||
func (v Vec3[T]) LenSquared() T {
|
||||
return (v.X * v.X) + (v.Y * v.Y) + (v.Z * v.Z)
|
||||
}
|
||||
|
||||
func (v *Vec3[T]) Add(other Vec3[T]) {
|
||||
v.X += other.X
|
||||
v.Y += other.Y
|
||||
v.Z += other.Z
|
||||
}
|
||||
|
||||
func (v Vec3[T]) Equals(other Vec3[T]) bool {
|
||||
return v.X == other.X &&
|
||||
v.Y == other.Y &&
|
||||
v.Z == other.Z
|
||||
}
|
Reference in New Issue
Block a user