Skip to content

Commit

Permalink
feat: initial refraction idea
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexAegis committed Dec 5, 2023
1 parent 237b8b3 commit ee83f34
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 18 deletions.
4 changes: 2 additions & 2 deletions solutions/typescript/2023/05/src/p1.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ describe('2023 05 p1', () => {
describe('the input', () => {
it('should solve the input', async () => {
const resources = await loadTaskResources(packageJson.aoc);
expect(p1(resources.input)).toEqual(0);
expect(p1(resources.input)).toEqual(84_470_622);
});
});

describe('example 1', () => {
it('should be solved', async () => {
const resources = await loadTaskResources(packageJson.aoc, 'example.1.txt');
expect(p1(resources.input)).toEqual(0);
expect(p1(resources.input)).toEqual(35);
});
});
});
27 changes: 27 additions & 0 deletions solutions/typescript/2023/05/src/p2.naive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { task } from '@alexaegis/advent-of-code-lib';
import packageJson from '../package.json';
import { findRange, parse } from './parse.js';

// Will never terminate for the actual input
export const p2Naive = (input: string): number => {
const data = parse(input);
return data.seeds
.slideWindow(2, 2)
.flatMap(([seedStart, seedCount]) => {
const locations: number[] = [];
for (let seed = seedStart; seed < seedStart + seedCount; seed++) {
const soil = findRange(seed, data.seedToSoilMap);
const fertilizer = findRange(soil, data.soilToFertilizerMap);
const water = findRange(fertilizer, data.fertilizerToWaterMap);
const light = findRange(water, data.waterToLightMap);
const temperature = findRange(light, data.lightToTemperatureMap);
const humidity = findRange(temperature, data.temperatureToHumidityMap);
const location = findRange(humidity, data.humidityToLocationMap);
locations.push(location);
}
return locations;
})
.min();
};

await task(p2Naive, packageJson.aoc, 'example.1.txt'); // 46
57 changes: 56 additions & 1 deletion solutions/typescript/2023/05/src/p2.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { loadTaskResources } from '@alexaegis/advent-of-code-lib';
import { describe, expect, it } from 'vitest';
import packageJson from '../package.json';
import { p2 } from './p2.js';
import { p2, refract } from './p2.js';
import type { Range } from './parse.js';

describe('2023 05 p2', () => {
describe('the input', () => {
Expand All @@ -17,4 +18,58 @@ describe('2023 05 p2', () => {
expect(p2(input)).toEqual(0);
});
});

describe('refraction', () => {
it('should refract into 3 ranges when b target is enveloped into a target', () => {
const a: Range = {
sourceRangeStart: 2,
destinationRange: 2,
rangeLength: 4,
};
const b: Range = {
sourceRangeStart: 3,
destinationRange: 7,
rangeLength: 2,
};
const result = refract(a, b);

expect(result).toContainEqual<Range>({
sourceRangeStart: 5,
destinationRange: 5,
rangeLength: 1,
});
expect(result).toContainEqual<Range>({
sourceRangeStart: 3,
destinationRange: 7,
rangeLength: 2,
});
expect(result).toContainEqual<Range>({
sourceRangeStart: 2,
destinationRange: 2,
rangeLength: 1,
});
expect(result.length).toEqual(3);
});

it('should refract into 1 range when a target is enveloped into b source', () => {
const a: Range = {
sourceRangeStart: 2,
destinationRange: 2,
rangeLength: 2,
};
const b: Range = {
sourceRangeStart: 0,
destinationRange: 1,
rangeLength: 6,
};
const result = refract(a, b);

expect(result).toContainEqual<Range>({
sourceRangeStart: 2,
destinationRange: 3,
rangeLength: 2,
});
expect(result.length).toEqual(1);
});
});
});
93 changes: 81 additions & 12 deletions solutions/typescript/2023/05/src/p2.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,90 @@
import { task } from '@alexaegis/advent-of-code-lib';
import { Interval, task } from '@alexaegis/advent-of-code-lib';
import packageJson from '../package.json';
import { findRange, parse } from './parse.js';
import { parse, type Range } from './parse.js';

export const getRangeEnd = (range: Range): number => {
return range.destinationRange + range.rangeLength;
};

