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..1525196 --- /dev/null +++ b/inputs/09p.txt @@ -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 \ 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)