Skip to content

Commit

Permalink
chore: solution draft
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexAegis committed Jan 1, 2025
1 parent 8c483ad commit 64cbe34
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 67 deletions.
1 change: 1 addition & 0 deletions solutions/typescript/2024/01/src/p1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export const p1 = (input: string): number => {
.map(([l, r]) => Math.abs(l - r))
.sum();
};

await task(p1, packageJson.aoc); // 1722302 ~16.04ms
2 changes: 1 addition & 1 deletion solutions/typescript/2024/06/src/p1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const p1 = (input: string): number => {
guardPosition.addMut(guardDirection);
guardPath.add(guardPosition.toString());
}
//g.print((n) => (guardPath.has(n.coordinate.toString()) ? 'X' : n.toString()));
g.print((n) => (guardPath.has(n.coordinate.toString()) ? 'X' : n.toString()));
return guardPath.size;
};

Expand Down
230 changes: 176 additions & 54 deletions solutions/typescript/2024/06/src/p2.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,186 @@
import { Direction, task } from '@alexaegis/advent-of-code-lib';
import { BoundingBox, Direction, task, Vec2, type Vec2String } from '@alexaegis/advent-of-code-lib';
import packageJson from '../package.json' assert { type: 'json' };

export const p2 = (input: string): number => {
const g = input.toGridGraph({});
const possibleObstructionCoordinates = g.nodeValues
.filter((node) => node.value === '.')
.map((node) => node.coordinate);
return possibleObstructionCoordinates.filter((possibleObstructionCoordinate) => {
const g = input.toGridGraph({});

const guardNode = g.findNode((node) => node.value === '^');
if (!guardNode) {
throw new Error('Guard not found');
export interface PatrolResult {
path: Set<Vec2String>;
encounters: Set<Vec2String>;
isLoop: boolean;
movement: Move[];
}

interface Move {
position: Vec2;
direction: Direction;
}

export const patrol = (obscructions: Set<string>, map: BoundingBox, from: Vec2): PatrolResult => {
let guardPosition = from.clone();
let guardDirection = Direction.NORTH.clone();
const path = new Set<Vec2String>();
const encounters = new Set<Vec2String>();
const guardMovement = new Set<string>();
const movementPath: Move[] = [];

path.add(guardPosition.toString());
guardMovement.add(guardPosition.toString() + '+' + guardDirection.toString());
movementPath.push({ position: guardPosition, direction: guardDirection });

let isLoop = false;

while (true) {
let forwardPosition = guardPosition.add(guardDirection);
if (!forwardPosition.isWithin(map)) {
break;
}

const obsructionNode = g.getNode(possibleObstructionCoordinate);
if (!obsructionNode) {
throw new Error('Obstruction not found');
if (obscructions.has(forwardPosition.toString())) {
encounters.add(forwardPosition.toString());
guardDirection = guardDirection.rotateLeft();
}

obsructionNode.setValue('#');
guardNode.setValue('.');
let guardPosition = guardNode.coordinate;
let guardDirection = Direction.NORTH.clone();
const guardPath = new Set<string>();
const guardMovement = new Set<string>();

guardPath.add(guardPosition.toString());
guardMovement.add(guardPosition.toString() + '+' + guardDirection.toString());

let isLoop = false;
let i = 0;
while (true) {
i++;
let forwardPosition = guardPosition.add(guardDirection);
let forwardNode = g.getNode(forwardPosition);
if (!forwardNode) {
// Not a loop
break;
}
if (forwardNode.value === '#') {
guardDirection = guardDirection.rotateLeft();
}

const pathLengthBeforeStep = guardMovement.size;
guardPosition.addMut(guardDirection);
guardPath.add(guardPosition.toString());
guardMovement.add(guardPosition.toString() + '+' + guardDirection.toString());

const pathLengthAfterStep = guardMovement.size;
if (pathLengthBeforeStep === pathLengthAfterStep) {
isLoop = true;
break;
}
guardPosition.addMut(guardDirection);
path.add(guardPosition.toString());
const move = guardPosition.toString() + '+' + guardDirection.toString();
movementPath.push({ position: guardPosition, direction: guardDirection });

if (guardMovement.has(move)) {
isLoop = true;
break;
} else {
guardMovement.add(move);
}
//g.print((n) => (guardPath.has(n.coordinate.toString()) ? 'X' : n.toString()));
//console.log('--------', daysWithoutUpdate, isLoop, i);
// possibleObstructionNode.setValue('.');
return isLoop;
}
return {
path,
encounters,
isLoop,
};
};

/**
* Since the guard can only rotate right, and 90 degrees, a loop always
* will look like a rectangle
*/
export const matchEnclosure = (
position: Vec2,
direction: Direction,
pivotPlacement: Direction,
boundingBox: BoundingBox,
obscructions: Set<Vec2String>,
): boolean => {
const possibleObstruction = position.add(direction);
if (obscructions.has(possibleObstruction.toString())) {
return false; // Already obsctructed
}

const firstCorner = position.add(direction.rotateLeft(1), {
times: (v) => !obscructions.has(v.toString()) && boundingBox.contains(v),
});
console.log('fc', firstCorner);

return false;
};

export const createParametricEnclosure =
(pivot: Vec2, pivotPlacement: Direction) => (size: Vec2) => {};

export const createEnclosure = (pivot: Vec2, pivotPlacement: Direction, size: Vec2): Vec2[] => {
const corners = [pivot];

const vertical = pivotPlacement.y > 0 ? new Vec2(1, -size.y) : new Vec2(-1, size.y);
const horizontal = pivotPlacement.x > 0 ? new Vec2(-size.x, -1) : new Vec2(size.x, 1);
// Horizontal

corners.push(pivot.add(vertical));
corners.push(pivot.add(horizontal));

corners.push(pivot.add(vertical.add(horizontal)));

return corners;
};

const enclosurePivotMap = {
[Direction.NORTH.toString()]: Direction.NORTHWEST,
[Direction.EAST.toString()]: Direction.NORTHEAST,
[Direction.SOUTH.toString()]: Direction.SOUTHEAST,
[Direction.WEST.toString()]: Direction.SOUTHWEST,
} as const;

export const p2 = (input: string): number => {
const g = input.toGridGraph();
const boundingBox = g.boundingBox();

const obstructions = new Set(
g.nodeValues.filter((node) => node.value === '#').map((node) => node.coordinate.toString()),
);

const freeNodes = new Set(
g.nodeValues.filter((node) => node.value === '.').map((node) => node.coordinate.toString()),
);

const guardNode = g.findNode((node) => node.value === '^');
if (!guardNode) {
throw new Error('Guard not found');
}

g.print();
console.log('23332323----------------------');

const originalPatrolResult = patrol(obstructions, boundingBox, guardNode.coordinate);

const enclosure = createEnclosure(new Vec2(3, 3), Direction.SOUTHWEST, new Vec2(3, 3));

g.print((n) =>
enclosure.map((e) => e.toString()).includes(n.coordinate.toString())
? enclosure
.map((e) => e.toString())
.indexOf(n.coordinate.toString())
.toString()
: originalPatrolResult.path.has(n.coordinate.toString())
? 'X'
: originalPatrolResult.encounters.has(n.coordinate.toString())
? 'E'
: n.toString(),
);

const result = originalPatrolResult.movement.filter((move) => {
const pivotPlacement = enclosurePivotMap[move.direction.toString()];
if (!pivotPlacement) {
throw new Error('invalid direction');
}
return matchEnclosure(
move.position,
move.direction,
pivotPlacement,
boundingBox,
obstructions,
);
}).length;

// const possibleObstructionCoordinates = [...originalPatrolResult.path].filter(
// (p) => p !== guardNode.coordinate.toString(),
// );

//const possibleObstructionCoordinates = [...freeNodes];
//
//return possibleObstructionCoordinates.filter((possibleObstructionCoordinate) => {
// const newObstructions = new Set(obstructions);
// newObstructions.add(possibleObstructionCoordinate);
//
// const patrolResult = patrol(newObstructions, map, guardNode.coordinate);
//
// //g.print((n) =>
// // patrolResult.path.has(n.coordinate.toString())
// // ? 'X'
// // : n.coordinate.toString() === possibleObstructionCoordinate
// // ? 'O'
// // : n.toString(),
// //);
// // console.log('--------', patrolResult);
// return patrolResult.isLoop;
//}).length;
return result;
};

await task(p2, packageJson.aoc); // 4602 ~0.09ms
await task(p2, packageJson.aoc); // 1563 ~0.09ms
// 1563 too low
48 changes: 48 additions & 0 deletions solutions/typescript/libs/lib/src/model/vector/vec2.class.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,52 @@ describe('Vec2', () => {
});
});
});

describe('addMut', () => {
it('should add a vector to another', () => {
const target = new Vec2(1, 1);
const delta = new Vec2(2, 3);
const expectedResult = new Vec2(3, 4);
target.addMut(delta);
expect(target).toEqual(expectedResult);
});

it('should add a vector to another many times', () => {
const target = new Vec2(1, 1);
const delta = new Vec2(2, 3);
const expectedResult = new Vec2(9, 13);
target.addMut(delta, { times: 4 });
expect(target).toEqual(expectedResult);
});

it('should add a vector to another multiple times while it should', () => {
const target = new Vec2(1, 1);
const delta = new Vec2(2, 3);
const expectedResult = new Vec2(9, 13);
target.addMut(delta, {
times: (_v, i) => i < 4,
});
expect(target).toEqual(expectedResult);
});

it('should add a vector to another multiple times while it can', () => {
const target = new Vec2(1, 1);
const delta = new Vec2(2, 3);
const expectedResult = new Vec2(5, 7);
target.addMut(delta, {
times: (v, _i) => v.x < 7,
});
expect(target).toEqual(expectedResult);
});

it('should not add a vector to another multiple times if it cant', () => {
const target = new Vec2(1, 1);
const delta = new Vec2(2, 3);
const expectedResult = new Vec2(1, 1);
target.addMut(delta, {
times: (v, _i) => v.x < 1,
});
expect(target).toEqual(expectedResult);
});
});
});
22 changes: 18 additions & 4 deletions solutions/typescript/libs/lib/src/model/vector/vec2.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export class Vec2 implements Vec2Like {
public add(
coord: Vec2Like,
options?: {
times?: number;
times?: number | ((v: Vec2, i: number) => boolean);
limit?: BoundingBox | ((v: Vec2Like) => boolean);
},
): Vec2 {
Expand Down Expand Up @@ -190,16 +190,30 @@ export class Vec2 implements Vec2Like {
public addMut(
v: Vec2Like,
options?: {
times?: number;
times?: number | ((v: Vec2, i: number) => boolean);
limit?: BoundingBox | ((v: Vec2Like) => boolean);
flipX?: boolean;
flipY?: boolean;
},
): this {
const originalX = this.x;
const originalY = this.y;
const diffX = v.x * (options?.times ?? 1);
const diffY = v.y * (options?.times ?? 1);

let diffX = 0;
let diffY = 0;

if (typeof options?.times === 'function') {
let times = 0;
while (options.times(this.add(v, { times: times + 1 }), times)) {
times++;
}
diffX = v.x * times;
diffY = v.y * times;
} else {
const times = options?.times ?? 1;
diffX = v.x * times;
diffY = v.y * times;
}

this.x += options?.flipX ? -diffX : diffX;
this.y += options?.flipY ? -diffY : diffY;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,12 @@ export const benchTask = async <Input, Result = string, Args = undefined>(
resources: TaskResources<Input, Args>,
logger?: Logger,
): Promise<Result> => {
// TODO: Remove the if once PerformanceObserver is implemented in bun
if (process.versions['bun'] === undefined) {
const obs = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
logger?.(`${entry.name}: ${roundToDecimal(entry.duration, 2)} ms`);
});
const obs = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
logger?.(`${entry.name}: ${roundToDecimal(entry.duration, 2)} ms`);
});
obs.observe({ entryTypes: ['measure'], buffered: true });
}
});
obs.observe({ entryTypes: ['measure'], buffered: true });

performance.mark('runstart');
const result = await runner(resources.input, resources.args);
Expand Down

0 comments on commit 64cbe34

Please sign in to comment.