11_common.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import { Vector2 } from "../3/3_common.ts";
  2. export class StarMap {
  3. private originalMap: string[];
  4. private mapDimensions: {width: number, height: number};
  5. private expansionRate: number;
  6. public galaxyList: Array<Vector2> = [];
  7. public emptyColumns: number[] = [];
  8. public emptyRows: number[] = [];
  9. constructor(rawMap: string[], expansionRate = 1) {
  10. this.originalMap = rawMap;
  11. this.expansionRate = expansionRate > 1 ? expansionRate - 1 : expansionRate;
  12. this.mapDimensions = {
  13. width: this.originalMap[0].length,
  14. height: this.originalMap.length
  15. };
  16. this.parse();
  17. // Sort the galaxy list by Y values
  18. this.galaxyList.sort((a, b) => a.Y - b.Y)
  19. }
  20. private parse() {
  21. // Find the empty rows and columns
  22. for (let col = 0; col < this.mapDimensions.width; col++) {
  23. // Count of the number of empty cells in the column
  24. let emptyCellsInColumn = 0;
  25. for (let row = 0; row < this.mapDimensions.height; row++) {
  26. // If current cell is a galaxy, add it to the list and move to the next row
  27. if (this.isGalaxy(this.originalMap[row][col])) {
  28. this.galaxyList.push({
  29. X: col,
  30. Y: row
  31. });
  32. continue;
  33. }
  34. // Check if the current row is empty
  35. // Only needs done during the first column
  36. if (col == 0 && this.isEmpty(this.originalMap[row])) {
  37. this.emptyRows.push(row);
  38. }
  39. // Otherwise, add an empty char to the pivotted column
  40. emptyCellsInColumn++;
  41. }
  42. // Check if the column was empty
  43. if (emptyCellsInColumn == this.mapDimensions.height) {
  44. this.emptyColumns.push(col);
  45. }
  46. }
  47. }
  48. private isEmpty(sector: string) {
  49. return /^[.]+$/.test(sector);
  50. }
  51. private isGalaxy(symbol: string) {
  52. return symbol == "#";
  53. }
  54. public getExpandedDistance(galaxyIdx1: number, galaxyIdx2: number, debug = false): number {
  55. // Get the two galaxies being compared
  56. const galaxy1 = this.galaxyList[galaxyIdx1];
  57. const galaxy2 = this.galaxyList[galaxyIdx2];
  58. // DEBUG
  59. if (debug) {
  60. console.log("DEBUG:");
  61. console.log("Comparing ", galaxy1, "to ", galaxy2);
  62. }
  63. // Check for any empty rows or columns between the two
  64. let yOffset = 0;
  65. let xOffset = 0;
  66. this.emptyColumns.forEach((col) => {
  67. if (between(col, galaxy1.X, galaxy2.X)) {
  68. yOffset += this.expansionRate;
  69. if (debug) {
  70. console.log(`Adding ${this.expansionRate} for the empty column at ${col}`);
  71. }
  72. }
  73. });
  74. this.emptyRows.forEach((row) => {
  75. if (between(row, galaxy1.Y, galaxy2.Y)) {
  76. xOffset += this.expansionRate;
  77. if (debug) {
  78. console.log(`Adding ${this.expansionRate} for the empty row at ${row}`);
  79. }
  80. }
  81. });
  82. if (debug) {
  83. console.log(`DEBUG: xOffset - ${xOffset}`);
  84. console.log(`DEBUG: yOffset - ${yOffset}`);
  85. }
  86. // Find the immediate deltas between the two galaxies
  87. const delta: Vector2 = {
  88. X: galaxy1.X - galaxy2.X,
  89. Y: galaxy1.Y - galaxy2.Y
  90. };
  91. if (debug) {
  92. console.log("DEBUG: delta values - ", delta);
  93. }
  94. return Math.abs(delta.X) + xOffset + Math.abs(delta.Y) + yOffset;
  95. }
  96. public solvePart1(debug = false):number {
  97. let totalPairs = 0;
  98. let totalShortestPaths = 0;
  99. for (let idx1 = 0; idx1 < this.galaxyList.length - 1; idx1++) {
  100. for (let idx2 = idx1 + 1; idx2 < this.galaxyList.length; idx2++) {
  101. totalPairs++;
  102. const manhatDist = this.getExpandedDistance(idx1, idx2, debug)
  103. if (debug) {
  104. console.log(`Manhattan Distance between node ${idx1 + 1} and ${idx2 + 1} is: `, manhatDist);
  105. }
  106. totalShortestPaths += manhatDist;
  107. }
  108. if (debug) {
  109. console.log("---------------------");
  110. }
  111. }
  112. return totalShortestPaths;
  113. }
  114. }
  115. function between(toCheck: number, boundary1: number, boundary2: number): boolean {
  116. return (toCheck > boundary1 && toCheck < boundary2)
  117. || (toCheck > boundary2 && toCheck < boundary1);
  118. }