diff --git a/README.md b/README.md
index d493891..dc4e323 100644
--- a/README.md
+++ b/README.md
@@ -14,4 +14,4 @@ Day | Name | Type of Algo & Notes
6 | Universal Orbit Map | - __Tree traversal__ and depth calculations. It's not quite a Graph, but it has a __directed graph__ algo feel too
7 | Amplification Circuit | - More Intcode... Piping together multiple Intcode computers 😳😳😳
- Refactored Intcode computer to an OOP approach so a single computer maintains its data
- Also requires making __permutations generator__
- Some gymnastics to make this circular, but its easier with this OOP approach and the "objects"/instances of a struct maintaining their own data
- Concurrency could be used to sync these Amps together...
8 | Space Image Format | 3D Array manipulation, pretty straight forward
-9 | Sensor Boost | __MORE INTCODE. YAYY__ 🙃
- A new parameter mode and opcode.
- __Really feeling the (tech) debt of some earlier design choices here, went back to refactor day07 before jumping into this one__
+9 | Sensor Boost | __MORE INTCODE. YAYY__ 🙃
- A new parameter mode and opcode.
- __Really feeling the (tech) debt of some earlier design choices here, went back to refactor day07 before jumping into this one__, then it was a small bit of code for the relative param/opcode & resizing computer memory if necessary
diff --git a/day09/part1/input.txt b/day09/input.txt
similarity index 100%
rename from day09/part1/input.txt
rename to day09/input.txt
diff --git a/day09/part1/main.go b/day09/part1/main.go
index 93b8518..bf87cf0 100644
--- a/day09/part1/main.go
+++ b/day09/part1/main.go
@@ -1,158 +1,210 @@
+/*
+Intcode struct is defined within this file
+MakePermutations is in the util package as that will likely be reused
+*/
+
package main
-import "fmt"
-
-func returnCodes(number int) (int, int, int, int) {
- return number % 100, (number % 1000) / 100, (number % 10000) / 1000, (number % 100000) / 10000
-}
-
-func getValue(puzzleInput []int, parameterCode, nextOrTwoPastValue, relativeValue int) int {
- // fmt.Println("in getValues", parameterCode, nextOrTwoPastValue, relativeValue)
- if parameterCode == 0 {
- // 0 is position mode
- return puzzleInput[nextOrTwoPastValue]
- }
- if parameterCode == 1 {
- // 1 is immediate mode (no-else-return)
- return nextOrTwoPastValue
- }
- // 2 is relative mode...
- sum := nextOrTwoPastValue + relativeValue
- if sum >= len(puzzleInput) {
- puzzleInput = resize(puzzleInput, sum)
- }
- return puzzleInput[sum]
-}
-
-func runDiagnostics(puzzleInput []int, inputValue int) string {
- // fmt.Println(puzzleInput)
-
- var relativeValue int // nil value of zero
-
- for i := 0; i < len(puzzleInput); {
- // find op code (last 2 digits of number), a 1, 2, 3, 4, or 99
- // find param1 and param2 which are the 100's and 1000's digit in the i-th element
- opCode, param1, param2, _ := returnCodes(puzzleInput[i])
- var firstVal, secondVal, thirdVal int
-
- // set value variables based on what the opCodes are (some of them will throw errors if I attempt to set them...)
- if opCode == 1 || opCode == 2 || opCode == 7 || opCode == 8 {
- firstVal, secondVal = getValue(puzzleInput, param1, puzzleInput[i+1], relativeValue), getValue(puzzleInput, param2, puzzleInput[i+2], relativeValue)
- thirdVal = puzzleInput[i+3]
- } else if opCode == 3 || opCode == 4 {
- firstVal = puzzleInput[i+1]
- } else if opCode == 5 || opCode == 6 {
- firstVal, secondVal = getValue(puzzleInput, param1, puzzleInput[i+1], relativeValue), getValue(puzzleInput, param2, puzzleInput[i+2], relativeValue)
- } else if opCode == 9 {
- // not actually sure what I need to do here...
- firstVal = getValue(puzzleInput, param1, puzzleInput[i+1], relativeValue)
- }
-
- // fmt.Println("desired specs", opCode, firstVal, thirdVal)
-
- // switch statement to handle the opcode value
- switch opCode {
- case 99:
- // fmt.Println("99 halted at index: ", i)
- return "halted"
- case 1:
- // add and place (by position)
- // firstToAdd, secondToAdd := getValue(puzzleInput, param1, puzzleInput[i+1]), getValue(puzzleInput, param2, puzzleInput[i+2])
- if thirdVal >= len(puzzleInput) {
- puzzleInput = resize(puzzleInput, thirdVal)
- }
- puzzleInput[thirdVal] = firstVal + secondVal
- i += 4
- case 2:
- // multiply and place (by position)
- if thirdVal >= len(puzzleInput) {
- puzzleInput = resize(puzzleInput, thirdVal)
- }
- puzzleInput[thirdVal] = firstVal * secondVal
- i += 4
- case 3:
- // write inputValue to puzzle input by position
- if firstVal >= len(puzzleInput) {
- puzzleInput = resize(puzzleInput, firstVal)
- }
- puzzleInput[firstVal] = inputValue
- i += 2
- case 4:
- // output the value to the console, always by position
- fmt.Println("output: ", puzzleInput[firstVal])
- i += 2
- case 5:
- // jump-if-true
- // if first param is != 0 set instruction pointer to value from second parameter
- if firstVal != 0 {
- // fmt.Println("5 moves i to", secondVal)
- i = secondVal
- } else {
- // otherwise do nothing except increment i
- // increment by 3 (like opCode 6)
- i += 3
- }
- case 6:
- // jump-if-false
- // if first param is != 0 set instruction pointer to value from second parameter
- if firstVal == 0 {
- i = secondVal
- } else {
- // otherwise increment i to the next instruction
- // this instruction has 3 values, so i increments by 3
- i += 3
- }
- case 7:
- // less than - if firstVal < secondVal, store a 1 @ position of thirdVal, otherwise store a 0
- if firstVal < secondVal {
- puzzleInput[thirdVal] = 1
- } else {
- puzzleInput[thirdVal] = 0
- }
- i += 4
- case 8:
- // equals, same as opCode 7 but conditional is firstVal is equal to secondVal
- if firstVal == secondVal {
- puzzleInput[thirdVal] = 1
- } else {
- puzzleInput[thirdVal] = 0
- }
- i += 4
- case 9:
- // relativeValue += puzzleInput[i+1]
- relativeValue += firstVal
- // fmt.Print("relative value op code")
- i += 2
- default:
- fmt.Println("bad opCode!!!")
- return "badCode"
- }
- }
- return "EOF"
-}
+import (
+ "adventofcode/util"
+ "fmt"
+ "log"
+ "strconv"
+ "strings"
+)
func main() {
- // puzzle input as a slice
- puzzleInput := []int{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, 1101, 27, 0, 1014, 1101, 286, 0, 1023, 1102, 1, 35, 1018, 1102, 20, 1, 1000, 1101, 26, 0, 1010, 1101, 0, 289, 1022, 1102, 1, 30, 1019, 1102, 734, 1, 1025, 1102, 1, 31, 1012, 1101, 25, 0, 1001, 1102, 1, 1, 1021, 1101, 0, 36, 1002, 1101, 0, 527, 1028, 1101, 895, 0, 1026, 1102, 1, 23, 1016, 1101, 21, 0, 1003, 1102, 22, 1, 1011, 1102, 1, 522, 1029, 1102, 1, 892, 1027, 1102, 1, 0, 1020, 1102, 1, 28, 1015, 1102, 38, 1, 1006, 1101, 0, 32, 1008, 1101, 743, 0, 1024, 1101, 0, 37, 1007, 1102, 1, 24, 1013, 1102, 1, 33, 1009, 1102, 39, 1, 1004, 1102, 1, 34, 1005, 1102, 1, 29, 1017, 109, 19, 21102, 40, 1, -3, 1008, 1016, 40, 63, 1005, 63, 203, 4, 187, 1106, 0, 207, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, -7, 2101, 0, -7, 63, 1008, 63, 32, 63, 1005, 63, 227, 1106, 0, 233, 4, 213, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, -3, 2108, 37, -2, 63, 1005, 63, 255, 4, 239, 1001, 64, 1, 64, 1105, 1, 255, 1002, 64, 2, 64, 109, 11, 21108, 41, 40, -6, 1005, 1014, 275, 1001, 64, 1, 64, 1106, 0, 277, 4, 261, 1002, 64, 2, 64, 109, 10, 2105, 1, -7, 1105, 1, 295, 4, 283, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, -27, 1201, -2, 0, 63, 1008, 63, 25, 63, 1005, 63, 321, 4, 301, 1001, 64, 1, 64, 1105, 1, 321, 1002, 64, 2, 64, 109, 15, 21107, 42, 41, 0, 1005, 1018, 341, 1001, 64, 1, 64, 1106, 0, 343, 4, 327, 1002, 64, 2, 64, 109, -25, 2108, 20, 10, 63, 1005, 63, 359, 1105, 1, 365, 4, 349, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, 12, 2107, 35, 0, 63, 1005, 63, 385, 1001, 64, 1, 64, 1106, 0, 387, 4, 371, 1002, 64, 2, 64, 109, 4, 21101, 43, 0, 6, 1008, 1015, 43, 63, 1005, 63, 409, 4, 393, 1106, 0, 413, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, 9, 21101, 44, 0, -8, 1008, 1010, 46, 63, 1005, 63, 437, 1001, 64, 1, 64, 1106, 0, 439, 4, 419, 1002, 64, 2, 64, 109, 5, 21108, 45, 45, -4, 1005, 1019, 457, 4, 445, 1106, 0, 461, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, -22, 2102, 1, 7, 63, 1008, 63, 33, 63, 1005, 63, 481, 1106, 0, 487, 4, 467, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, 14, 21102, 46, 1, -1, 1008, 1014, 43, 63, 1005, 63, 507, 1106, 0, 513, 4, 493, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, 12, 2106, 0, 1, 4, 519, 1106, 0, 531, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, -17, 1205, 10, 547, 1001, 64, 1, 64, 1106, 0, 549, 4, 537, 1002, 64, 2, 64, 109, -8, 1202, -2, 1, 63, 1008, 63, 17, 63, 1005, 63, 569, 1105, 1, 575, 4, 555, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, 23, 1206, -5, 593, 4, 581, 1001, 64, 1, 64, 1105, 1, 593, 1002, 64, 2, 64, 109, -14, 1208, -8, 24, 63, 1005, 63, 613, 1001, 64, 1, 64, 1105, 1, 615, 4, 599, 1002, 64, 2, 64, 109, -2, 1207, -1, 33, 63, 1005, 63, 633, 4, 621, 1105, 1, 637, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, 2, 21107, 47, 48, 5, 1005, 1016, 659, 4, 643, 1001, 64, 1, 64, 1105, 1, 659, 1002, 64, 2, 64, 109, -11, 1208, 8, 32, 63, 1005, 63, 681, 4, 665, 1001, 64, 1, 64, 1106, 0, 681, 1002, 64, 2, 64, 109, 2, 2101, 0, 0, 63, 1008, 63, 36, 63, 1005, 63, 703, 4, 687, 1106, 0, 707, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, 12, 1206, 7, 719, 1106, 0, 725, 4, 713, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, 2, 2105, 1, 8, 4, 731, 1001, 64, 1, 64, 1106, 0, 743, 1002, 64, 2, 64, 109, -21, 2102, 1, 9, 63, 1008, 63, 39, 63, 1005, 63, 769, 4, 749, 1001, 64, 1, 64, 1105, 1, 769, 1002, 64, 2, 64, 109, 11, 1201, -3, 0, 63, 1008, 63, 24, 63, 1005, 63, 793, 1001, 64, 1, 64, 1105, 1, 795, 4, 775, 1002, 64, 2, 64, 109, 20, 1205, -5, 809, 4, 801, 1105, 1, 813, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, -23, 1207, 4, 36, 63, 1005, 63, 833, 1001, 64, 1, 64, 1105, 1, 835, 4, 819, 1002, 64, 2, 64, 109, -3, 2107, 33, 5, 63, 1005, 63, 853, 4, 841, 1106, 0, 857, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, 16, 1202, -9, 1, 63, 1008, 63, 37, 63, 1005, 63, 879, 4, 863, 1105, 1, 883, 1001, 64, 1, 64, 1002, 64, 2, 64, 109, 12, 2106, 0, -1, 1105, 1, 901, 4, 889, 1001, 64, 1, 64, 4, 64, 99, 21101, 0, 27, 1, 21101, 0, 915, 0, 1106, 0, 922, 21201, 1, 48476, 1, 204, 1, 99, 109, 3, 1207, -2, 3, 63, 1005, 63, 964, 21201, -2, -1, 1, 21101, 0, 942, 0, 1105, 1, 922, 21202, 1, 1, -1, 21201, -2, -3, 1, 21101, 0, 957, 0, 1105, 1, 922, 22201, 1, -1, -2, 1106, 0, 968, 21202, -2, 1, -2, 109, -3, 2106, 0, 0}
+ // read the input file, modify it to a slice of numbers
+ inputFile := util.ReadFile("../input.txt")
- // tests
- // some 16 digit number
- // puzzleInput := []int{1102, 34915192, 34915192, 7, 4, 7, 99, 0}
+ splitStrings := strings.Split(inputFile, ",")
- // the middle number
- // puzzleInput := []int{104, 1125899906842624, 99}
+ inputNumbers := make([]int, len(splitStrings))
+ for i, v := range splitStrings {
+ inputNumbers[i], _ = strconv.Atoi(v)
+ }
- // Part 1: ID of System is 1 (use as the input)
- runDiagnostics(puzzleInput, 1)
-
- // Part 2: ID of System is 5 (use as the input)
- // runDiagnostics(puzzleInput, 5)
+ // initialize a computer with a test mode input of `1`
+ comp := MakeComputer(inputNumbers, 1)
+ fmt.Println("BOOST keycode is", comp.LastOutput)
}
-// reize function
-func resize(puzzle []int, newSize int) []int {
- result := make([]int, newSize+1)
- copy(result, puzzle)
- // fmt.Println(len(puzzle), len(result))
- return result
+/*
+Intcode is an OOP approach *************************************************
+MakeComputer is equivalent to the constructor
+Step takes in an input int and updates properties in the computer:
+ - InstructionIndex: where to read the next instruction from
+ - LastOutput, what the last opcode 4 outputted
+ - PuzzleIndex based if the last instruction modified the puzzle at all
+****************************************************************************/
+type Intcode struct {
+ PhaseSetting int // initial input: ID or number used to "prime"/setup the comp
+ PuzzleInput []int // file/puzzle input parsed into slice of ints
+ InstructionIndex int // stores the index where the next instruction is
+ RelativeBase int // relative base for opcode 9 and param mode 2
+ LastOutput int // last output from an opcode 4
+ IsRunning bool // will be true until a 99 opcode is hit
+}
+
+// MakeComputer initializes a new comp
+func MakeComputer(PuzzleInput []int, PhaseSetting int) Intcode {
+ puzzleInputCopy := make([]int, len(PuzzleInput))
+ copy(puzzleInputCopy, PuzzleInput)
+
+ comp := Intcode{
+ PhaseSetting,
+ puzzleInputCopy,
+ 0,
+ 0,
+ 0,
+ true,
+ }
+
+ // Prime the computer by running its initial phase setting through it
+ // This will update the comp's InstructionIndex so it's pointing to the next command
+ // will also update the PuzzleInput itself via opcode 3's insert
+ // AND will run the computer until it asks for the next input, _comp is now primed_
+ comp.Step(PhaseSetting)
+ return comp
+}
+
+// Step will read the next 4 values in the input `sli` and make updates
+// according to the opcodes
+func (comp *Intcode) Step(input int) {
+ // read the instruction, opcode and the indexes where the params point to
+ opcode, paramIndexes := comp.GetOpCodeAndParamIndexes()
+ param1, param2, param3 := paramIndexes[0], paramIndexes[1], paramIndexes[2]
+
+ // ensure params are within the bounds of PuzzleInput, resize if necessary
+ comp.ResizeMemory(param1, param2, param3)
+
+ switch opcode {
+ case 99: // 99: Terminates program
+ // fmt.Println("Terminating...")
+ comp.IsRunning = false
+ case 1: // 1: Add next two paramIndexes, store in third
+ comp.PuzzleInput[param3] = comp.PuzzleInput[param1] + comp.PuzzleInput[param2]
+ comp.InstructionIndex += 4
+ comp.Step(input)
+ case 2: // 2: Multiply next two and store in third
+ comp.PuzzleInput[param3] = comp.PuzzleInput[param1] * comp.PuzzleInput[param2]
+ comp.InstructionIndex += 4
+ comp.Step(input)
+ case 3: // 3: Takes one input and saves it to position of one parameter
+ // check if input has already been used (i.e. input == -1)
+ // if it's been used, return out to prevent further Steps
+ // NOTE: making a big assumption that -1 will never be an input...
+ if input == -1 {
+ return
+ }
+
+ // else recurse with a -1 to signal the initial input has been processed
+ comp.PuzzleInput[param1] = input
+ comp.InstructionIndex += 2
+ comp.Step(-1)
+ case 4: // 4: outputs its input value
+ // set LastOutput of the computer & log it
+ comp.LastOutput = comp.PuzzleInput[param1]
+ // fmt.Printf("Opcode 4 output: %v\n", comp.LastOutput)
+ comp.InstructionIndex += 2
+
+ // continue running until terminates or asks for another input
+ comp.Step(input)
+ // 5: jump-if-true: if first param != 0, move pointer to second param, else nothing
+ case 5:
+ if comp.PuzzleInput[param1] != 0 {
+ comp.InstructionIndex = comp.PuzzleInput[param2]
+ } else {
+ comp.InstructionIndex += 3
+ }
+ comp.Step(input)
+ // 6: jump-if-false, if first param == 0 then set instruction pointer to 2nd param, else nothing
+ case 6:
+ if comp.PuzzleInput[param1] == 0 {
+ comp.InstructionIndex = comp.PuzzleInput[param2]
+ } else {
+ comp.InstructionIndex += 3
+ }
+ comp.Step(input)
+ // 7: less-than, if param1 < param2 then store 1 in postion of 3rd param, else store 0
+ case 7:
+ if comp.PuzzleInput[param1] < comp.PuzzleInput[param2] {
+ comp.PuzzleInput[param3] = 1
+ } else {
+ comp.PuzzleInput[param3] = 0
+ }
+ comp.InstructionIndex += 4
+ comp.Step(input)
+ // 8: equals, if param1 == param2 then set position of 3rd param to 1, else store 0
+ case 8:
+ if comp.PuzzleInput[param1] == comp.PuzzleInput[param2] {
+ comp.PuzzleInput[param3] = 1
+ } else {
+ comp.PuzzleInput[param3] = 0
+ }
+ comp.InstructionIndex += 4
+ comp.Step(input)
+ // 9: adjust relative base
+ case 9:
+ comp.RelativeBase += comp.PuzzleInput[param1]
+ comp.InstructionIndex += 2
+ comp.Step(input)
+ default:
+ log.Fatalf("Error: unknown opcode %v at index %v", opcode, comp.PuzzleInput[comp.InstructionIndex])
+ }
+}
+
+/*
+GetOpCodeAndParamIndexes will parse the instruction at comp.PuzzleInput[comp.InstructionIndex]
+- opcode will be the left two digits, mod by 100 will get that
+- rest of instructions will be grabbed via mod 10
+ - these also have to be parsed for the
+*/
+func (comp *Intcode) GetOpCodeAndParamIndexes() (int, [3]int) {
+ instruction := comp.PuzzleInput[comp.InstructionIndex]
+
+ // opcode is the lowest two digits, so mod by 100
+ opcode := instruction % 100
+ instruction /= 100
+
+ // assign the indexes that need to be read by reading the parameter modes
+ var paramIndexes [3]int
+ for i := 1; i <= 3 && comp.InstructionIndex+i < len(comp.PuzzleInput); i++ {
+ // grab the mode with a mod, last digit
+ mode := instruction % 10
+ instruction /= 10
+
+ switch mode {
+ case 0: // position mode, index will be the value at the index
+ paramIndexes[i-1] = comp.PuzzleInput[comp.InstructionIndex+i]
+ case 1: // immediate mode, the index itself
+ paramIndexes[i-1] = comp.InstructionIndex + i
+ case 2: // relative mode, like position mode but index is added to relative base
+ paramIndexes[i-1] = comp.PuzzleInput[comp.InstructionIndex+i] + comp.RelativeBase
+ }
+ }
+
+ return opcode, paramIndexes
+}
+
+// ResizeMemory will take any number of integers and resize the computer's memory appropriately
+func (comp *Intcode) ResizeMemory(sizes ...int) {
+ // get largest of input sizes
+ maxArgSize := sizes[0]
+ for _, v := range sizes {
+ if v > maxArgSize {
+ maxArgSize = v
+ }
+ }
+
+ // resize if PuzzleInput's length is shorter
+ if maxArgSize > len(comp.PuzzleInput) {
+ // make empty slice to copy into, of the new, larger size
+ resizedPuzzleInput := make([]int, maxArgSize)
+ // copy old puzzle input values in
+ copy(resizedPuzzleInput, comp.PuzzleInput)
+
+ // overwrite puzzle input
+ comp.PuzzleInput = resizedPuzzleInput
+ }
}
diff --git a/day09/part2/main.go b/day09/part2/main.go
new file mode 100644
index 0000000..58a07a5
--- /dev/null
+++ b/day09/part2/main.go
@@ -0,0 +1,210 @@
+/*
+Intcode struct is defined within this file
+MakePermutations is in the util package as that will likely be reused
+*/
+
+package main
+
+import (
+ "adventofcode/util"
+ "fmt"
+ "log"
+ "strconv"
+ "strings"
+)
+
+func main() {
+ // read the input file, modify it to a slice of numbers
+ inputFile := util.ReadFile("../input.txt")
+
+ splitStrings := strings.Split(inputFile, ",")
+
+ inputNumbers := make([]int, len(splitStrings))
+ for i, v := range splitStrings {
+ inputNumbers[i], _ = strconv.Atoi(v)
+ }
+
+ // initialize a computer with a senor boost input of `2`
+ comp := MakeComputer(inputNumbers, 2)
+ fmt.Println("BOOST keycode is", comp.LastOutput)
+}
+
+/*
+Intcode is an OOP approach *************************************************
+MakeComputer is equivalent to the constructor
+Step takes in an input int and updates properties in the computer:
+ - InstructionIndex: where to read the next instruction from
+ - LastOutput, what the last opcode 4 outputted
+ - PuzzleIndex based if the last instruction modified the puzzle at all
+****************************************************************************/
+type Intcode struct {
+ PhaseSetting int // initial input: ID or number used to "prime"/setup the comp
+ PuzzleInput []int // file/puzzle input parsed into slice of ints
+ InstructionIndex int // stores the index where the next instruction is
+ RelativeBase int // relative base for opcode 9 and param mode 2
+ LastOutput int // last output from an opcode 4
+ IsRunning bool // will be true until a 99 opcode is hit
+}
+
+// MakeComputer initializes a new comp
+func MakeComputer(PuzzleInput []int, PhaseSetting int) Intcode {
+ puzzleInputCopy := make([]int, len(PuzzleInput))
+ copy(puzzleInputCopy, PuzzleInput)
+
+ comp := Intcode{
+ PhaseSetting,
+ puzzleInputCopy,
+ 0,
+ 0,
+ 0,
+ true,
+ }
+
+ // Prime the computer by running its initial phase setting through it
+ // This will update the comp's InstructionIndex so it's pointing to the next command
+ // will also update the PuzzleInput itself via opcode 3's insert
+ // AND will run the computer until it asks for the next input, _comp is now primed_
+ comp.Step(PhaseSetting)
+ return comp
+}
+
+// Step will read the next 4 values in the input `sli` and make updates
+// according to the opcodes
+func (comp *Intcode) Step(input int) {
+ // read the instruction, opcode and the indexes where the params point to
+ opcode, paramIndexes := comp.GetOpCodeAndParamIndexes()
+ param1, param2, param3 := paramIndexes[0], paramIndexes[1], paramIndexes[2]
+
+ // ensure params are within the bounds of PuzzleInput, resize if necessary
+ comp.ResizeMemory(param1, param2, param3)
+
+ switch opcode {
+ case 99: // 99: Terminates program
+ // fmt.Println("Terminating...")
+ comp.IsRunning = false
+ case 1: // 1: Add next two paramIndexes, store in third
+ comp.PuzzleInput[param3] = comp.PuzzleInput[param1] + comp.PuzzleInput[param2]
+ comp.InstructionIndex += 4
+ comp.Step(input)
+ case 2: // 2: Multiply next two and store in third
+ comp.PuzzleInput[param3] = comp.PuzzleInput[param1] * comp.PuzzleInput[param2]
+ comp.InstructionIndex += 4
+ comp.Step(input)
+ case 3: // 3: Takes one input and saves it to position of one parameter
+ // check if input has already been used (i.e. input == -1)
+ // if it's been used, return out to prevent further Steps
+ // NOTE: making a big assumption that -1 will never be an input...
+ if input == -1 {
+ return
+ }
+
+ // else recurse with a -1 to signal the initial input has been processed
+ comp.PuzzleInput[param1] = input
+ comp.InstructionIndex += 2
+ comp.Step(-1)
+ case 4: // 4: outputs its input value
+ // set LastOutput of the computer & log it
+ comp.LastOutput = comp.PuzzleInput[param1]
+ // fmt.Printf("Opcode 4 output: %v\n", comp.LastOutput)
+ comp.InstructionIndex += 2
+
+ // continue running until terminates or asks for another input
+ comp.Step(input)
+ // 5: jump-if-true: if first param != 0, move pointer to second param, else nothing
+ case 5:
+ if comp.PuzzleInput[param1] != 0 {
+ comp.InstructionIndex = comp.PuzzleInput[param2]
+ } else {
+ comp.InstructionIndex += 3
+ }
+ comp.Step(input)
+ // 6: jump-if-false, if first param == 0 then set instruction pointer to 2nd param, else nothing
+ case 6:
+ if comp.PuzzleInput[param1] == 0 {
+ comp.InstructionIndex = comp.PuzzleInput[param2]
+ } else {
+ comp.InstructionIndex += 3
+ }
+ comp.Step(input)
+ // 7: less-than, if param1 < param2 then store 1 in postion of 3rd param, else store 0
+ case 7:
+ if comp.PuzzleInput[param1] < comp.PuzzleInput[param2] {
+ comp.PuzzleInput[param3] = 1
+ } else {
+ comp.PuzzleInput[param3] = 0
+ }
+ comp.InstructionIndex += 4
+ comp.Step(input)
+ // 8: equals, if param1 == param2 then set position of 3rd param to 1, else store 0
+ case 8:
+ if comp.PuzzleInput[param1] == comp.PuzzleInput[param2] {
+ comp.PuzzleInput[param3] = 1
+ } else {
+ comp.PuzzleInput[param3] = 0
+ }
+ comp.InstructionIndex += 4
+ comp.Step(input)
+ // 9: adjust relative base
+ case 9:
+ comp.RelativeBase += comp.PuzzleInput[param1]
+ comp.InstructionIndex += 2
+ comp.Step(input)
+ default:
+ log.Fatalf("Error: unknown opcode %v at index %v", opcode, comp.PuzzleInput[comp.InstructionIndex])
+ }
+}
+
+/*
+GetOpCodeAndParamIndexes will parse the instruction at comp.PuzzleInput[comp.InstructionIndex]
+- opcode will be the left two digits, mod by 100 will get that
+- rest of instructions will be grabbed via mod 10
+ - these also have to be parsed for the
+*/
+func (comp *Intcode) GetOpCodeAndParamIndexes() (int, [3]int) {
+ instruction := comp.PuzzleInput[comp.InstructionIndex]
+
+ // opcode is the lowest two digits, so mod by 100
+ opcode := instruction % 100
+ instruction /= 100
+
+ // assign the indexes that need to be read by reading the parameter modes
+ var paramIndexes [3]int
+ for i := 1; i <= 3 && comp.InstructionIndex+i < len(comp.PuzzleInput); i++ {
+ // grab the mode with a mod, last digit
+ mode := instruction % 10
+ instruction /= 10
+
+ switch mode {
+ case 0: // position mode, index will be the value at the index
+ paramIndexes[i-1] = comp.PuzzleInput[comp.InstructionIndex+i]
+ case 1: // immediate mode, the index itself
+ paramIndexes[i-1] = comp.InstructionIndex + i
+ case 2: // relative mode, like position mode but index is added to relative base
+ paramIndexes[i-1] = comp.PuzzleInput[comp.InstructionIndex+i] + comp.RelativeBase
+ }
+ }
+
+ return opcode, paramIndexes
+}
+
+// ResizeMemory will take any number of integers and resize the computer's memory appropriately
+func (comp *Intcode) ResizeMemory(sizes ...int) {
+ // get largest of input sizes
+ maxArgSize := sizes[0]
+ for _, v := range sizes {
+ if v > maxArgSize {
+ maxArgSize = v
+ }
+ }
+
+ // resize if PuzzleInput's length is shorter
+ if maxArgSize > len(comp.PuzzleInput) {
+ // make empty slice to copy into, of the new, larger size
+ resizedPuzzleInput := make([]int, maxArgSize)
+ // copy old puzzle input values in
+ copy(resizedPuzzleInput, comp.PuzzleInput)
+
+ // overwrite puzzle input
+ comp.PuzzleInput = resizedPuzzleInput
+ }
+}