export const refract = (a: Range, b: Range): Range[] => {
const aTarget = Interval.closed(a.destinationRange, a.destinationRange + a.rangeLength);
const bSource = Interval.closed(b.sourceRangeStart, b.sourceRangeStart + b.rangeLength);
const bTarget = Interval.closed(b.destinationRange, b.destinationRange + b.rangeLength);

const result: Range[] = [];

if (aTarget.high > bSource.high) {
const topRefraction: Range = {
sourceRangeStart: bSource.high,
destinationRange: bSource.high,
rangeLength: Math.min(aTarget.high - bSource.high, a.rangeLength),
};
result.push(topRefraction);
}

if (aTarget.low < bSource.low) {
const bottomRefraction: Range = {
sourceRangeStart: aTarget.low,
destinationRange: aTarget.low,
rangeLength: Math.min(bSource.low - aTarget.low, a.rangeLength),
};
result.push(bottomRefraction);
}

aTarget.intersects(bSource);
// Only if there's an itersection
if (aTarget.intersects(bSource)) {
const middleRefractionStartLow = Math.max(aTarget.low, bSource.low);
const middleRefractionStartHigh = Math.min(aTarget.high, bSource.high);
const mappingDelta = bTarget.low - bSource.low;
// Only this one is mapping
const middleRefraction: Range = {
sourceRangeStart: middleRefractionStartLow,
rangeLength: middleRefractionStartHigh - middleRefractionStartLow,
destinationRange: middleRefractionStartLow + mappingDelta,
};
result.push(middleRefraction);
}

return result;
};

export const p2 = (input: string): number => {
const data = parse(input);
return data.seeds
.map((seed) => {
const soil = findRange(seed, data.seedToSoilMap);
const fertilizer = findRange(soil, data.soilToFertilizerMap);
const water = findRange(fertilizer, data.fertilizerToWaterMap);
const light = findRange(water, data.waterToLightMap);
const temperature = findRange(light, data.lightToTemperatureMap);
const humidity = findRange(temperature, data.temperatureToHumidityMap);
const location = findRange(humidity, data.humidityToLocationMap);
return location;
.slideWindow(2, 2)
.flatMap(([seedStart, seedCount]) => {
const firstRange: Range = {
sourceRangeStart: seedStart,
destinationRange: seedStart,
rangeLength: seedCount,
};

const seedToSoilRefraction = data.seedToSoilMap.flatMap((range) =>
refract(firstRange, range),
);
const soilToFertilizerRefraction = seedToSoilRefraction.flatMap((a) =>
data.soilToFertilizerMap.flatMap((range) => refract(a, range)),
);
const fertilizerToWaterRefraction = soilToFertilizerRefraction.flatMap((a) =>
data.fertilizerToWaterMap.flatMap((range) => refract(a, range)),
);
const waterToLightRefraction = fertilizerToWaterRefraction.flatMap((a) =>
data.waterToLightMap.flatMap((range) => refract(a, range)),
);
const lightToTemperatureRefraction = waterToLightRefraction.flatMap((a) =>
data.lightToTemperatureMap.flatMap((range) => refract(a, range)),
);
const temperatureToHumidityRefraction = lightToTemperatureRefraction.flatMap((a) =>
data.temperatureToHumidityMap.flatMap((range) => refract(a, range)),
);
const humidityToLocationRefraction = temperatureToHumidityRefraction.flatMap((a) =>
data.humidityToLocationMap.flatMap((range) => refract(a, range)),
);

return humidityToLocationRefraction.map((range) => range.sourceRangeStart).min();
})
.min();
};

await task(p2, packageJson.aoc); // 84470622 ~4.36ms
await task(p2, packageJson.aoc, 'example.1.txt'); // 84470622 ~4.36ms
5 changes: 3 additions & 2 deletions solutions/typescript/libs/lib/src/array/array.polyfill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ declare global {
filterMap<V>(mapFn: (t: T) => V | undefined): V[];
partition(partitioner: (a: T) => boolean): [T[], T[]];
pairwise(callback: (a: T, b: T) => void): void;
slideWindow<N extends number = 2>(windowSize?: N): SizedTuple<T, N>[];
slideWindow<N extends number = 2>(windowSize?: N, stepSize?: number): SizedTuple<T, N>[];
bubbleFindPair(comparator: (a: T, b: T) => boolean): [T, T];
walkPairs(): Generator<[T, T]>;
pairs(): [T, T][];
Expand Down Expand Up @@ -228,8 +228,9 @@ Array.prototype.count = function <T>(this: T[], predicate: (t: T) => boolean): n

Array.prototype.slideWindow = function <T, N extends number>(
windowSize: N = 2 as N,
stepSize = 1,
): SizedTuple<T, N>[] {
return slideWindow(this, windowSize);
return slideWindow(this, windowSize, stepSize);
};

Array.prototype.pairwise = function <T>(this: T[], callback: (a: T, b: T) => void): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import type { SizedTuple } from '../../model/index.js';
export const slideWindow = <T, N extends number>(
array: T[],
windowSize: N = 2 as N,
stepSize = 1,
): SizedTuple<T, N>[] => {
const result: SizedTuple<T, N>[] = [];
const window = [];
for (const element of array) {
window.push(element);
if (window.length === windowSize) {
result.push([...window] as SizedTuple<T, N>);
window.shift();
window.splice(0, stepSize);
}
}
return result;
Expand Down

0 comments on commit ee83f34

Please sign in to comment.