1
0
www.mikescher.com/www/statics/aoc/2019/20_solution-2.ts
2019-12-24 13:34:32 +01:00

184 lines
4.4 KiB
TypeScript

namespace AdventOfCode2019_20_2
{
const DAY = 20;
const PROBLEM = 2;
type Point = [number, number];
export async function run()
{
let input = await AdventOfCode.getInput(DAY);
if (input == null) return;
AdventOfCode.setIntermedOutputSize("0.35vw");
let grid = input
.split(new RegExp('\r?\n'))
.filter(p => p.trim().length > 0)
.map(p => p.split('').map(q => q) );
const width = grid[0].length;
const height = grid.length;
let tunnels: {[_:string]: [Point, Point]} = {};
let tunnelsList: {[_:number]: [boolean, Point]} = {};
let entry: Point = [0, 0];
let exit: Point = [0, 0];
for (let y=1; y<height-1; y++)
for (let x=1; x<width-1; x++)
{
let v = grid[y][x];
if (isUpperChar(v))
{
let isinner = x>3 && y>3 && x<width-3 && y<height-3;
let key;
let pos: Point;
if (grid[y-1][x] === "." && isUpperChar(grid[y+1][x]))
{
key = v + grid[y+1][x];
pos = [x, y-1];
}
else if (grid[y][x+1] === "." && isUpperChar(grid[y][x-1]))
{
key = grid[y][x-1] + v;
pos = [x+1, y];
}
else if (grid[y+1][x] === "." && isUpperChar(grid[y-1][x]))
{
key = grid[y-1][x] + v;
pos = [x, y+1];
}
else if (grid[y][x-1] === "." && isUpperChar(grid[y][x+1]))
{
key = v + grid[y][x+1];
pos = [x-1, y];
}
else continue;
if (key === "AA")
{
entry = pos;
AdventOfCode.outputConsole("[AA] := " + point_to_str(pos));
}
else if (key === "ZZ")
{
exit = pos;
AdventOfCode.outputConsole("[ZZ] := " + point_to_str(pos));
}
else if (key in tunnels)
{
if (isinner) tunnels[key][0] = pos;
else tunnels[key][1] = pos;
tunnelsList[id(tunnels[key][0])] = [true, tunnels[key][1]]; // down
tunnelsList[id(tunnels[key][1])] = [false, tunnels[key][0]]; // up
AdventOfCode.outputConsole("[PORTAL] := " + point_to_str(tunnels[key][0]) + " --> " + point_to_str(tunnels[key][1]));
}
else
{
if (isinner) tunnels[key] = [pos, [-1, -1]];
else tunnels[key] = [[-1, -1], pos];
}
}
}
for (let y=0; y<height; y++)
for (let x=0; x<width; x++)
{
let v = grid[y][x];
if (isUpperChar(v)) v = " ";
grid[y][x] = v;
}
await AdventOfCode.outputIntermed(toStr(grid));
// ------------------
let distmap: {[id:number]: number} = {};
let dqueue: [number, number, Point][] = []; //<len, depth, pos>
dqueue.push([0, 0, entry]);
let last_dist = -1;
while (dqueue.length>0)
{
const [dist, depth, pt] = dqueue.shift()!;
const [ptx, pty] = pt;
let ptid2 = id2(pt, depth);
let ptid1 = id(pt);
if (ptid2 in distmap && distmap[ptid2] <= dist) continue;
if (dist !== last_dist)
{
await AdventOfCode.outputIntermed(toStr2(grid, dqueue, tunnelsList)+"\n\n" + dist);
last_dist = dist;
}
if (depth === 0 && ptx === exit[0] && pty === exit[1])
{
AdventOfCode.output(DAY, PROBLEM, dist.toString());
await AdventOfCode.outputIntermed(toStr(grid));
return;
}
distmap[ptid2] = dist;
if (grid[pty-1][ptx] === '.') dqueue.push([ dist+1, depth, [ptx, pty-1] ]);
if (grid[pty][ptx+1] === '.') dqueue.push([ dist+1, depth, [ptx+1, pty] ]);
if (grid[pty+1][ptx] === '.') dqueue.push([ dist+1, depth, [ptx, pty+1] ]);
if (grid[pty][ptx-1] === '.') dqueue.push([ dist+1, depth, [ptx-1, pty] ]);
if (ptid1 in tunnelsList)
{
const [tunnel_dir, tunnel_pos] = tunnelsList[ptid1];
if (depth ===0 && !tunnel_dir) { /* wall */ }
else dqueue.push([dist+1, depth + (tunnel_dir ? 1 : -1), tunnel_pos]);
}
}
}
function id (p: Point) { return p[1]*10000+p[0]; }
function id2(p: Point, d: number) { return p[1]*1000000+1000*p[0]+d; }
function isUpperChar(c: string): boolean
{
return c.charCodeAt(0) >= "A".charCodeAt(0) && c.charCodeAt(0) <= "Z".charCodeAt(0);
}
function toStr(grid: string[][]): string
{
return grid.map(p => p.join("") ).join("\n");
}
function toStr2(grid: string[][], highlights: [any, any, Point][], tunnels: {[_:number]: [any, Point]}): string
{
const width = grid[0].length;
const height = grid.length;
let str = "";
for (let y=0; y<height; y++)
{
for (let x=0; x<width; x++)
{
if (highlights.some( p => p[2][0] === x && p[2][1] === y )) str += "O";
else if (id([x,y]) in tunnels) str += "@";
else str += grid[y][x];
}
str += "\n";
}
return str
}
function point_to_str (p: Point) { return `[${p[0]}|${p[1]}]`; }
}