Skip to content

Commit 32231b8

Browse files
committed
feat: day 5 print queue quiz 1/2 soln, #10
1 parent ae65aca commit 32231b8

File tree

7 files changed

+224
-0
lines changed

7 files changed

+224
-0
lines changed

src/2024/2024-12-05/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## Day 5: Print Queue
2+
3+
Visit the Advent of Code website for more information on this puzzle at:
4+
5+
**Source:** https://adventofcode.com/2024/day/5<br>
6+
**Status:** On-going
7+
8+
<br>
9+
10+
| Code | Description |
11+
| --- | --- |
12+
| **orderedUpdates.ts** | Has functions for finding correct "updates" according to defined "rules." It also counts the sum of middle page numbers from correctly-ordered "updates." |
13+
| **fileReader.ts** | Reads and transforms a text file for processing by the quiz scripts. |

src/2024/2024-12-05/input.txt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
39|89
2+
101|15
3+
101|95
4+
101|39
5+
5|48
6+
95|15
7+
5|89
8+
48|15
9+
101|48
10+
89|48
11+
95|89
12+
101|89
13+
95|48
14+
39|15
15+
5|39
16+
101|5
17+
39|95
18+
5|95
19+
39|48
20+
5|15
21+
89|15
22+
23+
5,39,95,89,48
24+
101,95,89,48,15
25+
5,48,15
26+
5,101,39,95,89
27+
95,15,48
28+
101,15,5,48,39
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import path from 'path'
2+
import { currentDirectory, readFile } from '@/utils/file.js'
3+
import { uniformArrayElements } from '@/utils/arrays.js'
4+
5+
export type Rules = Record<number, number[]>
6+
7+
export type QuizData = {
8+
rules: Rules;
9+
updates: number[][]
10+
}
11+
12+
/**
13+
* Reads and transforms quiz input text for processing.
14+
* @param fileName {string} Filename of input text relative to the calling function
15+
* @returns {QuizData} Formatted data
16+
*/
17+
export const fileReader = (fileName: string): QuizData => {
18+
const directory = currentDirectory(import.meta.url)
19+
const file = readFile(path.join(directory, '..', fileName))
20+
21+
const segments = file.split('\n\n')
22+
23+
if (
24+
segments[0] === undefined || // rules
25+
segments[1] === undefined // updates
26+
) {
27+
throw new Error('Undefined rules or updates data')
28+
}
29+
30+
const rules: Rules = segments[0]
31+
.split('\n')
32+
.reduce((list: Rules, item) => {
33+
const pair: number[] = item.split('|').map(Number)
34+
35+
if (!uniformArrayElements(pair, 'number')) {
36+
throw new Error('Invalid rules value')
37+
}
38+
39+
const key = pair[0] as number
40+
41+
if (list[key] === undefined) {
42+
list[key] = [pair[1] as number]
43+
} else {
44+
list[key].push(pair[1] as number)
45+
}
46+
47+
return list
48+
}, {})
49+
50+
return {
51+
rules,
52+
updates: segments[1]
53+
.split('\n')
54+
.map(item => item.split(',').map(Number))
55+
}
56+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import type { QuizData, Rules } from './fileReader.js'
2+
import { uniformArrayElements, arrayMiddleIndex } from '@/utils/arrays.js'
3+
4+
/**
5+
* Checks if an "update" list is correct according to defined "rules"
6+
* @param rules {Rules} Object containing parsed and formatted rules and updates data
7+
* @param updateItems {number[]} "updates" item content
8+
* @returns Flag indicating if the set of `updateItems` is correct
9+
*/
10+
export const isOrderedReport = (rules: Rules, updateItems: number[]): boolean => {
11+
let isOrdered = true
12+
13+
if (!uniformArrayElements(updateItems, 'number')) {
14+
throw new Error('Invalid updateItems item/s')
15+
}
16+
17+
for (let i = 0; i < updateItems.length - 1; i += 1) {
18+
const currentItem = updateItems[i] as number
19+
20+
// Current "update" item should have en entry in the "rules" object
21+
if (rules[currentItem] === undefined) {
22+
isOrdered = false
23+
break
24+
}
25+
26+
// Get the rest of items after the current item for comparison
27+
const afterItems = updateItems.filter((_, index) => index > i)
28+
29+
// Current item's "rule" should have the after-item entries
30+
if (!afterItems.every(item => rules[currentItem]?.includes(item))) {
31+
isOrdered = false
32+
break
33+
}
34+
35+
// Backtrack current item's inclusion in previous item maps
36+
if (i > 0) {
37+
for (let j = 0; j < i; j += 1) {
38+
const beforeItem = updateItems[j] as number
39+
40+
if (rules[beforeItem] === undefined) {
41+
isOrdered = false
42+
break
43+
}
44+
45+
if (!rules[beforeItem].includes(currentItem)) {
46+
isOrdered = false
47+
break
48+
}
49+
}
50+
}
51+
}
52+
53+
return isOrdered
54+
}
55+
56+
/**
57+
* Counts the sum of middle page numbers from correctly-ordered "updates"
58+
* @param data {QuizData} Object containing "rules" and "updates" input
59+
* @param verbose {boolean} Flag to display processing log messages. Defaults to false.
60+
* @returns {number}
61+
*/
62+
export const sumOfCorrectUpdates = (data: QuizData, verbose: boolean = false): number => {
63+
let sum = 0
64+
65+
for (let i = 0; i < data.updates.length; i += 1) {
66+
const isOrdered = isOrderedReport(data.rules, data.updates[i] ?? [])
67+
68+
if (isOrdered) {
69+
if (verbose) {
70+
console.log('---correct', data.updates[i])
71+
}
72+
73+
const mid = arrayMiddleIndex(data.updates[i] as number[])
74+
const item = data.updates[i]?.[mid - 1]
75+
sum += item ?? 0
76+
}
77+
}
78+
79+
return sum
80+
}

src/2024/2024-12-05/main.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { fileReader } from './lib/fileReader.js'
2+
import { sumOfCorrectUpdates } from './lib/orderedUpdates.js'
3+
import type { QuizData } from './lib/fileReader.js'
4+
5+
const data: QuizData = fileReader('input.txt')
6+
7+
/**
8+
* Part 1/2 of the 2024-12-05 quiz
9+
* Counts the sum of middle pages from correct updates
10+
*/
11+
const quiz20241205 = () => {
12+
const sum = sumOfCorrectUpdates(data, true)
13+
console.log('Sum of middle page numbers:', sum)
14+
}
15+
16+
quiz20241205()

src/2024/2024-12-05/sample.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { test, expect } from 'vitest'
2+
import { sumOfCorrectUpdates } from './lib/orderedUpdates.js'
3+
import { fileReader } from './lib/fileReader.js'
4+
import type { QuizData } from './lib/fileReader.js'
5+
6+
const data: QuizData = fileReader('input.txt')
7+
8+
test('Count middle pages - demo', () => {
9+
expect(sumOfCorrectUpdates(data)).toBe(232)
10+
})

src/utils/arrays.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,24 @@ export const arrangeArray = (order: ARRAY_ORDERING) =>
1818
throw new Error('Invalid ordering')
1919
}
2020
}
21+
22+
/**
23+
* Checks if array elements have the same type and has no null or undefined values
24+
* @param items {S[]} array of elements
25+
* @param type {T} type name of the elements inside the `items` array
26+
* @returns {boolean} Flag indicating if all array elements have the same type
27+
*/
28+
export const uniformArrayElements = <S, T>(items: S[], type: T): boolean => {
29+
return (
30+
items.filter(value => typeof value === type).length === items.length
31+
)
32+
}
33+
34+
/**
35+
* Retrieves the middle (center) index of an array
36+
* @param list {T[]} 1-dimensional array
37+
* @returns {number} Middle index of an array
38+
*/
39+
export const arrayMiddleIndex = <T>(list: T[]): number => {
40+
return Math.floor(list.length / 2) + list.length % 2
41+
}

0 commit comments

Comments
 (0)