aoc-2023/day_3/solve.ts

125 lines
3.0 KiB
TypeScript
Raw Permalink Normal View History

2024-12-09 22:41:02 +09:00
type PartInfo = {
partNumber: number;
begin: number;
end: number;
}
function nextPartNumber(line: string, pos: number): PartInfo | null {
const numbers: string[] = [];
// eat characters until a number is found
while (pos < line.length) {
const ch = line[pos];
if (/\d/.test(ch)) {
break;
}
pos++;
}
// collect numbers
while (pos < line.length) {
const ch = line[pos];
if (!/\d/.test(ch)) {
break;
}
numbers.push(ch);
pos++;
}
if (numbers.length === 0) {
return null;
}
const partNumber = parseInt(numbers.join(""))
return {
partNumber,
begin: pos - numbers.length,
end: pos - 1 // inclusive
}
}
function* queryNeighbors(x: number, y: number, boxWidth: number, width: number, height: number) {
boxWidth = Math.min(boxWidth, width - x);
if (x > 0) {
if (y > 0) {
yield [x - 1, y - 1];
}
yield [x - 1, y];
if (y < height - 1) {
yield [x - 1, y + 1];
}
}
if (x + boxWidth < width) {
if (y > 0) {
yield [x + boxWidth, y - 1];
}
yield [x + boxWidth, y];
if (y < height - 1) {
yield [x + boxWidth, y + 1];
}
}
if (y > 0) {
for (let i = x; i < x + boxWidth; i++) {
yield [i, y - 1];
}
}
if (y < height - 1) {
for (let i = x; i < x + boxWidth; i++) {
yield [i, y + 1];
}
}
}
function checkValidPartNumber(lines: string[], info: PartInfo, y: number) {
const neighbors = queryNeighbors(info.begin, y, info.end - info.begin + 1, lines[0].length, lines.length);
for (const [x, y] of neighbors) {
const line = lines[y];
const ch = line[x];
if ((!/\d/.test(ch)) && ch !== ".") {
return true;
}
}
return false;
}
function* iterPartNumbers(lines: string[]) {
let pos = 0;
let y = 0;
while (y < lines.length) {
const line = lines[y];
while (pos < line.length) {
const part = nextPartNumber(line, pos);
if (!part) {
break;
}
pos = part.end + 1;
// check valid part number
if (!checkValidPartNumber(lines, part, y)) {
continue;
}
yield part;
}
pos = 0;
y++;
}
}
// const example = `467..114..
// ...*......
// ..35..633.
// ......#...
// 617*......
// .....+.58.
// ..592.....
// ......755.
// ...$.*....
// .664.598..`;
const example = await Deno.readTextFile("input.txt");
const lines = example.split("\n").map(x => x.trim()).filter(x => x.length > 0);
const width = lines[0].length;
const height = lines.length;
console.log(width, height);
console.log([...iterPartNumbers(lines)])
console.log([...iterPartNumbers(lines)].reduce((a, b) => a + b.partNumber, 0))
// console.log([...queryNeighbors(7, 1, 3, width, height)]
// .map(n => lines[n[1]][n[0]])
// )