Skip to content

Commit

Permalink
feat: backported p2 solution for p1
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexAegis committed Dec 13, 2023
1 parent 9d32174 commit 4534bd6
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 151 deletions.
2 changes: 1 addition & 1 deletion .github/badges/typescript/2023.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"label": "Advent of TypeScript 2023",
"message": "11/25",
"message": "12/25",
"color": "orange"
}
27 changes: 16 additions & 11 deletions solutions/typescript/2023/12/src/p1.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { cartesianCombinations, task } from '@alexaegis/advent-of-code-lib';
import { task } from '@alexaegis/advent-of-code-lib';
import packageJson from '../package.json';
import { parse } from './parse.js';

function generateVariations(damagedLog: string, criteria: RegExp): string[] {
const variants = [...damagedLog].map((entry) => (entry === '?' ? ['#', '.'] : [entry]));
return cartesianCombinations(...variants)
.map((combination) => combination.join(''))
.filter((combination) => criteria.test(combination));
}
import { calculateVariations, parse } from './parse.js';

export const p1 = (input: string): number =>
parse(input)
.map((spring) => generateVariations(spring.log, spring.criteriaRegExp).length)
.map((entry) => {
const [currentCriteria, ...remainingCriteria] = entry.criteria;
if (!currentCriteria) {
throw new Error('no criteria for line');
}
return calculateVariations({
currentCriteria,
currentOriginalCriteria: currentCriteria,
rebuiltLog: '',
remainingCriteria,
remainingDamagedLog: entry.log,
});
})
.sum();

await task(p1, packageJson.aoc); // 7118 ~0ms
await task(p1, packageJson.aoc); // 7118 ~30.83ms
135 changes: 9 additions & 126 deletions solutions/typescript/2023/12/src/p2.ts
Original file line number Diff line number Diff line change
@@ -1,120 +1,6 @@
import { task } from '@alexaegis/advent-of-code-lib';
import packageJson from '../package.json';
import { parse, type SpringLog } from './parse.js';

interface State {
rebuiltLog: string;
currentCriteria: number;
currentOriginalCriteria: number;
remainingDamagedLog: string;
remainingCriteria: number[];
}

const calculateVariations = (state: State, cache: Map<string, number>): number => {
const key =
state.remainingCriteria.join(',') +
';' +
state.remainingDamagedLog +
';' +
state.currentOriginalCriteria +
';' +
state.currentCriteria;

const cachedResult = cache.get(key);
if (cachedResult !== undefined) {
return cachedResult;
}

let result = cachedResult ?? 0;

while (state.currentCriteria > 0 && state.remainingDamagedLog.startsWith('#')) {
state.currentCriteria = state.currentCriteria - 1;
state.remainingDamagedLog = state.remainingDamagedLog.slice(1);
state.rebuiltLog = state.rebuiltLog + '#';
}

if (
state.currentCriteria === 0 &&
state.remainingCriteria.length === 0 &&
!state.remainingDamagedLog.includes('#')
) {
state.rebuiltLog += state.remainingDamagedLog.replaceAll('?', '.');
return 1;
}

while (
state.currentCriteria === state.currentOriginalCriteria &&
state.remainingDamagedLog.startsWith('.')
) {
state.remainingDamagedLog = state.remainingDamagedLog.slice(1);
state.rebuiltLog = state.rebuiltLog + '.';
}

if (state.currentCriteria > 0 && state.remainingDamagedLog.startsWith('.')) {
return 0;
}

if (state.currentCriteria === 0 && state.remainingDamagedLog.startsWith('#')) {
return 0;
}

if (
state.currentCriteria === 0 &&
(state.remainingDamagedLog.startsWith('.') || state.remainingDamagedLog.startsWith('?'))
) {
const nextCriteria = state.remainingCriteria.shift();

if (nextCriteria === undefined) {
state.currentOriginalCriteria = 0;
} else {
state.currentCriteria = nextCriteria;
state.currentOriginalCriteria = nextCriteria;
}

state.rebuiltLog = state.rebuiltLog + '.';
state.remainingDamagedLog = state.remainingDamagedLog.slice(1);
}

while (
state.currentCriteria === state.currentOriginalCriteria &&
state.remainingDamagedLog.startsWith('.')
) {
state.remainingDamagedLog = state.remainingDamagedLog.slice(1);
state.rebuiltLog = state.rebuiltLog + '.';
}

if (
state.currentCriteria === 0 &&
state.remainingDamagedLog.length === 0 &&
state.remainingCriteria.length === 0
) {
return 1;
}

if (state.remainingDamagedLog.startsWith('?')) {
result += calculateVariations(
{
...state,
remainingCriteria: [...state.remainingCriteria],
remainingDamagedLog: '#' + state.remainingDamagedLog.slice(1),
},
cache,
);

result += calculateVariations(
{
...state,
remainingCriteria: [...state.remainingCriteria],
remainingDamagedLog: '.' + state.remainingDamagedLog.slice(1),
},
cache,
);
} else if (state.currentCriteria > 0 && state.remainingDamagedLog.length > 0) {
result += calculateVariations(state, cache);
}
cache.set(key, result);
return result;
};
import { calculateVariations, parse, type SpringLog } from './parse.js';

const unfoldEntry =
(times: number) =>
Expand All @@ -134,17 +20,14 @@ export const p2 = (input: string): number =>
if (!currentCriteria) {
throw new Error('no criteria for line');
}
return calculateVariations(
{
currentCriteria,
currentOriginalCriteria: currentCriteria,
rebuiltLog: '',
remainingCriteria,
remainingDamagedLog: entry.log,
},
new Map(),
);
return calculateVariations({
currentCriteria,
currentOriginalCriteria: currentCriteria,
rebuiltLog: '',
remainingCriteria,
remainingDamagedLog: entry.log,
});
})
.sum();

