diff --git a/days/09.go b/days/09.go new file mode 100644 index 0000000..b80c82b --- /dev/null +++ b/days/09.go @@ -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) +} diff --git a/inputs/09p.txt b/inputs/09p.txt new file mode 100644 index 0000000..17a281f --- /dev/null +++ b/inputs/09p.txt @@ -0,0 +1 @@ +1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1101,0,3,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,252,1,1023,1102,36,1,1008,1102,24,1,1017,1101,25,0,1013,1102,479,1,1026,1101,0,259,1022,1102,1,38,1001,1102,1,713,1024,1101,0,708,1025,1102,1,22,1006,1101,0,32,1010,1101,476,0,1027,1102,1,516,1029,1102,1,34,1009,1101,0,23,1016,1102,1,37,1011,1102,525,1,1028,1101,0,35,1004,1102,31,1,1002,1102,39,1,1019,1102,28,1,1015,1102,1,1,1021,1101,0,30,1007,1101,0,27,1014,1101,21,0,1018,1101,0,29,1005,1102,26,1,1000,1102,1,0,1020,1101,0,20,1012,1101,33,0,1003,109,13,21108,40,40,6,1005,1019,199,4,187,1106,0,203,1001,64,1,64,1002,64,2,64,109,15,1205,-7,221,4,209,1001,64,1,64,1105,1,221,1002,64,2,64,109,-25,1208,-3,26,63,1005,63,243,4,227,1001,64,1,64,1106,0,243,1002,64,2,64,109,25,2105,1,-5,1001,64,1,64,1106,0,261,4,249,1002,64,2,64,109,-4,21108,41,42,-8,1005,1016,281,1001,64,1,64,1106,0,283,4,267,1002,64,2,64,109,-6,1206,2,301,4,289,1001,64,1,64,1105,1,301,1002,64,2,64,109,-4,21102,42,1,2,1008,1016,42,63,1005,63,323,4,307,1106,0,327,1001,64,1,64,1002,64,2,64,109,-7,2108,35,1,63,1005,63,343,1105,1,349,4,333,1001,64,1,64,1002,64,2,64,109,-13,1208,7,35,63,1005,63,369,1001,64,1,64,1106,0,371,4,355,1002,64,2,64,109,24,21102,43,1,-1,1008,1017,42,63,1005,63,391,1105,1,397,4,377,1001,64,1,64,1002,64,2,64,109,-13,2101,0,-4,63,1008,63,38,63,1005,63,419,4,403,1105,1,423,1001,64,1,64,1002,64,2,64,109,21,1206,-5,435,1106,0,441,4,429,1001,64,1,64,1002,64,2,64,109,-22,21101,44,0,10,1008,1014,44,63,1005,63,463,4,447,1105,1,467,1001,64,1,64,1002,64,2,64,109,25,2106,0,-2,1106,0,485,4,473,1001,64,1,64,1002,64,2,64,109,-19,2107,37,-2,63,1005,63,501,1106,0,507,4,491,1001,64,1,64,1002,64,2,64,109,8,2106,0,10,4,513,1001,64,1,64,1105,1,525,1002,64,2,64,109,-6,21107,45,46,0,1005,1012,547,4,531,1001,64,1,64,1105,1,547,1002,64,2,64,109,-5,1202,-1,1,63,1008,63,21,63,1005,63,567,1105,1,573,4,553,1001,64,1,64,1002,64,2,64,109,2,1207,-3,21,63,1005,63,589,1105,1,595,4,579,1001,64,1,64,1002,64,2,64,109,1,1201,-8,0,63,1008,63,34,63,1005,63,619,1001,64,1,64,1106,0,621,4,601,1002,64,2,64,109,-6,2102,1,-1,63,1008,63,33,63,1005,63,643,4,627,1105,1,647,1001,64,1,64,1002,64,2,64,109,10,21101,46,0,3,1008,1017,43,63,1005,63,667,1106,0,673,4,653,1001,64,1,64,1002,64,2,64,109,-13,2102,1,8,63,1008,63,35,63,1005,63,697,1001,64,1,64,1106,0,699,4,679,1002,64,2,64,109,23,2105,1,0,4,705,1105,1,717,1001,64,1,64,1002,64,2,64,109,-1,1205,-3,729,1106,0,735,4,723,1001,64,1,64,1002,64,2,64,109,-15,2101,0,0,63,1008,63,38,63,1005,63,755,1106,0,761,4,741,1001,64,1,64,1002,64,2,64,109,-2,2107,28,-1,63,1005,63,779,4,767,1106,0,783,1001,64,1,64,1002,64,2,64,109,-2,2108,35,0,63,1005,63,801,4,789,1105,1,805,1001,64,1,64,1002,64,2,64,109,1,1201,-5,0,63,1008,63,26,63,1005,63,831,4,811,1001,64,1,64,1105,1,831,1002,64,2,64,109,-5,1207,5,30,63,1005,63,849,4,837,1106,0,853,1001,64,1,64,1002,64,2,64,109,2,1202,-2,1,63,1008,63,26,63,1005,63,879,4,859,1001,64,1,64,1105,1,879,1002,64,2,64,109,15,21107,47,46,0,1005,1017,899,1001,64,1,64,1105,1,901,4,885,4,64,99,21102,1,27,1,21101,915,0,0,1106,0,922,21201,1,66416,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21102,942,1,0,1105,1,922,21202,1,1,-1,21201,-2,-3,1,21102,1,957,0,1105,1,922,22201,1,-1,-2,1105,1,968,22102,1,-2,-2,109,-3,2105,1,0 \ No newline at end of file diff --git a/inputs/09s1.txt b/inputs/09s1.txt new file mode 100644 index 0000000..521db73 --- /dev/null +++ b/inputs/09s1.txt @@ -0,0 +1 @@ +109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99 \ No newline at end of file diff --git a/inputs/09s2.txt b/inputs/09s2.txt new file mode 100644 index 0000000..ad18566 --- /dev/null +++ b/inputs/09s2.txt @@ -0,0 +1 @@ +1102,34915192,34915192,7,4,7,99,0 \ No newline at end of file diff --git a/inputs/09s3.txt b/inputs/09s3.txt new file mode 100644 index 0000000..78bddee --- /dev/null +++ b/inputs/09s3.txt @@ -0,0 +1 @@ +104,1125899906842624,99 \ No newline at end of file diff --git a/main.go b/main.go index d5bac69..8938fe1 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,7 @@ var dayMap = []day{ &days.Day06{}, &days.Day07{}, &days.Day08{}, + &days.Day09{}, } func main() { diff --git a/utilities/intcode.go b/utilities/intcode.go index f13196d..efdeb44 100644 --- a/utilities/intcode.go +++ b/utilities/intcode.go @@ -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)