much cleaner way to look for shapes in grids

This commit is contained in:
Joshua Seigler 2024-12-04 23:05:28 -05:00
parent 54dc419f8a
commit 5764869e99
2 changed files with 28 additions and 104 deletions

View file

@ -48,17 +48,17 @@
{ {
"part1": { "part1": {
"solved": true, "solved": true,
"result": "2358", "result": "2143",
"attempts": [ "attempts": [
"0" "0"
], ],
"time": 327.70272 "time": 67.709144
}, },
"part2": { "part2": {
"solved": true, "solved": true,
"result": "1737", "result": "1737",
"attempts": [], "attempts": [],
"time": 201.22507 "time": 182.986319
} }
}, },
{ {

View file

@ -4,118 +4,42 @@ const parseInput = (rawInput: string) => {
return rawInput.split('\n').map(line => line.split('')) return rawInput.split('\n').map(line => line.split(''))
} }
const directions = ["down","right","dl","dr"] as const
type Direction = typeof directions[number]
type Prospect1 = {
letters: string
direction: Direction
next: [number, number]
}
type Coord = Prospect1['next']
const getNext = (dir: Direction, [row, col]: Coord): Coord => {
switch(dir) {
case "down": {return [row+1, col]}
case "right": {return [row, col+1]}
case "dl": {return [row+1, col-1]}
case "dr": {return [row+1, col+1]}
}
}
const part1 = (rawInput: string) => { const part1 = (rawInput: string) => {
const input = parseInput(rawInput) const input = parseInput(rawInput)
let total = 0 let total = 0
let prospects: Prospect1[] = [] input.forEach((line,r) => {
input.forEach((line, row) => { line.forEach((cell, c) => {
line.forEach((letter, col) => { total += [
prospects = prospects.map((prospect) => { [[r,c],[r,c+1],[r,c+2],[r,c+3]], // right
const { [[r,c],[r+1,c+1],[r+2,c+2],[r+3,c+3]], // downright
direction, [[r,c],[r+1,c],[r+2,c],[r+3,c]], // down
letters, [[r,c],[r+1,c-1],[r+2,c-2],[r+3,c-3]], // downleft
next ].reduce((acc,cur) => /XMAS|SAMX/.test(cur.map(([r,c]) => {
} = prospect return (input[r] ?? [])[c] ?? "."
if (next[0] < row) return null }).join('')) ? acc+1:acc, 0)
if (next[0] === row && next[1] === col) {
const nextLetters = letters + letter
if (["XMAS","SAMX"].includes(nextLetters)) {
total += 1
return null
}
if (["XMA","SAM","XM","SA"].includes(nextLetters)) {
return {
letters: nextLetters,
direction: direction,
next: getNext(direction, next)
}
}
}
return prospect
}).filter(prospect => prospect != null)
if ("XMAS".includes(letter)) {
directions.forEach(direction => {
prospects.push({
letters: letter,
direction,
next: getNext(direction, [row, col])
})
})
}
}) })
}) })
return total return total
} }
type Prospect2 = {
letters: string
direction: Direction
next: [number, number]
center: [number, number]
}
const part2 = (rawInput: string) => { const part2 = (rawInput: string) => {
const input = parseInput(rawInput) const input = parseInput(rawInput)
let centers = new Map<string, number>()
let prospects: Prospect2[] = []
let total = 0 let total = 0
input.forEach((line, row) => { for (let r = 0; r < input.length -2; r++) {
line.forEach((letter, col) => { for (let c = 0; c < input[0].length -2; c++) {
prospects = prospects.map((prospect) => { if(/MMASS|SSAMM|MSAMS|SMASM/.test(
const { [
direction, [r,c],
letters, [r,c+2],
next [r+1,c+1],
} = prospect [r+2,c],
if (next[0] < row) return null [r+2,c+2]
if (next[0] === row && next[1] === col) { ].map(([r,c]) => input[r][c]).join('')
const nextLetters = letters + letter )) {
if (["MAS","SAM"].includes(nextLetters)) { total++
const key = prospect.center.join(",")
if (centers.has(key)) { total++ }
centers.set(key, 1)
return null
}
if (["MA","SA"].includes(nextLetters)) {
return {
...prospect,
letters: nextLetters,
next: getNext(direction, next),
} }
} }
} }
return prospect
}).filter(prospect => prospect != null)
if ("XMAS".includes(letter)) {
["dl" as const, "dr" as const].forEach(direction => {
const center = getNext(direction, [row, col])
prospects.push({
letters: letter,
direction,
next: center,
center,
})
})
}
})
})
return total return total
} }
@ -165,5 +89,5 @@ MXMXAXMASX`,
solution: part2, solution: part2,
}, },
trimTestInputs: true, trimTestInputs: true,
onlyTests: false, onlyTests: true,
}) })