From b874f1f3109779564f3fbd101836f39b93e78d5e Mon Sep 17 00:00:00 2001 From: Carlos de la Orden Date: Thu, 28 Dec 2023 15:44:29 +0100 Subject: [PATCH] day 9 part 1 --- src/days/9/__snapshots__/index.test.ts.snap | 65 ++--------------- src/days/9/index.test.ts | 76 +++++++++++++------- src/days/9/index.ts | 78 +++++++++------------ 3 files changed, 90 insertions(+), 129 deletions(-) diff --git a/src/days/9/__snapshots__/index.test.ts.snap b/src/days/9/__snapshots__/index.test.ts.snap index 35db6e3..6cc0a78 100644 --- a/src/days/9/__snapshots__/index.test.ts.snap +++ b/src/days/9/__snapshots__/index.test.ts.snap @@ -1,68 +1,15 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`expandWithDifferences handles neg values 1`] = ` +exports[`Day 9 Mirage maintenance reduceHistories (recursive) generates prev histories 1`] = ` [ [ - -9, - -13, - -17, - -21, - -25, - -29, - -33, - -37, - -41, - -45, - -49, - -53, - -57, - -61, - -65, - -69, - -73, - -77, - -81, - -85, - -89, + 3, + 3, + 3, + 3, + 3, ], [ - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - -4, - ], - [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, diff --git a/src/days/9/index.test.ts b/src/days/9/index.test.ts index 299ef95..c09f175 100644 --- a/src/days/9/index.test.ts +++ b/src/days/9/index.test.ts @@ -1,32 +1,56 @@ -import { explode } from '@/lib/utils' -import { calculateDifferences, expandWithDifferences } from '.' +import { + calculateDifferences, + calculateNext, + isAllZeros, + makeHistory, + parseInput, + reduceHistories, +} from '.' -describe('calculateDifferences', () => { - it('creates a new Array with differences', () => { - const result = calculateDifferences([0, 3, 6, 9, 12, 15]) - expect(result).toEqual([3, 3, 3, 3, 3]) - const result2 = calculateDifferences(result) - expect(result2).toEqual([0, 0, 0, 0]) +describe('Day 9 Mirage maintenance', () => { + describe('parseInput', () => { + it('generates array of histories', () => { + expect(parseInput('0 3 6 9 12 15\n1 2 3 4')).toEqual([ + [0, 3, 6, 9, 12, 15], + [1, 2, 3, 4], + ]) + }) }) -}) - -describe('expandWithDifferences', () => { - it('creates an Array of dimishing differences from original row', () => { - const result = expandWithDifferences([0, 3, 6, 9, 12, 15]) - expect(result).toEqual([ - [0, 3, 6, 9, 12, 15], - [3, 3, 3, 3, 3], - [0, 0, 0, 0], - ]) + describe('isAllZeros', () => { + it('returns true if array is composed of only 0s', () => { + expect(isAllZeros([0])).toBe(true) + expect(isAllZeros([])).toBe(true) + expect(isAllZeros([1, 0])).toBe(false) + }) + }) + describe('calculateDifferences', () => { + it('creates a new Array with differences', () => { + const result = calculateDifferences([0, 3, 6, 9, 12, 15]) + expect(result).toEqual([3, 3, 3, 3, 3]) + const result2 = calculateDifferences(result) + expect(result2).toEqual([0, 0, 0, 0]) + }) }) - it('handles neg values', () => { - const result = expandWithDifferences( - explode( - '-9 -13 -17 -21 -25 -29 -33 -37 -41 -45 -49 -53 -57 -61 -65 -69 -73 -77 -81 -85 -89', - ' ' - ).map(Number) - ) - expect(result).toMatchSnapshot() + describe('reduceHistories (recursive)', () => { + it('generates prev histories', () => { + const result = reduceHistories([0, 3, 6, 9, 12, 15]) + expect(result).toMatchSnapshot() + }) + }) + describe('calculateNext', () => { + it('returns the next value in the history', () => { + expect(calculateNext([0, 3, 6, 9, 12, 15])).toBe(18) + expect(calculateNext([1, 3, 6, 10, 15, 21])).toBe(28) + expect(calculateNext([10, 13, 16, 21, 30, 45])).toBe(68) + expect( + calculateNext( + makeHistory('9 8 7 6 5 4 3 2 1 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11') + ) + ).toBe(-12) + expect(calculateNext(makeHistory('-9 -13 -17 -21 -25 -29 -33 -37'))).toBe( + -41 + ) + }) }) }) diff --git a/src/days/9/index.ts b/src/days/9/index.ts index 00ec3b3..c58aa7a 100644 --- a/src/days/9/index.ts +++ b/src/days/9/index.ts @@ -1,63 +1,53 @@ import { explode, splitLines, sum } from '@/lib/utils' import assert from 'assert' -import { createPipe, map, pipe, tap } from 'remeda' +import { createPipe, equals, last, map, pipe } from 'remeda' -const parseInput = createPipe( - splitLines, - map((l) => explode(l, ' ').map(Number)) -) +export const makeHistory = (line: string) => explode(line, ' ').map(Number) + +export const parseInput = createPipe(splitLines, map(makeHistory)) + +export const isAllZeros = (xs: number[]) => + xs.length === 0 || xs.every(equals(0)) + +export const printPyramid = (hs: number[][]) => + hs.reduce((acc, h, i) => { + acc += ' '.repeat(i) + h.join(' ') + '\n' + return acc + }, '') export const calculateDifferences = (seq: number[]) => seq.reduce((acc, n, index) => { - if (index < seq.length - 1) { - const next = seq[index + 1] - if (next) { - acc.push(next - n) - } + if (index > 0) { + acc.push(n - (seq.at(index - 1) as number)) } return acc }, [] as number[]) -export const expandWithDifferences = (seq: number[]) => { - return seq.reduce( - (acc, _seq, index) => { - if (acc.at(-1)?.every((x) => x === 0)) return acc - const differences = calculateDifferences(acc[index] as number[]) - acc.push(differences) - return acc - }, - [seq] - ) +/** + * Returns the differences until a [0...0] array is found. + * Does not include the original + * @param from initial history + * @returns + */ +export function reduceHistories(from: number[]): number[][] { + if (isAllZeros(from)) return [] + const next = calculateDifferences(from) + return [next].concat(reduceHistories(next)) } -export const extrapolateNextValue = (seqs: number[][]): number => { - const reversed = seqs.reverse() - reversed[0] = Array.from({ length: seqs.at(-1)?.length ?? 0 }).fill( - 0 - ) as number[] - return reversed - .reduce( - (acc, _seq, index) => { - const nextRow = reversed[index + 1] - if (!nextRow) return acc - acc.push((nextRow.at(-1) as number) + (acc.at(-1) as number)) - return acc - }, - [0] - ) - .at(-1) as number +export const calculateNext = (history: number[], debug = false) => { + assert(history.length, 'empty history') + const histories = reduceHistories(history) + if (debug) { + console.log(printPyramid([history].concat(histories))) + } + const next = histories.reduceRight((acc, h) => (last(h) ?? 0) + acc, 0) + return next + (last(history) ?? 0) } export function day9PartOne(sample: string, input: string) { assert(sample && input, 'Bad input data') - const solution = pipe( - input, - parseInput, - map(expandWithDifferences), - tap(console.log), - map(extrapolateNextValue), - sum - ) + const solution = pipe(input, parseInput, map(calculateNext), sum) console.log('Part One', solution) }