summaryrefslogtreecommitdiff
path: root/aoc_2023/day-05/part_2.ts
blob: db69735eb20445ef1a0b992d8eeee34385b01ebd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { JSONHashMap } from "@/utils";

export type Pair = [number, number];

const getIntervals = (lines: string[]) => {
  const maps: number[][][] = [];

  for (const line of lines.slice(1, lines.length)) {
    if (!line) continue;

    if (line.includes("to")) {
      maps.push([]);
      continue;
    }

    const currMap = maps.at(-1);
    const [dest, source, range] = line.split(" ").map((x) => parseInt(x));
    if (currMap) {
      currMap.push([dest, source, range]);
    }
  }

  return maps;
};

const constructPiecewiseFn = (intervals: number[][]) => {
  const fn: JSONHashMap<Pair, Pair> = new JSONHashMap();

  let fromIntervals: Pair[] = [];

  for (const [dest, source, range] of intervals) {
    const fromI = [source, source + range - 1];
    fromIntervals.push([source, source + range - 1]);
    fn.set(fromI as Pair, [dest, dest + range - 1]);
  }

  fromIntervals = fromIntervals.sort(
    ([source_a], [source_b]) => source_a - source_b
  );

  for (let i = 0; i < fromIntervals.length - 1; i++) {
    const [_start, end] = fromIntervals[i];
    const [nextStart, _nextEnd] = fromIntervals[i + 1];

    if (end !== nextStart - 1) {
      fn.set([end + 1, nextStart - 1], [end + 1, nextStart - 1]);
    }
  }

  if (fromIntervals[0][0] !== 0) {
    const [start, _end] = fromIntervals[0];
    fn.set([0, start - 1], [0, start - 1]);
  }
  const final: Pair = [fromIntervals.at(-1)![1] + 1, Infinity];
  fn.set(final, final);

  return fn
    .keys()
    .map((range) => [range, fn.get(range)!] as [Pair, Pair])
    .sort(([[source_a]], [[source_b]]) => source_a - source_b);
};

export const compose = (f: [Pair, Pair][], g: [Pair, Pair][]) => {
  const composed: [Pair, Pair][] = [];

  for (const [fDomain, fRange] of f) {
    const fOffset = fRange[0] - fDomain[0];

    for (const [gDomain, gRange] of g) {
      const gOffset = gRange[0] - gDomain[0];

      const start = Math.max(fDomain[0], gDomain[0] - fOffset);
      const end = Math.min(fDomain[1], gDomain[1] - fOffset);

      if (start > end) continue;

      composed.push([
        [start, end],
        [start + fOffset + gOffset, end + fOffset + gOffset],
      ]);
    }
  }

  return composed;
};

export const main = async (lines: string[]): Promise<number | string> => {
  const seeds = lines[0]
    .split(":")
    .at(1)!
    .split(" ")
    .filter((x) => x)
    .map((x) => parseInt(x));

  const intervals = getIntervals(lines);
  intervals.forEach((interval, i) => {
    console.log(" ==== ");
    //    console.log(interval);
    console.log(constructPiecewiseFn(interval));
    const [a, b] = [
      constructPiecewiseFn(interval),
      constructPiecewiseFn(intervals[i + 1]),
    ];
    if (i === intervals.length - 1) return;
    console.log(compose(a, b));
  });

  return 0;
};

//

const isrun = process.argv.length > 1 && process.argv[1] === import.meta.path;
if (isrun) {
  const file = Bun.file("./problem.txt");
  const text = await file.text();
  const lines = text.split("\n").filter((x) => x && x.length);

  console.log("=== COMPUTATION ===\n");

  const answer = await main(lines);

  console.log("\n=== /COMPUTATION ===\n");

  console.log("=== ANSWER TO P2 ===");
  console.log(answer);
}