8_1.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { LoadInput } from "../common.ts";
  2. const tests_EZ = [
  3. "RL",
  4. "",
  5. "AAA = (BBB, CCC)",
  6. "BBB = (DDD, EEE)",
  7. "CCC = (ZZZ, GGG)",
  8. "DDD = (DDD, DDD)",
  9. "EEE = (EEE, EEE)",
  10. "GGG = (GGG, GGG)",
  11. "ZZZ = (ZZZ, ZZZ)",
  12. ];
  13. const tests_longer = [
  14. "LLR",
  15. "",
  16. "AAA = (BBB, BBB)",
  17. "BBB = (AAA, ZZZ)",
  18. "ZZZ = (ZZZ, ZZZ)",
  19. ];
  20. const START_NODE: keyof MapNodeTree = "AAA";
  21. const END_NODE: keyof MapNodeTree = "ZZZ";
  22. const input = await LoadInput(8);
  23. const [directions, map] = ParseMap(input);
  24. let nodeID: keyof MapNodeTree|undefined = START_NODE;
  25. let stepsTaken = 0;
  26. while (nodeID = GetNextNodeInMap(directions, map, nodeID, stepsTaken)) {
  27. stepsTaken++;
  28. if (nodeID == END_NODE) {
  29. break;
  30. }
  31. }
  32. console.log(`A total of ${stepsTaken} steps were taken`);
  33. /**
  34. * Parse the input into a string of directions and a list of nodes and their child nodes
  35. *
  36. * @param {string[]} map The array of lines representing the map
  37. * @returns {[string, MapNodeTree]} A string of the directions to take and the node tree for the map
  38. */
  39. function ParseMap(map: string[]): [string, MapNodeTree] {
  40. const tree: MapNodeTree = {};
  41. const directions = map.shift() || "";
  42. // Discard empty line
  43. map.shift();
  44. let nodeLine:string|undefined = "";
  45. while(nodeLine = map.shift()) {
  46. const [id, leftNode, rightNode] = Array.from(nodeLine.matchAll(/(\w{3})/g), (match) => match[1]);
  47. if (!id || !leftNode || !rightNode) {
  48. throw new Error(`Failed to parse line: ${nodeLine}\n\tid: ${id}\n\tleftNode: ${leftNode}\n\trightNode: ${rightNode}`);
  49. }
  50. tree[id] = {L: leftNode, R: rightNode};
  51. }
  52. return [directions, tree];
  53. }
  54. /**
  55. * Find the ID of the next node to visit
  56. *
  57. * @param {string} directions The entire string of directions
  58. * @param {MapNodeTree} map A list of nodes and their child nodes
  59. * @param {keyof MapNodeTree} currentNode The ID of the node we're current at
  60. * @param {number} stepsTaken The amount of steps already taken in the trek
  61. * @returns {keyof MapNodeTree|undefined} The next node ID, or undefined if none was found
  62. */
  63. function GetNextNodeInMap(directions: string, map: MapNodeTree, currentNode: keyof MapNodeTree, stepsTaken: number): keyof MapNodeTree|undefined {
  64. let nextNodeID: keyof MapNodeTree|undefined = undefined;
  65. // Ensure the current node exists
  66. if (map[currentNode]) {
  67. // Get the next direction to travel in as a looping index of the directions string
  68. const nextDirection = directions[stepsTaken % directions.length] as "L"|"R";
  69. // Store the next node ID
  70. nextNodeID = map[currentNode][nextDirection];
  71. }
  72. return nextNodeID;
  73. }
  74. /**
  75. * An object representing a tree of nodes
  76. */
  77. type MapNodeTree = {
  78. /** The ID of the node */
  79. [NodeID: string]: {
  80. /** The ID of the node to the left of this one */
  81. L: string,
  82. /** The ID of the node to the right of this one */
  83. R: string,
  84. },
  85. };