Skip to content

feat: day 4 ceres search 20241204 #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ FROM base AS production
ENV NODE_ENV=production
COPY --from=build /opt/app/dist /opt/app/dist
COPY package*.json ./
RUN npm install && npm prune --production
USER user
EXPOSE 9229
CMD ["sh"]
1 change: 0 additions & 1 deletion docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ services:
dockerfile: Dockerfile
target: production
volumes:
- ./output:/opt/app/output
- /opt/app/node_modules
ports:
- "9229:9229"
Expand Down
8 changes: 8 additions & 0 deletions src/2024/2024-12-01/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,11 @@ Visit the Advent of Code website for more information on this puzzle at:

**Source:** https://adventofcode.com/2024/day/1<br>
**Status:** Complete ⭐⭐

<br>

| Code | Description |
| --- | --- |
| **listTotalDistance.ts** | Calculates the total distance between the smallest value-pairs from array `a` and array `b`. |
| **similarityScore.ts** | Calculates the similarity scores of elements in array `a` with array `b` by multiplying each element in array `a` with the total number of its duplicates in array `b`. |
| **fileReader.ts** | Reads a two-column (2) number input separated by three (3) space characters from a text file. |
1 change: 0 additions & 1 deletion src/2024/2024-12-01/lib/fileReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export const fileReader = (): arrayLists => {
const pair = item.split(' ')

if (pair[0] === undefined || pair[1] === undefined) {
console.log(pair)
throw new Error('Undefined value')
}

Expand Down
7 changes: 7 additions & 0 deletions src/2024/2024-12-02/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,10 @@ Visit the Advent of Code website for more information on this puzzle at:

**Source:** https://adventofcode.com/2024/day/2<br>
**Status:** Complete ⭐⭐

<br>

| Code | Description |
| --- | --- |
| **countSafeReports.ts** | Contains functions for counting the number of "safe" reports with or without a problem dampener. |
| **fileReader.ts** | Reads the quiz's input file into two (2) string arrays |
8 changes: 7 additions & 1 deletion src/2024/2024-12-03/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,10 @@
Visit the Advent of Code website for more information on this puzzle at:

**Source:** https://adventofcode.com/2024/day/3<br>
**Status:** Completed ⭐⭐
**Status:** Complete ⭐⭐

<br>

| Code | Description |
| --- | --- |
| **extractMultiply.ts** | Contains functions that parse and sum the multiplication result of `mul(x,y)` sequences from corrupted (garbled) text. |
14 changes: 14 additions & 0 deletions src/2024/2024-12-04/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## Day 4: Ceres Search

Visit the Advent of Code website for more information on this puzzle at:

**Source:** https://adventofcode.com/2024/day/4<br>
**Status:** Complete ⭐⭐

<br>

| Code | Description |
| --- | --- |
| **wordCheckerUtils.ts** | Contains functions for checking the existence of a sequence of characters (words) vertically, horizontally, and diagonally in a 2x2 character array. |
| **wordCount.ts** | Counts the number of occurrences of a word in a 2x2 character array. |
| **xmasCount.ts** | Counts the number of (2x) crossed "MAS" words overlapping at the letter "A" a 2x2 character array. |
9 changes: 9 additions & 0 deletions src/2024/2024-12-04/input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
SAMPLEONLY
REPLACEITW
ACTUALAOC.
INPUTEXT..
ABCDEFGHIJ
XMASXMASXM
GMUMSHSGSH
MXAXAXMARD
ASHSGJM2MX
105 changes: 105 additions & 0 deletions src/2024/2024-12-04/lib/wordCheckerUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
export type CharacterArray = string[][]

interface CoordinateBase {
x: number;
y: number;
}

interface Coordinate extends CoordinateBase {
direction: 1 | -1;
}

interface CoordinateData {
xDirection: 1 | -1;
yDirection: 1 | -1;
data: CharacterArray
}

/**
* Finds the `WORD` input parameter in the vertical directions (up/down) from an (x,y) coordinate
* @typedef coord {Coordinate} Coordinate object
* @param coord.x {number} x coordinate (array x index)
* @param coord.y {number} y coordinate (array y index)
* @param coord.direction {number} Up or down letter-checking direction
* - `-1` for "up" going to (0,0)
* - `1` for "down" going to (N,N) from the `coord`
* @param fullData {CharacterArray} 2D array of strings consisting of letters per item
* @param WORD {string} Word to find
* @returns {boolean} Flag indicating the existence of the `WORD`
*/
export const checkVertical = (coord: Coordinate, fullData: CharacterArray, WORD: string): boolean => {
let yIndex = coord.y
let subWord = ''

if (!Array.isArray(fullData)) return false

for (let i = 0; i < WORD.length; i += 1) {
if (yIndex < 0) break
if (yIndex >= fullData.length) break

subWord += (fullData[yIndex])?.[coord.x]
yIndex += (coord.direction * 1)
}

return subWord === WORD
}

/**
* Finds the `WORD` input parameter in the horizontal directions (left/right) from an (x,y) coordinate
* @typedef coord {Coordinate} Coordinate object
* @param coord.x {number} x coordinate (array x index)
* @param coord.y {number} y coordinate (array y index)
* @param coord.direction {number} `-1` for "left" going to (0,0) or `1` for "right" going to (N,N) from the `coord`
* @param rowData {string[]} Array of row-wise letters from a 2D array
* @returns {boolean} Flag indicating the existence of the `WORD`
* @param WORD {string} Word to find
*/
export const checkHorizontal = (coord: Coordinate, rowData: string[], WORD: string): boolean => {
let xIndex = coord.x
let subWord = ''

if (!Array.isArray(rowData)) return false

for (let i = 0; i < WORD.length; i += 1) {
if (xIndex < 0) break
if (xIndex >= rowData.length) break

subWord += rowData[xIndex]
xIndex += (coord.direction * 1)
}

return subWord === WORD
}

/**
* Finds the `WORD` input parameter in the horizontal directions from an (x,y) coordinate
* @typedef coord {Coordinate} Coordinate object
* @param coord.x {number} x coordinate (array x index)
* @param coord.y {number} y coordinate (array y index)
* @typedef param {CoordinateData} Direction and data object
* @param param.xDirection {number} `-1` for "left" going to (0,0) or `1` for "right" going to (N,N) from the `coord`
* @param param.yDirection {number} `-1` for "up" going to (0,0) or `1` for "down" going to (N,N) from the `coord`
* @param param.data {CharacterArray} 2D string array containing the input text
* @returns {boolean} Flag indicating the existence of the `WORD`
* @param WORD {string} Word to find
*/
export const checkDiagonal = (coord: CoordinateBase, param: CoordinateData, WORD: string): boolean => {
let xIndex = coord.x
let yIndex = coord.y
let subWord = ''

if (!Array.isArray(param.data)) return false
if (param.data[0] === undefined) return false

for (let i = 0; i < WORD.length; i += 1) {
if (xIndex < 0 || xIndex >= param.data[0].length) break
if (yIndex < 0 || yIndex >= param.data.length) break

subWord += (param.data[yIndex])?.[xIndex]

xIndex += (param.xDirection * 1)
yIndex += (param.yDirection * 1)
}

return subWord === WORD
}
82 changes: 82 additions & 0 deletions src/2024/2024-12-04/lib/wordCount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { checkVertical, checkHorizontal, checkDiagonal } from './wordCheckerUtils.js'

/**
* Counts the number of occurence of the `WORD` from a set of input
* @param data {CharacterArray} 2D string array containing the input text
* @param WORD_TO_FIND {string} Word to find
* @returns {number} Number of `WORD`s
*/
export const wordCount = (data: string[][], WORD_TO_FIND: string): number => {
let xmasCount = 0
const firstLetter = WORD_TO_FIND[0]

for (let y = 0; y < data.length; y += 1) {
const row = data[y]

if (!Array.isArray(row)) continue

if (row.filter(
item => typeof item !== 'string').length > 0
) continue

for (let x = 0; x < row.length; x += 1) {
const letter = row[x]

if (letter !== firstLetter) continue

// Check WORD_TO_FIND down
if (checkVertical(
{ x, y, direction: 1 }, data, WORD_TO_FIND)) xmasCount += 1

// Check WORD_TO_FIND up
if (checkVertical(
{ x, y, direction: -1 }, data, WORD_TO_FIND)) xmasCount += 1

// Check WORD_TO_FIND right
if (checkHorizontal(
{ x, y, direction: 1 }, row, WORD_TO_FIND)) xmasCount += 1

// Check WORD_TO_FIND left
if (checkHorizontal(
{ x, y, direction: -1 }, row, WORD_TO_FIND)) xmasCount += 1

// Check WORD_TO_FIND diagonally right-up
if (checkDiagonal(
{ x, y },
{ xDirection: 1, yDirection: -1, data },
WORD_TO_FIND
)) {
xmasCount += 1
}

// Check WORD_TO_FIND diagonally right-down
if (checkDiagonal(
{ x, y },
{ xDirection: 1, yDirection: 1, data },
WORD_TO_FIND
)) {
xmasCount += 1
}

// Check WORD_TO_FIND diagonally left-up
if (checkDiagonal(
{ x, y },
{ xDirection: -1, yDirection: -1, data },
WORD_TO_FIND
)) {
xmasCount += 1
}

// Check WORD_TO_FIND diagonally left-down
if (checkDiagonal(
{ x, y },
{ xDirection: -1, yDirection: 1, data },
WORD_TO_FIND
)) {
xmasCount += 1
}
}
}

return xmasCount
}
56 changes: 56 additions & 0 deletions src/2024/2024-12-04/lib/xmasCount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { checkDiagonal } from './wordCheckerUtils.js'

/**
* Counts the number of (2x) crossed "MAS" words overlapping at the letter "A"
* @param data {CharacterArray} 2D string array containing the input text
* @param WORD_TO_FIND {string} Word to find ("MAS")
* @returns {number} Number of overlapping crossed-over ("MAS") `WORD`s
*/
export const countMASword = (data: string[][], WORD_TO_FIND: string = 'MAS'): number => {
const wordLength = WORD_TO_FIND.length
const middleZeroBasedIndex = (Math.floor(wordLength / 2) + wordLength % 2) - 1
const offset = middleZeroBasedIndex
const reverseWord = WORD_TO_FIND.split('').reverse().join('')

let count = 0

for (let y = 0; y < data.length; y += 1) {
const row = data[y]

if (row === undefined) continue

for (let x = 0; x < row.length; x += 1) {
const letter = row[x]

if (letter !== WORD_TO_FIND[middleZeroBasedIndex]) continue

if (
(checkDiagonal(
{ x: x + offset, y: y - offset },
{ xDirection: -1, yDirection: 1, data },
WORD_TO_FIND
) ||
checkDiagonal(
{ x: x + offset, y: y - offset },
{ xDirection: -1, yDirection: 1, data },
reverseWord)
) &&

(checkDiagonal(
{ x: x + offset, y: y + offset },
{ xDirection: -1, yDirection: -1, data },
WORD_TO_FIND
) ||
checkDiagonal(
{ x: x + offset, y: y + offset },
{ xDirection: -1, yDirection: -1, data },
reverseWord)
)
) {
count += 1
}
}
}

return count
}
23 changes: 23 additions & 0 deletions src/2024/2024-12-04/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import path from 'path'
import { currentDirectory, readFile } from '@/utils/file.js'
import { wordCount } from './lib/wordCount.js'
import { countMASword } from './lib/xmasCount.js'

const directory = currentDirectory(import.meta.url)

const data: string[][] = readFile(path.join(directory, 'input.txt'))
.split('\n')
.map(row => row.split(''))

const quiz20241204_01 = () => {
const count = wordCount(data, 'XMAS')
console.log('"XMAS" word count:', count)
}

const quiz20241204_02 = () => {
const count = countMASword(data, 'MAS')
console.log('"MAS-only" word count:', count)
}

quiz20241204_01()
quiz20241204_02()
19 changes: 19 additions & 0 deletions src/2024/2024-12-04/sample.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { test, expect } from 'vitest'
import { wordCount } from './lib/wordCount.js'
import { countMASword } from './lib/xmasCount.js'

const data: string[][] = `ABCDEFGHIJ
XMASXMASXM
GMUMSHLGWH
MXAXAXMHRD
ASHSGJM2AX`
.split('\n')
.map(row => row.split(''))

test('Count "XMAS" words - demo', () => {
expect(wordCount(data, 'XMAS')).toBe(4)
})

test('Count "MAS-only" crossed words - demo', () => {
expect(countMASword(data, 'MAS')).toBe(1)
})
Loading