Day 9 solution

This day showed me that when the input instruction was introduced and said "write addresses will never be in immediate mode", that didn't mean "so don't bother handling modes for input addresses", it meant "handle the mode, but assert if it's immediate mode". It was super helpful that this program contained a bootstrap sequence to validate each instruction.

Memory expansion came with a few caveats: obviously reads and writes needed to handle expanding the memory space, but a Reset also can no longer get away with simply copying the program into memory again because we need to ensure that any additional memory is cut off (or at least zeroed), so the quickest way to handle that in Go is to simply allocate a new buffer; I'd rather manipulate the existing buffer, but I'm having a hard time finding the best way to do that.

And finally, make sure you reset your relativeBase when resetting the program...that one was ugly to track down.
This commit is contained in:
2022-06-09 23:33:48 -05:00
parent 2d6150e318
commit 0b3cdc2331
7 changed files with 122 additions and 39 deletions

42
days/09.go Normal file
View 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)
}

1
inputs/09p.txt Normal file
View 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
View 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
View File

@ -0,0 +1 @@
1102,34915192,34915192,7,4,7,99,0

1
inputs/09s3.txt Normal file
View File

@ -0,0 +1 @@
104,1125899906842624,99

View File

@ -39,6 +39,7 @@ var dayMap = []day{
&days.Day06{},
&days.Day07{},
&days.Day08{},
&days.Day09{},
}
func main() {

View File

@ -7,23 +7,26 @@ import (
)
const (
opAdd = 1
opMultiply = 2
opInput = 3
opOutput = 4
opJumpIfTrue = 5
opJumpIfFalse = 6
opLessThan = 7
opEquals = 8
opHalt = 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 struct {
memory []int64
program []int64
memory []int64
program []int64
relativeBase int
}
type IntcodeProgramState struct {
@ -74,34 +77,60 @@ func (p *IntcodeProgram) Copy() IntcodeProgram {
func (p *IntcodeProgram) init() {
if p.memory == nil {
p.memory = make([]int64, len(p.program))
p.Reset()
copy(p.memory, p.program)
}
}
func (p *IntcodeProgram) getParamValue(param, mode int) int64 {
switch mode {
case modePosition:
return p.memory[param]
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() {
@ -113,7 +142,7 @@ func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOut
inputsRequested := 0
for instructionPointer := 0; instructionPointer < len(p.program); {
instruction := p.memory[instructionPointer]
instruction := p.GetMemory(instructionPointer)
instructionPointer++
paramModes := [3]int{
@ -130,37 +159,37 @@ func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOut
opcode := instruction % 100
switch opcode {
case opAdd:
param1 := p.memory[instructionPointer]
param2 := p.memory[instructionPointer+1]
param3 := p.memory[instructionPointer+2]
p.memory[param3] = p.getParamValue(int(param1), paramModes[0]) + p.getParamValue(int(param2), paramModes[1])
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 opMultiply:
param1 := p.memory[instructionPointer]
param2 := p.memory[instructionPointer+1]
param3 := p.memory[instructionPointer+2]
p.memory[param3] = p.getParamValue(int(param1), paramModes[0]) * p.getParamValue(int(param2), paramModes[1])
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.memory[instructionPointer]
p.memory[param1] = inputFunc(inputsRequested)
param1 := p.GetMemory(instructionPointer)
p.setMemory(int(param1), inputFunc(inputsRequested), paramModes[0])
instructionPointer += 1
case opOutput:
param1 := p.memory[instructionPointer]
param1 := p.GetMemory(instructionPointer)
outputFunc(p.getParamValue(int(param1), paramModes[0]), p.makeState(instructionPointer))
instructionPointer += 1
case opJumpIfTrue:
param1 := p.memory[instructionPointer]
param2 := p.memory[instructionPointer+1]
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]))
@ -169,8 +198,8 @@ func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOut
}
case opJumpIfFalse:
param1 := p.memory[instructionPointer]
param2 := p.memory[instructionPointer+1]
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]))
@ -179,31 +208,38 @@ func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOut
}
case opLessThan:
param1 := p.memory[instructionPointer]
param2 := p.memory[instructionPointer+1]
param3 := p.memory[instructionPointer+2]
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.memory[param3] = 1
p.setMemory(int(param3), 1, paramModes[2])
} else {
p.memory[param3] = 0
p.setMemory(int(param3), 0, paramModes[2])
}
instructionPointer += 3
case opEquals:
param1 := p.memory[instructionPointer]
param2 := p.memory[instructionPointer+1]
param3 := p.memory[instructionPointer+2]
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.memory[param3] = 1
p.setMemory(int(param3), 1, paramModes[2])
} else {
p.memory[param3] = 0
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)