import * as std from 'std'; var data = std.loadFile("17.test"); data = data.trim().split('\n'); data = data.map(d => d.split('')); var gheight = data.length; var gwidth = data[0].length; console.log(`${gwidth}x${gheight} graph; ${gheight*gwidth} nodes to search`); var start = [0,0]; var end = [gwidth-1,gheight-1]; var gdist = {}; var gprev; function vec_same(a,b) { return a[0] === b[0] && a[1] === b[1]; } function in_graph(c) { if (c[0] < 0 || c[0] >= gwidth || c[1] < 0 || c[1] >= gheight) return false; return true; } var graph = {}; function left(c) { return [c[1], -c[0]]; } function right(c) { return [-c[1], c[0]]; } function node_dir(c, dir) { c = c.slice(); c[0] += dir[0]; c[1] += dir[1]; return { c: c, dir: dir.slice() }; } function dijkstra(source) { function get_node(n) { var nn = JSON.stringify(n); if (!graph[nn]) graph[nn] = { dist: 100000000, considered: false, previous: undefined, streak: 0, c: n.c, dir: n.dir, value: Number(data[n.c[1]][n.c[0]]), }; return graph[nn]; } graph = {}; var first = { c: [0,0], dir: [1,0] }; get_node(first).dist = 0; var leafs = []; leafs.push(get_node(first)); var endnode = undefined; while (leafs.length) { var u = undefined; if (leafs.length > 1) { var i = 0; i = leafs.reduce((low_idx,b,i,arr) => arr[low_idx].dist < b.dist ? low_idx : i, 0); u = leafs[i]; leafs.splice(i,1); } else u = leafs.pop(); if (vec_same(u.c, end)) { endnode = u; break; } u.considered = true; var adj = []; if (u.streak < 3) adj.push(node_dir(u.c, u.dir)); adj.push(node_dir(u.c, left(u.dir))); adj.push(node_dir(u.c, right(u.dir))); adj = adj.filter(n=>in_graph(n.c)); adj.forEach(function(x) { var n = get_node(x); var alt = u.dist + n.value; if (alt < n.dist) { n.dist = alt; n.previous = u; if (vec_same(u.dir, n.dir)) n.streak = u.streak + 1; else n.streak = 1; } if (!n.added) { leafs.push(n); n.added = true; } }); } var p = endnode; var path = []; while (p) { path.push(p); p = p.previous; } return path.reverse(); } var path = dijkstra(start); console.log(`Least heat is ${path[path.length-1].dist}`); //var d = path.reduce((a,v) => a += v.value,0); //console.log(d); if (data.length < 100) { console.log(`heat path is ${JSON.stringify(path.map(p=>p.value))}`); path.forEach(p=>data[p.c[1]][p.c[0]] = '@'); data.forEach(d=>console.log(d)); }