const util = require("util"); const Computer = require("../IntComp/Computer"); const SpaceImageFormat = require("../SpaceImageFormat/SpaceImageFormat"); const input = [3, 8, 1005, 8, 330, 1106, 0, 11, 0, 0, 0, 104, 1, 104, 0, 3, 8, 102, -1, 8, 10, 101, 1, 10, 10, 4, 10, 1008, 8, 0, 10, 4, 10, 102, 1, 8, 29, 3, 8, 1002, 8, -1, 10, 1001, 10, 1, 10, 4, 10, 1008, 8, 0, 10, 4, 10, 101, 0, 8, 51, 1, 1103, 2, 10, 1006, 0, 94, 1006, 0, 11, 1, 1106, 13, 10, 3, 8, 1002, 8, -1, 10, 101, 1, 10, 10, 4, 10, 1008, 8, 1, 10, 4, 10, 1001, 8, 0, 87, 3, 8, 102, -1, 8, 10, 101, 1, 10, 10, 4, 10, 1008, 8, 0, 10, 4, 10, 1001, 8, 0, 109, 2, 1105, 5, 10, 2, 103, 16, 10, 1, 1103, 12, 10, 2, 105, 2, 10, 3, 8, 102, -1, 8, 10, 1001, 10, 1, 10, 4, 10, 108, 1, 8, 10, 4, 10, 1001, 8, 0, 146, 1006, 0, 49, 2, 1, 12, 10, 2, 1006, 6, 10, 1, 1101, 4, 10, 3, 8, 1002, 8, -1, 10, 1001, 10, 1, 10, 4, 10, 108, 0, 8, 10, 4, 10, 1001, 8, 0, 183, 1, 6, 9, 10, 1006, 0, 32, 3, 8, 102, -1, 8, 10, 1001, 10, 1, 10, 4, 10, 1008, 8, 1, 10, 4, 10, 101, 0, 8, 213, 2, 1101, 9, 10, 3, 8, 1002, 8, -1, 10, 1001, 10, 1, 10, 4, 10, 1008, 8, 1, 10, 4, 10, 101, 0, 8, 239, 1006, 0, 47, 1006, 0, 4, 2, 6, 0, 10, 1006, 0, 58, 3, 8, 1002, 8, -1, 10, 1001, 10, 1, 10, 4, 10, 1008, 8, 0, 10, 4, 10, 102, 1, 8, 274, 2, 1005, 14, 10, 1006, 0, 17, 1, 104, 20, 10, 1006, 0, 28, 3, 8, 102, -1, 8, 10, 1001, 10, 1, 10, 4, 10, 108, 1, 8, 10, 4, 10, 1002, 8, 1, 309, 101, 1, 9, 9, 1007, 9, 928, 10, 1005, 10, 15, 99, 109, 652, 104, 0, 104, 1, 21101, 0, 937263411860, 1, 21102, 347, 1, 0, 1105, 1, 451, 21101, 932440724376, 0, 1, 21102, 1, 358, 0, 1105, 1, 451, 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, 29015167015, 1, 21101, 0, 405, 0, 1106, 0, 451, 21102, 1, 3422723163, 1, 21101, 0, 416, 0, 1106, 0, 451, 3, 10, 104, 0, 104, 0, 3, 10, 104, 0, 104, 0, 21101, 0, 868389376360, 1, 21101, 0, 439, 0, 1105, 1, 451, 21102, 825544712960, 1, 1, 21102, 1, 450, 0, 1106, 0, 451, 99, 109, 2, 21201, -1, 0, 1, 21101, 0, 40, 2, 21102, 482, 1, 3, 21102, 1, 472, 0, 1106, 0, 515, 109, -2, 2106, 0, 0, 0, 1, 0, 0, 1, 109, 2, 3, 10, 204, -1, 1001, 477, 478, 493, 4, 0, 1001, 477, 1, 477, 108, 4, 477, 10, 1006, 10, 509, 1101, 0, 0, 477, 109, -2, 2106, 0, 0, 0, 109, 4, 2101, 0, -1, 514, 1207, -3, 0, 10, 1006, 10, 532, 21102, 1, 0, -3, 22101, 0, -3, 1, 22102, 1, -2, 2, 21102, 1, 1, 3, 21101, 551, 0, 0, 1106, 0, 556, 109, -4, 2105, 1, 0, 109, 5, 1207, -3, 1, 10, 1006, 10, 579, 2207, -4, -2, 10, 1006, 10, 579, 22102, 1, -4, -4, 1106, 0, 647, 21201, -4, 0, 1, 21201, -3, -1, 2, 21202, -2, 2, 3, 21102, 1, 598, 0, 1106, 0, 556, 22101, 0, 1, -4, 21101, 1, 0, -1, 2207, -4, -2, 10, 1006, 10, 617, 21102, 0, 1, -1, 22202, -2, -1, -2, 2107, 0, -3, 10, 1006, 10, 639, 21201, -1, 0, 1, 21102, 639, 1, 0, 105, 1, 514, 21202, -2, -1, -2, 22201, -4, -2, -4, 109, -5, 2105, 1, 0]; /** All possible vectors for the robot to move */ const Vectors = { NORTH: { x: 0, y: -1, }, SOUTH: { x: 0, y: 1, }, EAST: { x: 1, y: 0, }, WEST: { x: -1, y: 0, }, }; /** * Data for tracking the robot's movement */ const mapData = { /** * Tiles we've painted, value is the current color */ grid: new Map(), /** * Unique number of tiles we've painted */ uniquePaintings: 0, /** * The current coordinates of the robot */ position: { x: 0, y: 0, }, /** * The current direction the robot is facing */ vector: Vectors.NORTH, /** * Paint the tile below the robot a given color * * @param {number} tileColor The new color for the tile below the robot * @returns {void} */ PaintTile: function (tileColor) { const hashMapKey = `${this.position.x},${this.position.y}`; const uniqueTile = this.grid.get(hashMapKey) === undefined; this.grid.set(hashMapKey, tileColor); if (uniqueTile) { this.uniquePaintings++; } }, /** * Set the heading for the robot * * @param {boolean} rotateLeft Should the robot rotate left? If not, rotate right * @returns {void} */ SetHeading: function (rotateLeft) { switch (this.vector) { case Vectors.NORTH: // console.log(`DEBUG: Facing North, turning ${rotateLeft ? "West" : "East"}`); this.vector = rotateLeft ? Vectors.WEST : Vectors.EAST; break; case Vectors.SOUTH: // console.log(`DEBUG: Facing South, turning ${rotateLeft ? "East" : "West"}`); this.vector = rotateLeft ? Vectors.EAST : Vectors.WEST; break; case Vectors.EAST: // console.log(`DEBUG: Facing West, turning ${rotateLeft ? "North" : "South"}`); this.vector = rotateLeft ? Vectors.NORTH : Vectors.SOUTH; break; case Vectors.WEST: // console.log(`DEBUG: Facing East, turning ${rotateLeft ? "South" : "North"}`); this.vector = rotateLeft ? Vectors.SOUTH : Vectors.NORTH; break; default: throw new Error("Wuh?"); } }, /** * Move the robot along the current vector * @returns {void} */ Move: function () { this.position.x += this.vector.x; this.position.y += this.vector.y; }, }; // Create and run the computer, Robby const robby = new Computer(input); robby.Run(); // Start Robby on a white tile mapData.grid.set("0,0", 1); // Increase by one to account for previous line mapData.uniquePaintings++; let loopCount = 0; do { const currentColor = mapData.grid.get(`${mapData.position.x},${mapData.position.y}`) ?? 0; robby.Input(currentColor); const nextColor = robby.FetchOutputValue(); const nextRotation = robby.FetchOutputValue(); mapData.SetHeading(nextRotation == 0); mapData.PaintTile(nextColor); mapData.Move(); if (++loopCount > 10_000_000) { console.error("Loop went on for too long."); process.exit(0); } } while (robby.running); console.log(`Total unique painted tiles: ${mapData.uniquePaintings}`); // Image data for Registration Identifier let imageData = []; // Loop over grid to key coords and their colors mapData.grid.forEach((color, coords) => { const [row, column] = coords.split(","); if (!imageData[column]) { imageData[column] = []; } imageData[column][row] = color; }); // Flatten it into one array, and replace undefined's with null's imageData = imageData.map(fillEmptySlotsWithZero) .map((row) => { while (row.length < 43) { row.push(0); } return row; }) .flat(); // Join it into a data stream imageData = imageData.join(""); // Create and render the image // Height was found from this post: https://old.reddit.com/r/adventofcode/comments/e93d3y/2019_day_11_part_2_animated_python_output/ // Width was brute forced const height = 6; const width = 43; // Render Robby's path as a Space Image const identifier = new SpaceImageFormat(width, height, imageData); identifier.Render(); console.log(); /** * Fill empty slots in an array with zeros * * @param {array} arr The array to fill * @returns {array} The input array with no empty spots */ function fillEmptySlotsWithZero(arr) { return Array.from(arr, (_, i) => { if (!(i in arr)) { return 0; } return arr[i]; }); }