finished day11-part1, Tweaks to Intcode compiler, Outputs is now []int type

This commit is contained in:
alexchao26
2020-08-04 00:58:22 -04:00
parent 936489e620
commit 2ac2f91236
5 changed files with 780 additions and 0 deletions
+1
View File
@@ -16,3 +16,4 @@ Day | Name | Type of Algo & Notes
8 | Space Image Format | 3D Array manipulation, pretty straight forward
9 | Sensor Boost | __MORE INTCODE. YAYY__ 🙃 <br> - A new parameter mode and opcode. <br> - __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
10 | Monitoring Station | - This (part2) is my favorite algo... Yes I have a favorite algo <br> Fundamentally it's a geometry problem, angles and trig <br> - Part 1: Calculated via slopes <br> - Part 2: Using Arctangent to find angles an asteroid makes against a vertical line from the home base asteroid. Then those angles can be used to determine if Asteroids are covering each other, AND iterating through all of them can find the next angle Asteroid to vaporize
11 | Space Police | - More Intcode stuff... <br>
+1
View File
@@ -0,0 +1 @@
3,8,1005,8,329,1106,0,11,0,0,0,104,1,104,0,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,0,10,4,10,1002,8,1,29,2,1102,1,10,1,1009,16,10,2,4,4,10,1,9,5,10,3,8,1002,8,-1,10,101,1,10,10,4,10,108,0,8,10,4,10,101,0,8,66,2,106,7,10,1006,0,49,3,8,1002,8,-1,10,101,1,10,10,4,10,108,1,8,10,4,10,1002,8,1,95,1006,0,93,3,8,102,-1,8,10,1001,10,1,10,4,10,108,1,8,10,4,10,102,1,8,120,1006,0,61,2,1108,19,10,2,1003,2,10,1006,0,99,3,8,1002,8,-1,10,1001,10,1,10,4,10,1008,8,0,10,4,10,101,0,8,157,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,1,10,4,10,1001,8,0,179,2,1108,11,10,1,1102,19,10,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,1,10,4,10,101,0,8,209,2,108,20,10,3,8,1002,8,-1,10,101,1,10,10,4,10,108,1,8,10,4,10,101,0,8,234,3,8,102,-1,8,10,101,1,10,10,4,10,108,0,8,10,4,10,1002,8,1,256,2,1102,1,10,1006,0,69,2,108,6,10,2,4,13,10,3,8,102,-1,8,10,101,1,10,10,4,10,1008,8,0,10,4,10,1002,8,1,294,1,1107,9,10,1006,0,87,2,1006,8,10,2,1001,16,10,101,1,9,9,1007,9,997,10,1005,10,15,99,109,651,104,0,104,1,21101,387395195796,0,1,21101,346,0,0,1105,1,450,21101,0,48210129704,1,21101,0,357,0,1105,1,450,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,46413147328,1,21102,404,1,0,1106,0,450,21102,179355823323,1,1,21101,415,0,0,1105,1,450,3,10,104,0,104,0,3,10,104,0,104,0,21102,1,838345843476,1,21101,0,438,0,1105,1,450,21101,709475709716,0,1,21101,449,0,0,1105,1,450,99,109,2,22102,1,-1,1,21102,40,1,2,21101,0,481,3,21101,0,471,0,1105,1,514,109,-2,2105,1,0,0,1,0,0,1,109,2,3,10,204,-1,1001,476,477,492,4,0,1001,476,1,476,108,4,476,10,1006,10,508,1101,0,0,476,109,-2,2106,0,0,0,109,4,2101,0,-1,513,1207,-3,0,10,1006,10,531,21101,0,0,-3,21201,-3,0,1,21201,-2,0,2,21101,1,0,3,21101,550,0,0,1105,1,555,109,-4,2106,0,0,109,5,1207,-3,1,10,1006,10,578,2207,-4,-2,10,1006,10,578,21201,-4,0,-4,1105,1,646,22101,0,-4,1,21201,-3,-1,2,21202,-2,2,3,21101,597,0,0,1105,1,555,22102,1,1,-4,21101,0,1,-1,2207,-4,-2,10,1006,10,616,21101,0,0,-1,22202,-2,-1,-2,2107,0,-3,10,1006,10,638,22102,1,-1,1,21101,638,0,0,106,0,513,21202,-2,-1,-2,22201,-4,-2,-4,109,-5,2106,0,0
+273
View File
@@ -0,0 +1,273 @@
/*
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`
robotBrain := MakeComputer(inputNumbers)
robot := MakeRobot(0, 0)
for robotBrain.IsRunning {
// get the current color from the robot's map
currentCoords := fmt.Sprintf("%v,%v", robot.x, robot.y)
currentColor := robot.MapCoordsToColor[currentCoords]
robotBrain.Step(currentColor)
// get outputs from the robot's brain (Intcode)
lenOutputs := len(robotBrain.Outputs)
color := robotBrain.Outputs[lenOutputs-2]
direction := robotBrain.Outputs[lenOutputs-1]
// "paint"/update robot's Map and move the robot
robot.MapCoordsToColor[currentCoords] = color
robot.MoveRobot(direction)
}
fmt.Printf("Tiles painted %v\n", len(robot.MapCoordsToColor))
}
// Robot struct, x and y are coordinate system based, NOT 2D array 0-indexed
type Robot struct {
x int
y int
Direction string
MapCoordsToColor map[string]int
}
// MakeRobot holds info on the location and direction of the robot only
func MakeRobot(startX, startY int) *Robot {
return &Robot{
startX,
startY,
"up",
make(map[string]int),
}
}
// MoveRobot moves the Robot
func (robot *Robot) MoveRobot(direction int) {
// direction is the same as the output from the robot brain
// i.e. 0 to turn left, 1 to turn right, then step forward 1 space
turnLeft := map[string]string{
"up": "left",
"left": "down",
"down": "right",
"right": "up",
}
turnRight := map[string]string{
"up": "right",
"right": "down",
"down": "left",
"left": "up",
}
if direction == 0 {
robot.Direction = turnLeft[robot.Direction]
} else {
robot.Direction = turnRight[robot.Direction]
}
switch robot.Direction {
case "up":
robot.y++
case "down":
robot.y--
case "left":
robot.x--
case "right":
robot.x++
}
}
/*
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 {
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
Outputs []int // stores all outputs
IsRunning bool // will be true until a 99 opcode is hit
}
// MakeComputer initializes a new comp
func MakeComputer(PuzzleInput []int) Intcode {
puzzleInputCopy := make([]int, len(PuzzleInput))
copy(puzzleInputCopy, PuzzleInput)
comp := Intcode{
puzzleInputCopy,
0,
0,
make([]int, 0),
true,
}
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.Outputs = append(comp.Outputs, 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
maxArg := sizes[0]
for _, v := range sizes {
if v > maxArg {
maxArg = v
}
}
// resize if PuzzleInput's length is shorter
if maxArg > len(comp.PuzzleInput) {
// make empty slice to copy into, of the new, larger size
resizedPuzzleInput := make([]int, maxArg+1)
// copy old puzzle input values in
copy(resizedPuzzleInput, comp.PuzzleInput)
// overwrite puzzle input
comp.PuzzleInput = resizedPuzzleInput
}
}
+281
View File
@@ -0,0 +1,281 @@
/*
IntcodeX 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 emergency hull painting robot's brain with a 0 for black tile
robotBrain := MakeComputerX(inputNumbers)
// make a robot to find the bounds of movement first
robot := MakeRobot(0, 0)
for robotBrain.IsRunning {
// a StepX produces two outputs
go robotBrain.StepX()
coords := fmt.Sprintf("%v,%v", robot.x, robot.y)
fmt.Println("writing to brain", coords, robot.MapCoordsToColor[coords])
robotBrain.InputChannel <- robot.MapCoordsToColor[coords]
color, direction := <-robotBrain.OutputChannel, <-robotBrain.OutputChannel
fmt.Printf("color %v, direction %v\n", color, direction)
// "paint" in the robot map, move the robot
robot.MapCoordsToColor[coords] = color
robot.MoveRobot(direction)
fmt.Println(robot)
}
// then make a 2D grid based on the bounds, then
fmt.Printf("Total tiles painted: %v\n", len(robot.MapCoordsToColor))
}
// Robot contains information on the emergency hill painting robot
type Robot struct {
x int
y int
Direction string
MapCoordsToColor map[string]int
}
// MakeRobot holds info on the location and direction of the robot only
func MakeRobot(startX, startY int) *Robot {
return &Robot{
startX,
startY,
"up",
make(map[string]int),
}
}
// MoveRobot moves the Robot
func (robot *Robot) MoveRobot(direction int) {
// direction is the same as the output from the robot brain
// i.e. 0 to turn left, 1 to turn right, then step forward 1 space
turnLeft := map[string]string{
"up": "left",
"left": "down",
"down": "right",
"right": "up",
}
turnRight := map[string]string{
"up": "right",
"right": "down",
"down": "left",
"left": "up",
}
if direction == 0 {
robot.Direction = turnLeft[robot.Direction]
} else {
robot.Direction = turnRight[robot.Direction]
}
switch robot.Direction {
case "up":
robot.y++
case "down":
robot.y--
case "left":
robot.x--
case "right":
robot.x++
}
}
/*
IntcodeX is an OOP approach *************************************************
MakeComputerX is equivalent to the constructor
StepX 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 IntcodeX struct {
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
InputChannel chan int // for inputs to computer
OutputChannel chan int // for recording all output
}
// MakeComputerX initializes a new comp
func MakeComputerX(puzzleInput []int) IntcodeX {
puzzleInputCopy := make([]int, len(puzzleInput))
copy(puzzleInputCopy, puzzleInput)
comp := IntcodeX{
puzzleInputCopy,
0,
0,
0,
true,
make(chan int),
make(chan int),
}
return comp
}
// StepX will read the next 4 values in the input `sli` and make updates
// according to the opcodes
func (comp *IntcodeX) StepX() {
// 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
// also close output channel
close(comp.OutputChannel)
case 1: // 1: Add next two paramIndexes, store in third
comp.PuzzleInput[param3] = comp.PuzzleInput[param1] + comp.PuzzleInput[param2]
comp.InstructionIndex += 4
go comp.StepX()
case 2: // 2: Multiply next two and store in third
comp.PuzzleInput[param3] = comp.PuzzleInput[param1] * comp.PuzzleInput[param2]
comp.InstructionIndex += 4
go comp.StepX()
case 3: // 3: Takes one input and saves it to position of one parameter
// read an input from input channel
input := <-comp.InputChannel
// else recurse with a -1 to signal the initial input has been processed
comp.PuzzleInput[param1] = input
comp.InstructionIndex += 2
go comp.StepX()
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
// write to output channel
comp.OutputChannel <- comp.LastOutput
// continue running until terminates or asks for another input
go comp.StepX()
// 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
}
go comp.StepX()
// 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
}
go comp.StepX()
// 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
go comp.StepX()
// 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
go comp.StepX()
// 9: adjust relative base
case 9:
comp.RelativeBase += comp.PuzzleInput[param1]
comp.InstructionIndex += 2
go comp.StepX()
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 *IntcodeX) 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 *IntcodeX) ResizeMemory(sizes ...int) {
fmt.Println("resizing", sizes)
// 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
}
}
+224
View File
@@ -0,0 +1,224 @@
/*
IntcodeY 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)
}
robotBrain := MakeComputerY(inputNumbers)
robotBrain.StepY(0)
robotBrain.StepY(0)
fmt.Println(robotBrain.Outputs)
}
// RobotY struct, x and y are coordinate system based, NOT 2D array 0-indexed
type RobotY struct {
x int
y int
Direction string
MapCoordsToColor map[string]int
}
// MakeRobotY holds info on the location and direction of the robot only
func MakeRobotY(startX, startY int) *RobotY {
return &RobotY{
startX,
startY,
"up",
make(map[string]int),
}
}
// MoveRobotY moves the RobotY
func (robot *RobotY) MoveRobotY(direction int) {
// direction is the same as the output from the robot brain
// i.e. 0 to turn left, 1 to turn right, then step forward 1 space
turnLeft := map[string]string{
"up": "left",
"left": "down",
"down": "right",
"right": "up",
}
turnRight := map[string]string{
"up": "right",
"right": "down",
"down": "left",
"left": "up",
}
if direction == 0 {
robot.Direction = turnLeft[robot.Direction]
} else {
robot.Direction = turnRight[robot.Direction]
}
switch robot.Direction {
case "up":
robot.y++
case "down":
robot.y--
case "left":
robot.x--
case "right":
robot.x++
}
}
/*
IntcodeY is an OOP approach *************************************************
MakeComputerY is equivalent to the constructor
StepY 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 IntcodeY struct {
PuzzleInput []int // file/puzzle input parsed into slice of ints
InstructionIndex int // stores the index where the next instruction is
Outputs []int // all outputs stored in order
IsRunning bool // will be true until a 99 opcode is hit
}
// MakeComputerY initializes a new comp
func MakeComputerY(PuzzleInput []int) IntcodeY {
puzzleInputCopy := make([]int, len(PuzzleInput))
copy(puzzleInputCopy, PuzzleInput)
comp := IntcodeY{
puzzleInputCopy,
0,
make([]int, 0),
true,
}
return comp
}
// StepY will read the next 4 values in the input `sli` and make updates
// according to the opcodes
func (comp *IntcodeY) StepY(input int) {
// read the instruction, opcode and the indexes where the params point to
opcode, paramIndexes := comp.GetOpCodeAndParamIndexesY()
param1, param2, param3 := paramIndexes[0], paramIndexes[1], paramIndexes[2]
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.StepY(input)
case 2: // 2: Multiply next two and store in third
comp.PuzzleInput[param3] = comp.PuzzleInput[param1] * comp.PuzzleInput[param2]
comp.InstructionIndex += 4
comp.StepY(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.StepY(-1)
case 4: // 4: outputs its input value
// set LastOutput of the computer & log it
comp.Outputs = append(comp.Outputs, 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.StepY(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.StepY(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.StepY(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.StepY(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.StepY(input)
default:
log.Fatalf("Error: unknown opcode %v at index %v", opcode, comp.PuzzleInput[comp.InstructionIndex])
}
}
/*
GetOpCodeAndParamIndexesY 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 *IntcodeY) GetOpCodeAndParamIndexesY() (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
}
}
return opcode, paramIndexes
}