await task(p2, packageJson.aoc); // 7030194981795 ~0ms
await task(p2, packageJson.aoc); // 7030194981795 ~539.06ms
131 changes: 119 additions & 12 deletions solutions/typescript/2023/12/src/parse.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,132 @@
export interface SpringLog {
/**
* `?` unknown
* `.` operational
* `#` damaged
*/
log: string;
criteria: number[];
criteriaRegExp: RegExp;
}

export const criteriaToRegExp = (criteria: number[]): RegExp =>
new RegExp('^\\.*' + criteria.map((brokenCount) => `#{${brokenCount}}`).join('\\.+') + '\\.*$');

export const parse = (input: string): SpringLog[] => {
return input.lines(false).map<SpringLog>((line) => {
const [log, critRaw] = line.splitIntoStringPair(' ');
const crit = critRaw.splitToInt({ delimiter: /,/ });
const criteria = critRaw.splitToInt({ delimiter: /,/ });
return {
log,
criteria: crit,
criteriaRegExp: criteriaToRegExp(crit),
criteria,
};
});
};

export interface State {
rebuiltLog: string;
currentCriteria: number;
currentOriginalCriteria: number;
remainingDamagedLog: string;
remainingCriteria: number[];
}

export const calculateVariations = (
state: State,
cache: Map<string, number> = new Map(),
): number => {
const key =
state.remainingCriteria.join(',') +
';' +
state.remainingDamagedLog +
';' +
state.currentOriginalCriteria +
';' +
state.currentCriteria;

const cachedResult = cache.get(key);
if (cachedResult !== undefined) {
return cachedResult;
}

let result = cachedResult ?? 0;

while (state.currentCriteria > 0 && state.remainingDamagedLog.startsWith('#')) {
state.currentCriteria = state.currentCriteria - 1;
state.remainingDamagedLog = state.remainingDamagedLog.slice(1);
state.rebuiltLog = state.rebuiltLog + '#';
}

if (
state.currentCriteria === 0 &&
state.remainingCriteria.length === 0 &&
!state.remainingDamagedLog.includes('#')
) {
state.rebuiltLog += state.remainingDamagedLog.replaceAll('?', '.');
return 1;
}

while (
state.currentCriteria === state.currentOriginalCriteria &&
state.remainingDamagedLog.startsWith('.')
) {
state.remainingDamagedLog = state.remainingDamagedLog.slice(1);
state.rebuiltLog = state.rebuiltLog + '.';
}

if (state.currentCriteria > 0 && state.remainingDamagedLog.startsWith('.')) {
return 0;
}

if (state.currentCriteria === 0 && state.remainingDamagedLog.startsWith('#')) {
return 0;
}

if (
state.currentCriteria === 0 &&
(state.remainingDamagedLog.startsWith('.') || state.remainingDamagedLog.startsWith('?'))
) {
const nextCriteria = state.remainingCriteria.shift();

if (nextCriteria === undefined) {
state.currentOriginalCriteria = 0;
} else {
state.currentCriteria = nextCriteria;
state.currentOriginalCriteria = nextCriteria;
}

state.rebuiltLog = state.rebuiltLog + '.';
state.remainingDamagedLog = state.remainingDamagedLog.slice(1);
}

while (
state.currentCriteria === state.currentOriginalCriteria &&
state.remainingDamagedLog.startsWith('.')
) {
state.remainingDamagedLog = state.remainingDamagedLog.slice(1);
state.rebuiltLog = state.rebuiltLog + '.';
}

if (
state.currentCriteria === 0 &&
state.remainingDamagedLog.length === 0 &&
state.remainingCriteria.length === 0
) {
return 1;
}

if (state.remainingDamagedLog.startsWith('?')) {
result += calculateVariations(
{
...state,
remainingCriteria: [...state.remainingCriteria],
remainingDamagedLog: '#' + state.remainingDamagedLog.slice(1),
},
cache,
);

result += calculateVariations(
{
...state,
remainingCriteria: [...state.remainingCriteria],
remainingDamagedLog: '.' + state.remainingDamagedLog.slice(1),
},
cache,
);
} else if (state.currentCriteria > 0 && state.remainingDamagedLog.length > 0) {
result += calculateVariations(state, cache);
}
cache.set(key, result);
return result;
};
2 changes: 1 addition & 1 deletion solutions/typescript/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
| [Day 9](/solutions/typescript/2023/09/) | [1.57ms](/solutions/typescript/2023/09/src/p1.ts) | [1.62ms](/solutions/typescript/2023/09/src/p2.ts) |
| [Day 10](/solutions/typescript/2023/10/) | [68.44ms](/solutions/typescript/2023/10/src/p1.ts) | [1.4s](/solutions/typescript/2023/10/src/p2.ts) |
| [Day 11](/solutions/typescript/2023/11/) | [104.54ms](/solutions/typescript/2023/11/src/p1.ts) | [104.48ms](/solutions/typescript/2023/11/src/p2.ts) |
| Day 12 | - | - |
| [Day 12](/solutions/typescript/2023/12/) | [30.83ms](/solutions/typescript/2023/12/src/p1.ts) | [539.06ms](/solutions/typescript/2023/12/src/p2.ts) |
| Day 13 | - | - |
| Day 14 | - | - |
| Day 15 | - | - |
Expand Down

0 comments on commit 4534bd6

Please sign in to comment.