mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-05-18 19:13:27 +02:00
added day17 solutions. refactor needed to make Intcode algo iterative for gui output
This commit is contained in:
@@ -23,3 +23,5 @@ Day | Name | Type of Algo & Notes
|
|||||||
14 | Space Stoichiometry | __Weighted Graph and Breadth First Traversals__ <br> - Because not all of the products have a quantity of 1, it complicates the graph's data model. I ended up mapping the product/chemical name to a map of its stoichiometry where the product's number is positive & reactants were negative. <br> - part2: not just a simple division because of "extra byproducts" of generating each piece of fuel. I just let this brute force thing run for ~30 seconds...
|
14 | Space Stoichiometry | __Weighted Graph and Breadth First Traversals__ <br> - Because not all of the products have a quantity of 1, it complicates the graph's data model. I ended up mapping the product/chemical name to a map of its stoichiometry where the product's number is positive & reactants were negative. <br> - part2: not just a simple division because of "extra byproducts" of generating each piece of fuel. I just let this brute force thing run for ~30 seconds...
|
||||||
15 | Oxygen System | YAY INTCODE 🙄 <br> - Combination of __2D grid searching algo__, __backtracking algo__ and the the Intcode... <br> - I've realized that I really need to stop using x and y for 2D grids and start using row and col because mathematically x is horizontal and y is vertical... My brain is all jumbled up <br> - Created a Robot struct/class that has a computer inside of it. It goes and searches around, collecting data on the floor types at various coordinates. That data is transformed into a 2D grid/array, and then finally fed into a backtracking, searching algorithm to determine the shortest path (turns out there's only one path to the O2 tank...) <br> - part2 is fairly straight forward 2D grid traversing and tagging a spread of oxygen to valid tiles/hallway spaces
|
15 | Oxygen System | YAY INTCODE 🙄 <br> - Combination of __2D grid searching algo__, __backtracking algo__ and the the Intcode... <br> - I've realized that I really need to stop using x and y for 2D grids and start using row and col because mathematically x is horizontal and y is vertical... My brain is all jumbled up <br> - Created a Robot struct/class that has a computer inside of it. It goes and searches around, collecting data on the floor types at various coordinates. That data is transformed into a 2D grid/array, and then finally fed into a backtracking, searching algorithm to determine the shortest path (turns out there's only one path to the O2 tank...) <br> - part2 is fairly straight forward 2D grid traversing and tagging a spread of oxygen to valid tiles/hallway spaces
|
||||||
16 | Flawed Frequency Transmission | - Some really weird, contrived (as if this whole thing isn't) phase calculator?.. <br> - part2 broke my brain. Optimally calculate subsets by __precalculating running sums__ (linear), then getting subsets by subtracting two of the precalculated running sums. i.e. sub[2:4] = sub[0:4] - sub[0:2] <br> - And also switching pattern recognition to make calculating a particular output O(nlogn)...
|
16 | Flawed Frequency Transmission | - Some really weird, contrived (as if this whole thing isn't) phase calculator?.. <br> - part2 broke my brain. Optimally calculate subsets by __precalculating running sums__ (linear), then getting subsets by subtracting two of the precalculated running sums. i.e. sub[2:4] = sub[0:4] - sub[0:2] <br> - And also switching pattern recognition to make calculating a particular output O(nlogn)...
|
||||||
|
17 | Set and Forget | More Intcode... <br> Robot walking around a scaffolding... Fairly similar to previous algos, and a 2D grid traversal again <br> - I feel like I cheated part2 by finding the pattern by eye after printing what the 2D grid looks like. Then it was a matter of giving the intcode computer the corresponding inputs (in a weird format). <br> - I need a big refactor of the intcode compiler to make it iterative (instead of recursive) because it's blowing the call stack in "continuous video feed" mode :(
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
1,330,331,332,109,3406,1102,1182,1,15,1101,0,1481,24,1002,0,1,570,1006,570,36,1002,571,1,0,1001,570,-1,570,1001,24,1,24,1106,0,18,1008,571,0,571,1001,15,1,15,1008,15,1481,570,1006,570,14,21101,0,58,0,1105,1,786,1006,332,62,99,21101,0,333,1,21102,1,73,0,1106,0,579,1101,0,0,572,1101,0,0,573,3,574,101,1,573,573,1007,574,65,570,1005,570,151,107,67,574,570,1005,570,151,1001,574,-64,574,1002,574,-1,574,1001,572,1,572,1007,572,11,570,1006,570,165,101,1182,572,127,1001,574,0,0,3,574,101,1,573,573,1008,574,10,570,1005,570,189,1008,574,44,570,1006,570,158,1105,1,81,21101,340,0,1,1105,1,177,21101,477,0,1,1106,0,177,21102,514,1,1,21102,1,176,0,1106,0,579,99,21102,184,1,0,1105,1,579,4,574,104,10,99,1007,573,22,570,1006,570,165,1002,572,1,1182,21101,0,375,1,21101,0,211,0,1106,0,579,21101,1182,11,1,21102,222,1,0,1105,1,979,21102,388,1,1,21102,1,233,0,1106,0,579,21101,1182,22,1,21101,244,0,0,1105,1,979,21102,401,1,1,21102,1,255,0,1105,1,579,21101,1182,33,1,21101,0,266,0,1106,0,979,21101,414,0,1,21102,277,1,0,1106,0,579,3,575,1008,575,89,570,1008,575,121,575,1,575,570,575,3,574,1008,574,10,570,1006,570,291,104,10,21101,0,1182,1,21101,0,313,0,1106,0,622,1005,575,327,1101,0,1,575,21101,0,327,0,1105,1,786,4,438,99,0,1,1,6,77,97,105,110,58,10,33,10,69,120,112,101,99,116,101,100,32,102,117,110,99,116,105,111,110,32,110,97,109,101,32,98,117,116,32,103,111,116,58,32,0,12,70,117,110,99,116,105,111,110,32,65,58,10,12,70,117,110,99,116,105,111,110,32,66,58,10,12,70,117,110,99,116,105,111,110,32,67,58,10,23,67,111,110,116,105,110,117,111,117,115,32,118,105,100,101,111,32,102,101,101,100,63,10,0,37,10,69,120,112,101,99,116,101,100,32,82,44,32,76,44,32,111,114,32,100,105,115,116,97,110,99,101,32,98,117,116,32,103,111,116,58,32,36,10,69,120,112,101,99,116,101,100,32,99,111,109,109,97,32,111,114,32,110,101,119,108,105,110,101,32,98,117,116,32,103,111,116,58,32,43,10,68,101,102,105,110,105,116,105,111,110,115,32,109,97,121,32,98,101,32,97,116,32,109,111,115,116,32,50,48,32,99,104,97,114,97,99,116,101,114,115,33,10,94,62,118,60,0,1,0,-1,-1,0,1,0,0,0,0,0,0,1,26,16,0,109,4,2102,1,-3,587,20102,1,0,-1,22101,1,-3,-3,21102,0,1,-2,2208,-2,-1,570,1005,570,617,2201,-3,-2,609,4,0,21201,-2,1,-2,1105,1,597,109,-4,2105,1,0,109,5,2102,1,-4,629,21001,0,0,-2,22101,1,-4,-4,21102,1,0,-3,2208,-3,-2,570,1005,570,781,2201,-4,-3,653,20102,1,0,-1,1208,-1,-4,570,1005,570,709,1208,-1,-5,570,1005,570,734,1207,-1,0,570,1005,570,759,1206,-1,774,1001,578,562,684,1,0,576,576,1001,578,566,692,1,0,577,577,21102,1,702,0,1105,1,786,21201,-1,-1,-1,1106,0,676,1001,578,1,578,1008,578,4,570,1006,570,724,1001,578,-4,578,21102,731,1,0,1106,0,786,1105,1,774,1001,578,-1,578,1008,578,-1,570,1006,570,749,1001,578,4,578,21101,0,756,0,1105,1,786,1105,1,774,21202,-1,-11,1,22101,1182,1,1,21101,774,0,0,1106,0,622,21201,-3,1,-3,1106,0,640,109,-5,2106,0,0,109,7,1005,575,802,20102,1,576,-6,21002,577,1,-5,1105,1,814,21102,0,1,-1,21102,1,0,-5,21102,1,0,-6,20208,-6,576,-2,208,-5,577,570,22002,570,-2,-2,21202,-5,55,-3,22201,-6,-3,-3,22101,1481,-3,-3,2102,1,-3,843,1005,0,863,21202,-2,42,-4,22101,46,-4,-4,1206,-2,924,21101,0,1,-1,1106,0,924,1205,-2,873,21101,0,35,-4,1105,1,924,1202,-3,1,878,1008,0,1,570,1006,570,916,1001,374,1,374,2102,1,-3,895,1102,1,2,0,2101,0,-3,902,1001,438,0,438,2202,-6,-5,570,1,570,374,570,1,570,438,438,1001,578,558,921,21002,0,1,-4,1006,575,959,204,-4,22101,1,-6,-6,1208,-6,55,570,1006,570,814,104,10,22101,1,-5,-5,1208,-5,35,570,1006,570,810,104,10,1206,-1,974,99,1206,-1,974,1102,1,1,575,21101,973,0,0,1106,0,786,99,109,-7,2105,1,0,109,6,21102,0,1,-4,21102,1,0,-3,203,-2,22101,1,-3,-3,21208,-2,82,-1,1205,-1,1030,21208,-2,76,-1,1205,-1,1037,21207,-2,48,-1,1205,-1,1124,22107,57,-2,-1,1205,-1,1124,21201,-2,-48,-2,1106,0,1041,21101,-4,0,-2,1105,1,1041,21101,0,-5,-2,21201,-4,1,-4,21207,-4,11,-1,1206,-1,1138,2201,-5,-4,1059,1201,-2,0,0,203,-2,22101,1,-3,-3,21207,-2,48,-1,1205,-1,1107,22107,57,-2,-1,1205,-1,1107,21201,-2,-48,-2,2201,-5,-4,1090,20102,10,0,-1,22201,-2,-1,-2,2201,-5,-4,1103,2102,1,-2,0,1105,1,1060,21208,-2,10,-1,1205,-1,1162,21208,-2,44,-1,1206,-1,1131,1105,1,989,21102,1,439,1,1105,1,1150,21101,0,477,1,1106,0,1150,21102,514,1,1,21102,1,1149,0,1105,1,579,99,21102,1,1157,0,1106,0,579,204,-2,104,10,99,21207,-3,22,-1,1206,-1,1138,2101,0,-5,1176,2101,0,-4,0,109,-6,2106,0,0,40,13,42,1,11,1,10,7,25,1,11,1,10,1,5,1,25,1,11,1,10,1,5,1,1,13,11,1,11,1,10,1,5,1,1,1,11,1,11,1,11,1,10,1,5,1,1,1,11,1,11,1,11,1,10,1,5,1,1,1,11,1,11,1,11,1,10,13,7,1,11,1,11,1,16,1,1,1,3,1,7,1,11,1,11,1,16,1,1,1,1,11,5,7,11,1,16,1,1,1,1,1,1,1,13,1,17,1,16,11,9,1,7,11,18,1,1,1,1,1,3,1,9,1,7,1,28,1,1,1,1,1,3,1,9,1,7,1,28,1,1,1,1,1,3,1,9,1,7,1,28,11,7,1,7,1,30,1,1,1,3,1,9,1,7,1,22,11,3,1,9,1,7,1,22,1,7,1,5,1,9,1,7,1,22,1,7,11,5,1,7,1,22,1,13,1,3,1,5,1,7,1,18,11,7,11,7,13,6,1,3,1,5,1,11,1,25,1,6,1,3,1,5,1,11,1,25,1,6,1,3,1,5,1,11,1,25,1,6,1,3,1,5,1,11,1,25,1,6,1,3,1,5,1,11,1,25,12,5,1,11,1,25,2,5,1,9,1,11,1,26,1,5,1,9,1,11,1,26,1,5,1,9,1,11,1,26,1,5,1,9,13,26,1,5,1,48,7,48
|
||||||
@@ -0,0 +1,282 @@
|
|||||||
|
/*
|
||||||
|
Intcode struct is defined within this file
|
||||||
|
Robot struct houses an Intcode computer and a method to initialize the floor details
|
||||||
|
- an algorithm in the main function traverses all tiles and checks all of its neighbors
|
||||||
|
- for all intersections that are found, their alignment parameters are calculated & added to a sum
|
||||||
|
*/
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
robot := MakeRobot(inputNumbers)
|
||||||
|
|
||||||
|
// fire off function to populate the robot's floorGrid property
|
||||||
|
robot.GetFloorGrid()
|
||||||
|
|
||||||
|
// find all intersections and sum up the products of its row and col - 0-indexed
|
||||||
|
// helper directions to traverse in all 4 directions
|
||||||
|
dRow := []int{0, 0, -1, 1}
|
||||||
|
dCol := []int{-1, 1, 0, 0}
|
||||||
|
|
||||||
|
var sumOfAlignmentParameters int
|
||||||
|
for row, rowSlice := range robot.floorGrid {
|
||||||
|
for col, floorType := range rowSlice {
|
||||||
|
// traverse to the four directions around the particular cell, increment surroundingScaffolds
|
||||||
|
// by 1 for every neighbor that is a scaffold,
|
||||||
|
// if this is equal to 4 after looping, then an intersection was found
|
||||||
|
var surroundingScaffolds int
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
neighborRow, neighborCol := row+dRow[i], col+dCol[i]
|
||||||
|
isInbounds := neighborRow >= 0 && neighborRow < len(robot.floorGrid) && neighborCol >= 0 && neighborCol < len(robot.floorGrid[0])
|
||||||
|
if isInbounds && floorType == "#" && robot.floorGrid[neighborRow][neighborCol] == "#" {
|
||||||
|
surroundingScaffolds++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if surroundingScaffolds == 4 {
|
||||||
|
sumOfAlignmentParameters += row * col
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Sum of alignment parameters: ", sumOfAlignmentParameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Robot struct to maintain detail's on the Robot's coordinates, path
|
||||||
|
type Robot struct {
|
||||||
|
row, col int
|
||||||
|
floorGrid [][]string
|
||||||
|
computer *Intcode
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeRobot returns an instance of a Robot
|
||||||
|
func MakeRobot(intcodeInput []int) *Robot {
|
||||||
|
return &Robot{
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
make([][]string, 0),
|
||||||
|
MakeComputer(intcodeInput),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFloorGrid will fire off the computer and populate the robot's floor details
|
||||||
|
func (robot *Robot) GetFloorGrid() {
|
||||||
|
robot.computer.Step(-1)
|
||||||
|
robot.floorGrid = append(robot.floorGrid, []string{})
|
||||||
|
row := 0
|
||||||
|
|
||||||
|
for _, v := range robot.computer.Outputs {
|
||||||
|
switch v {
|
||||||
|
case 10:
|
||||||
|
row++
|
||||||
|
robot.floorGrid = append(robot.floorGrid, []string{})
|
||||||
|
default:
|
||||||
|
tileType := string(v)
|
||||||
|
robot.floorGrid[row] = append(robot.floorGrid[row], tileType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse off empty slices @ end
|
||||||
|
for i := len(robot.floorGrid) - 1; i >= 0; i-- {
|
||||||
|
if len(robot.floorGrid[i]) == 0 {
|
||||||
|
robot.floorGrid = robot.floorGrid[:len(robot.floorGrid)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
switch opcode {
|
||||||
|
case 1, 2, 7, 8:
|
||||||
|
comp.ResizeMemory(param1, param2, param3)
|
||||||
|
case 5, 6:
|
||||||
|
comp.ResizeMemory(param1, param2)
|
||||||
|
case 3, 4, 9:
|
||||||
|
comp.ResizeMemory(param1)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,347 @@
|
|||||||
|
/*
|
||||||
|
Intcode struct is defined within this file
|
||||||
|
Robot struct houses an Intcode computer and a method to initialize the floor details
|
||||||
|
*/
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modify the first address from a 1 to a 2 to start the vacuum robot
|
||||||
|
inputNumbers[0] = 2
|
||||||
|
|
||||||
|
robot := MakeRobot(inputNumbers)
|
||||||
|
// fire off function to populate the robot's floorGrid property
|
||||||
|
robot.GetFloorGrid()
|
||||||
|
|
||||||
|
robot.computer.Outputs = []int{}
|
||||||
|
|
||||||
|
// NOTE the computer accepts numbers as inputs, but these numbers correlate to ASCII
|
||||||
|
// computer will ask for main movement routine. allows: [A-C,] i.e. A B C separated by ,
|
||||||
|
// end with a newline, e.g. integer 10 in ASCII
|
||||||
|
A, B, C := int('A'), int('B'), int('C')
|
||||||
|
comma, newline := int(','), int('\n')
|
||||||
|
|
||||||
|
mainRoutineOrder := []int{A, B, A, C, B, C, B, C, A, C}
|
||||||
|
for i, routine := range mainRoutineOrder {
|
||||||
|
robot.computer.Step(routine)
|
||||||
|
if i != len(mainRoutineOrder)-1 {
|
||||||
|
robot.computer.Step(comma)
|
||||||
|
} else {
|
||||||
|
robot.computer.Step(newline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// computer then asks for details of each movement function
|
||||||
|
// accepts [LR0-9,] ended with a newline
|
||||||
|
// NOTE I determined these paths manually after printing the floor and finding a pattern by eye...
|
||||||
|
L, R := int('L'), int('R')
|
||||||
|
numbers := make([]int, 10)
|
||||||
|
for i := range numbers {
|
||||||
|
numbers[i] = int('0') + i
|
||||||
|
}
|
||||||
|
// A is L10 R12 R12
|
||||||
|
patternA := []int{
|
||||||
|
L, comma, numbers[1], numbers[0], comma,
|
||||||
|
R, comma, numbers[1], numbers[2], comma,
|
||||||
|
R, comma, numbers[1], numbers[2],
|
||||||
|
newline,
|
||||||
|
}
|
||||||
|
// B is R6 R10 L10
|
||||||
|
patternB := []int{
|
||||||
|
R, comma, numbers[6], comma,
|
||||||
|
R, comma, numbers[1], numbers[0], comma,
|
||||||
|
L, comma, numbers[1], numbers[0],
|
||||||
|
newline,
|
||||||
|
}
|
||||||
|
// C is R10 L10 L12 R6
|
||||||
|
patternC := []int{
|
||||||
|
R, comma, numbers[1], numbers[0], comma,
|
||||||
|
L, comma, numbers[1], numbers[0], comma,
|
||||||
|
L, comma, numbers[1], numbers[2], comma,
|
||||||
|
R, comma, numbers[6],
|
||||||
|
newline,
|
||||||
|
}
|
||||||
|
// fmt.Println("pattern A: ")
|
||||||
|
for _, v := range patternA {
|
||||||
|
// fmt.Printf("%v,", v)
|
||||||
|
robot.computer.Step(v)
|
||||||
|
}
|
||||||
|
for _, v := range patternB {
|
||||||
|
robot.computer.Step(v)
|
||||||
|
}
|
||||||
|
for _, v := range patternC {
|
||||||
|
robot.computer.Step(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally, asks for continuous video feed or not 'y' or 'n' and a new line
|
||||||
|
// NOTE making this 'y' will cause a stack overflow with my recursive implementation :(
|
||||||
|
robot.computer.Step(int('n'))
|
||||||
|
robot.computer.Step(newline)
|
||||||
|
|
||||||
|
fmt.Println("Dust collected", robot.computer.Outputs[len(robot.computer.Outputs)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Robot struct to maintain detail's on the Robot's coordinates, path
|
||||||
|
type Robot struct {
|
||||||
|
row, col int
|
||||||
|
floorGrid [][]string
|
||||||
|
computer *Intcode
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeRobot returns an instance of a Robot
|
||||||
|
func MakeRobot(intcodeInput []int) *Robot {
|
||||||
|
return &Robot{
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
make([][]string, 0),
|
||||||
|
MakeComputer(intcodeInput),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFloorGrid will fire off the computer and populate the robot's floor details
|
||||||
|
func (robot *Robot) GetFloorGrid() {
|
||||||
|
robot.computer.Step(-1)
|
||||||
|
robot.floorGrid = append(robot.floorGrid, []string{})
|
||||||
|
row := 0
|
||||||
|
|
||||||
|
for _, v := range robot.computer.Outputs {
|
||||||
|
switch v {
|
||||||
|
case 10:
|
||||||
|
row++
|
||||||
|
robot.floorGrid = append(robot.floorGrid, []string{})
|
||||||
|
default:
|
||||||
|
tileType := string(v)
|
||||||
|
robot.floorGrid[row] = append(robot.floorGrid[row], tileType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse off empty slices @ end
|
||||||
|
for i := len(robot.floorGrid) - 1; i >= 0; i-- {
|
||||||
|
if len(robot.floorGrid[i]) == 0 {
|
||||||
|
robot.floorGrid = robot.floorGrid[:len(robot.floorGrid)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
switch opcode {
|
||||||
|
case 1, 2, 7, 8:
|
||||||
|
comp.ResizeMemory(param1, param2, param3)
|
||||||
|
case 5, 6:
|
||||||
|
comp.ResizeMemory(param1, param2)
|
||||||
|
case 3, 4, 9:
|
||||||
|
comp.ResizeMemory(param1)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.Println("Output", comp.PuzzleInput[param1])
|
||||||
|
|
||||||
|
// TODO come back to this b/c the entire Intcode machine needs to be made not-recursive
|
||||||
|
// todo for this to not blow the call stack
|
||||||
|
// // NOTE uncomment to view robot moving around floor
|
||||||
|
// if len(comp.Outputs) == 1967 {
|
||||||
|
// var row int
|
||||||
|
// floorGrid := [][]string{[]string{}}
|
||||||
|
// for _, v := range comp.Outputs {
|
||||||
|
// switch v {
|
||||||
|
// case 10:
|
||||||
|
// row++
|
||||||
|
// floorGrid = append(floorGrid, []string{})
|
||||||
|
// default:
|
||||||
|
// tileType := string(v)
|
||||||
|
// floorGrid[row] = append(floorGrid[row], tileType)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for _, v := range floorGrid {
|
||||||
|
// fmt.Println(v)
|
||||||
|
// }
|
||||||
|
// fmt.Println("")
|
||||||
|
// comp.Outputs = []int{}
|
||||||
|
// time.Sleep(time.Second)
|
||||||
|
// }
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
--- Day 17: Set and Forget ---
|
||||||
|
An early warning system detects an incoming solar flare and automatically activates the ship's electromagnetic shield. Unfortunately, this has cut off the Wi-Fi for many small robots that, unaware of the impending danger, are now trapped on exterior scaffolding on the unsafe side of the shield. To rescue them, you'll have to act quickly!
|
||||||
|
|
||||||
|
The only tools at your disposal are some wired cameras and a small vacuum robot currently asleep at its charging station. The video quality is poor, but the vacuum robot has a needlessly bright LED that makes it easy to spot no matter where it is.
|
||||||
|
|
||||||
|
An Intcode program, the Aft Scaffolding Control and Information Interface (ASCII, your puzzle input), provides access to the cameras and the vacuum robot. Currently, because the vacuum robot is asleep, you can only access the cameras.
|
||||||
|
|
||||||
|
Running the ASCII program on your Intcode computer will provide the current view of the scaffolds. This is output, purely coincidentally, as ASCII code: 35 means #, 46 means ., 10 starts a new line of output below the current one, and so on. (Within a line, characters are drawn left-to-right.)
|
||||||
|
|
||||||
|
In the camera output, # represents a scaffold and . represents open space. The vacuum robot is visible as ^, v, <, or > depending on whether it is facing up, down, left, or right respectively. When drawn like this, the vacuum robot is always on a scaffold; if the vacuum robot ever walks off of a scaffold and begins tumbling through space uncontrollably, it will instead be visible as X.
|
||||||
|
|
||||||
|
In general, the scaffold forms a path, but it sometimes loops back onto itself. For example, suppose you can see the following view from the cameras:
|
||||||
|
|
||||||
|
..#..........
|
||||||
|
..#..........
|
||||||
|
#######...###
|
||||||
|
#.#...#...#.#
|
||||||
|
#############
|
||||||
|
..#...#...#..
|
||||||
|
..#####...^..
|
||||||
|
Here, the vacuum robot, ^ is facing up and sitting at one end of the scaffold near the bottom-right of the image. The scaffold continues up, loops across itself several times, and ends at the top-left of the image.
|
||||||
|
|
||||||
|
The first step is to calibrate the cameras by getting the alignment parameters of some well-defined points. Locate all scaffold intersections; for each, its alignment parameter is the distance between its left edge and the left edge of the view multiplied by the distance between its top edge and the top edge of the view. Here, the intersections from the above image are marked O:
|
||||||
|
|
||||||
|
..#..........
|
||||||
|
..#..........
|
||||||
|
##O####...###
|
||||||
|
#.#...#...#.#
|
||||||
|
##O###O###O##
|
||||||
|
..#...#...#..
|
||||||
|
..#####...^..
|
||||||
|
For these intersections:
|
||||||
|
|
||||||
|
The top-left intersection is 2 units from the left of the image and 2 units from the top of the image, so its alignment parameter is 2 * 2 = 4.
|
||||||
|
The bottom-left intersection is 2 units from the left and 4 units from the top, so its alignment parameter is 2 * 4 = 8.
|
||||||
|
The bottom-middle intersection is 6 from the left and 4 from the top, so its alignment parameter is 24.
|
||||||
|
The bottom-right intersection's alignment parameter is 40.
|
||||||
|
To calibrate the cameras, you need the sum of the alignment parameters. In the above example, this is 76.
|
||||||
|
|
||||||
|
Run your ASCII program. What is the sum of the alignment parameters for the scaffold intersections?
|
||||||
|
|
||||||
|
Your puzzle answer was 3888.
|
||||||
|
|
||||||
|
--- Part Two ---
|
||||||
|
Now for the tricky part: notifying all the other robots about the solar flare. The vacuum robot can do this automatically if it gets into range of a robot. However, you can't see the other robots on the camera, so you need to be thorough instead: you need to make the vacuum robot visit every part of the scaffold at least once.
|
||||||
|
|
||||||
|
The vacuum robot normally wanders randomly, but there isn't time for that today. Instead, you can override its movement logic with new rules.
|
||||||
|
|
||||||
|
Force the vacuum robot to wake up by changing the value in your ASCII program at address 0 from 1 to 2. When you do this, you will be automatically prompted for the new movement rules that the vacuum robot should use. The ASCII program will use input instructions to receive them, but they need to be provided as ASCII code; end each line of logic with a single newline, ASCII code 10.
|
||||||
|
|
||||||
|
First, you will be prompted for the main movement routine. The main routine may only call the movement functions: A, B, or C. Supply the movement functions to use as ASCII text, separating them with commas (,, ASCII code 44), and ending the list with a newline (ASCII code 10). For example, to call A twice, then alternate between B and C three times, provide the string A,A,B,C,B,C,B,C and then a newline.
|
||||||
|
|
||||||
|
Then, you will be prompted for each movement function. Movement functions may use L to turn left, R to turn right, or a number to move forward that many units. Movement functions may not call other movement functions. Again, separate the actions with commas and end the list with a newline. For example, to move forward 10 units, turn left, move forward 8 units, turn right, and finally move forward 6 units, provide the string 10,L,8,R,6 and then a newline.
|
||||||
|
|
||||||
|
Finally, you will be asked whether you want to see a continuous video feed; provide either y or n and a newline. Enabling the continuous video feed can help you see what's going on, but it also requires a significant amount of processing power, and may even cause your Intcode computer to overheat.
|
||||||
|
|
||||||
|
Due to the limited amount of memory in the vacuum robot, the ASCII definitions of the main routine and the movement functions may each contain at most 20 characters, not counting the newline.
|
||||||
|
|
||||||
|
For example, consider the following camera feed:
|
||||||
|
|
||||||
|
#######...#####
|
||||||
|
#.....#...#...#
|
||||||
|
#.....#...#...#
|
||||||
|
......#...#...#
|
||||||
|
......#...###.#
|
||||||
|
......#.....#.#
|
||||||
|
^########...#.#
|
||||||
|
......#.#...#.#
|
||||||
|
......#########
|
||||||
|
........#...#..
|
||||||
|
....#########..
|
||||||
|
....#...#......
|
||||||
|
....#...#......
|
||||||
|
....#...#......
|
||||||
|
....#####......
|
||||||
|
In order for the vacuum robot to visit every part of the scaffold at least once, one path it could take is:
|
||||||
|
|
||||||
|
R,8,R,8,R,4,R,4,R,8,L,6,L,2,R,4,R,4,R,8,R,8,R,8,L,6,L,2
|
||||||
|
Without the memory limit, you could just supply this whole string to function A and have the main routine call A once. However, you'll need to split it into smaller parts.
|
||||||
|
|
||||||
|
One approach is:
|
||||||
|
|
||||||
|
Main routine: A,B,C,B,A,C
|
||||||
|
(ASCII input: 65, 44, 66, 44, 67, 44, 66, 44, 65, 44, 67, 10)
|
||||||
|
Function A: R,8,R,8
|
||||||
|
(ASCII input: 82, 44, 56, 44, 82, 44, 56, 10)
|
||||||
|
Function B: R,4,R,4,R,8
|
||||||
|
(ASCII input: 82, 44, 52, 44, 82, 44, 52, 44, 82, 44, 56, 10)
|
||||||
|
Function C: L,6,L,2
|
||||||
|
(ASCII input: 76, 44, 54, 44, 76, 44, 50, 10)
|
||||||
|
Visually, this would break the desired path into the following parts:
|
||||||
|
|
||||||
|
A, B, C, B, A, C
|
||||||
|
R,8,R,8, R,4,R,4,R,8, L,6,L,2, R,4,R,4,R,8, R,8,R,8, L,6,L,2
|
||||||
|
|
||||||
|
CCCCCCA...BBBBB
|
||||||
|
C.....A...B...B
|
||||||
|
C.....A...B...B
|
||||||
|
......A...B...B
|
||||||
|
......A...CCC.B
|
||||||
|
......A.....C.B
|
||||||
|
^AAAAAAAA...C.B
|
||||||
|
......A.A...C.B
|
||||||
|
......AAAAAA#AB
|
||||||
|
........A...C..
|
||||||
|
....BBBB#BBBB..
|
||||||
|
....B...A......
|
||||||
|
....B...A......
|
||||||
|
....B...A......
|
||||||
|
....BBBBA......
|
||||||
|
Of course, the scaffolding outside your ship is much more complex.
|
||||||
|
|
||||||
|
As the vacuum robot finds other robots and notifies them of the impending solar flare, it also can't help but leave them squeaky clean, collecting any space dust it finds. Once it finishes the programmed set of movements, assuming it hasn't drifted off into space, the cleaning robot will return to its docking station and report the amount of space dust it collected as a large, non-ASCII value in a single output instruction.
|
||||||
|
|
||||||
|
After visiting every part of the scaffold at least once, how much dust does the vacuum robot report it has collected?
|
||||||
|
|
||||||
|
Your puzzle answer was 927809.
|
||||||
|
|
||||||
|
Both parts of this puzzle are complete! They provide two gold stars: **
|
||||||
Reference in New Issue
Block a user