125 lines
3.0 KiB
TypeScript
125 lines
3.0 KiB
TypeScript
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]])
|
|
// )
|