11_1.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. import { Vector2 } from "../3/3_common.ts";
  2. import { LoadInput, Inspect } from "../common.ts";
  3. async function main() {
  4. const tests = [
  5. '...#......',
  6. '.......#..',
  7. '#.........',
  8. '..........',
  9. '......#...',
  10. '.#........',
  11. '.........#',
  12. '..........',
  13. '.......#..',
  14. '#...#.....'
  15. ];
  16. const test_reddit_1 = [
  17. "...#......#....",
  18. "...............",
  19. "#..........#...",
  20. "...............",
  21. "...............",
  22. "...............",
  23. "......#.....#..",
  24. ".#.............",
  25. "#..............",
  26. "...............",
  27. "...............",
  28. "...............",
  29. "......#.#......",
  30. "............#..",
  31. "....#..........",
  32. ];
  33. const test_reddit_2 = [
  34. "......#........",
  35. ".........#.....",
  36. "...............",
  37. "...............",
  38. "..........#...#",
  39. "...............",
  40. "...............",
  41. "#...#..........",
  42. "..#............",
  43. "...............",
  44. ".........#.....",
  45. ".........#.....",
  46. "...........#...",
  47. "...............",
  48. ".#...........#.",
  49. ];
  50. const input = await LoadInput(11);
  51. const sm = new StarMap(input);
  52. console.log("Empty Columns found:");
  53. Inspect(sm.emptyColumns);
  54. console.log("Empty Rows found:");
  55. Inspect(sm.emptyRows);
  56. console.log("Galaxies found:");
  57. console.log(sm.galaxyList);
  58. console.log(`The sum of the shortest paths between galaxies is: ${sm.solvePart1()}`);
  59. }
  60. class StarMap {
  61. private originalMap: string[];
  62. private mapDimensions: {width: number, height: number};
  63. public galaxyList: Array<Vector2> = [];
  64. public emptyColumns: number[] = [];
  65. public emptyRows: number[] = [];
  66. constructor(rawMap: string[]) {
  67. this.originalMap = rawMap;
  68. this.mapDimensions = {
  69. width: this.originalMap[0].length,
  70. height: this.originalMap.length
  71. };
  72. this.parse();
  73. // Sort the galaxy list by Y values
  74. this.galaxyList.sort((a, b) => a.Y - b.Y)
  75. }
  76. private parse() {
  77. // Find the empty rows and columns
  78. for (let col = 0; col < this.mapDimensions.width; col++) {
  79. // Count of the number of empty cells in the column
  80. let emptyCellsInColumn = 0;
  81. for (let row = 0; row < this.mapDimensions.height; row++) {
  82. // If current cell is a galaxy, add it to the list and move to the next row
  83. if (this.isGalaxy(this.originalMap[row][col])) {
  84. this.galaxyList.push({
  85. X: col,
  86. Y: row
  87. });
  88. continue;
  89. }
  90. // Check if the current row is empty
  91. // Only needs done during the first column
  92. if (col == 0 && this.isEmpty(this.originalMap[row])) {
  93. this.emptyRows.push(row);
  94. }
  95. // Otherwise, add an empty char to the pivotted column
  96. emptyCellsInColumn++;
  97. }
  98. // Check if the column was empty
  99. if (emptyCellsInColumn == this.mapDimensions.height) {
  100. this.emptyColumns.push(col);
  101. }
  102. }
  103. }
  104. private isEmpty(sector: string) {
  105. return /^[.]+$/.test(sector);
  106. }
  107. private isGalaxy(symbol: string) {
  108. return symbol == "#";
  109. }
  110. public getExpandedDistance(galaxyIdx1: number, galaxyIdx2: number, debug = false): number {
  111. // Get the two galaxies being compared
  112. const galaxy1 = this.galaxyList[galaxyIdx1];
  113. const galaxy2 = this.galaxyList[galaxyIdx2];
  114. // DEBUG
  115. if (debug) {
  116. console.log("DEBUG:");
  117. console.log("Comparing ", galaxy1, "to ", galaxy2);
  118. }
  119. // Check for any empty rows or columns between the two
  120. let yOffset = 0;
  121. let xOffset = 0;
  122. this.emptyColumns.forEach((col) => {
  123. if (between(col, galaxy1.X, galaxy2.X)) {
  124. yOffset += 1;
  125. if (debug) {
  126. console.log(`Adding 2 for the empty column at ${col}`);
  127. }
  128. }
  129. });
  130. this.emptyRows.forEach((row) => {
  131. if (between(row, galaxy1.Y, galaxy2.Y)) {
  132. xOffset += 1;
  133. if (debug) {
  134. console.log(`Adding 2 for the empty row at ${row}`);
  135. }
  136. }
  137. });
  138. if (debug) {
  139. console.log(`DEBUG: xOffset - ${xOffset}`);
  140. console.log(`DEBUG: yOffset - ${yOffset}`);
  141. }
  142. // Find the immediate deltas between the two galaxies
  143. const delta: Vector2 = {
  144. X: galaxy1.X - galaxy2.X,
  145. Y: galaxy1.Y - galaxy2.Y
  146. };
  147. if (debug) {
  148. console.log("DEBUG: delta values - ", delta);
  149. }
  150. return Math.abs(delta.X) + xOffset + Math.abs(delta.Y) + yOffset;
  151. }
  152. public solvePart1(debug = false):number {
  153. let totalPairs = 0;
  154. let totalShortestPaths = 0;
  155. for (let idx1 = 0; idx1 < this.galaxyList.length - 1; idx1++) {
  156. for (let idx2 = idx1 + 1; idx2 < this.galaxyList.length; idx2++) {
  157. totalPairs++;
  158. const manhatDist = this.getExpandedDistance(idx1, idx2, debug)
  159. if (debug) {
  160. console.log(`Manhattan Distance between node ${idx1 + 1} and ${idx2 + 1} is: `, manhatDist);
  161. }
  162. totalShortestPaths += manhatDist;
  163. }
  164. if (debug) {
  165. console.log("---------------------");
  166. }
  167. }
  168. return totalShortestPaths;
  169. }
  170. }
  171. /**
  172. * Get the slope of a line going through two {@link Vector2}'s
  173. *
  174. * If the two are on the same x-axis, then the slope will be 0.
  175. *
  176. * If the two are on the same y-axis, then the slope will be `Infinity`.
  177. *
  178. * @param {Vector2} node1
  179. * @param {Vector2} node2
  180. * @returns {number} A float or `Infinity`
  181. */
  182. function getSlope(node1: Vector2, node2: Vector2): number {
  183. const delta = {
  184. X: node2.X - node1.X,
  185. Y: node2.Y - node1.Y
  186. };
  187. if (delta.X == 0) { return Infinity; }
  188. return delta.Y/delta.X;
  189. }
  190. function getDistance(node1: Vector2, node2: Vector2): number {
  191. const delta: Vector2 = {
  192. X: node2.X - node1.X,
  193. Y: node2.Y - node1.Y
  194. };
  195. return Math.sqrt(Math.pow(delta.X, 2) + Math.pow(delta.Y, 2));
  196. }
  197. function getManhattanDistance(node1: Vector2, node2: Vector2): number {
  198. const delta: Vector2 = {
  199. X: node1.X - node2.X,
  200. Y: node1.Y - node2.Y
  201. };
  202. const manhatDist = Math.abs(delta.X) + Math.abs(delta.Y);
  203. return manhatDist;
  204. }
  205. function between(toCheck: number, boundary1: number, boundary2: number): boolean {
  206. return (toCheck > boundary1 && toCheck < boundary2)
  207. || (toCheck > boundary2 && toCheck < boundary1);
  208. }
  209. main();