Public
Edited
Dec 9, 2022
1 fork
2 stars
Insert cell
Insert cell
test = `R 4
U 4
L 3
D 1
R 4
D 1
L 5
R 2
`
Insert cell
testMotions = parseMotions(test)
Insert cell
testInitialState = `......
......
......
......
H.....`
Insert cell
function parseMotions(input) {
return input.trim().split("\n").map(parseMotion);
}
Insert cell
function parseMotion(input) {
let [direction, length] = input.split(/\s+/);
if (!/^[RULD]$/.test(direction)) throw new Error(`invalid direction: ${input}`);
if (!Number.isInteger(length = +length)) throw new Error(`invalid length: ${input}`);
return {direction, length};
}
Insert cell
[...processMotions(testMotions)]
Insert cell
function* processMotions(motions) {
let x = 0;
let y = 0;
yield [x, y];
for (const {direction, length} of motions) {
switch (direction) {
case "L": for (let i = 0; i < length; ++i) yield [--x, y]; break;
case "R": for (let i = 0; i < length; ++i) yield [++x, y]; break;
case "U": for (let i = 0; i < length; ++i) yield [x, ++y]; break;
case "D": for (let i = 0; i < length; ++i) yield [x, --y]; break;
}
}
}
Insert cell
visualizeMotion(testMotions)
Insert cell
function* processTailMotions(motions) {
let tx = 0;
let ty = 0;
yield [tx, ty];
for (const [hx, hy] of processMotions(motions)) {
[tx, ty] = moveTail(tx, ty, hx, hy);
yield [tx, ty];
}
}
Insert cell
function moveTail(tx, ty, hx, hy) {
if (tx < hx - 2 || tx > hx + 2 || ty < hy - 2 || ty > hy + 2) throw new Error(`head is too far away`);
if (!(hx - 1 <= tx && tx <= hx + 1 && hy - 1 <= ty && ty <= hy + 1)) {
tx += hx > tx ? 1 : hx < tx ? -1 : 0;
ty += hy > ty ? 1 : hy < ty ? -1 : 0;
}
return [tx, ty];
}
Insert cell
function countDistinctPositions(positions) {
return d3.union(Array.from(positions, (motion) => motion.join())).size;
}
Insert cell
countDistinctPositions(processTailMotions(testMotions))
Insert cell
countDistinctPositions(processTailMotions(motions))
Insert cell
function* visualizeMotion(motions) {
const positions = Array.from(processMotions(motions));
const tailPositions = Array.from(processTailMotions(motions));
for (let i = 0; i < tailPositions.length; ++i) {
yield Plot.plot({
grid: true,
height: 640,
x: {domain: d3.extent(positions, ([x]) => x)},
y: {domain: d3.extent(positions, ([, y]) => y)},
marks: [
Plot.line(tailPositions.slice(0, i + 1), {}),
Plot.line([tailPositions[i], positions[i]], {stroke: "red"})
]
});
}
}
Insert cell
input = FileAttachment("input.txt").text()
Insert cell
motions = parseMotions(input)
Insert cell
visualizeMotion(motions)
Insert cell
k = 10
Insert cell
function* processRopeMotions(motions) {
const RX = new Float64Array(k);
const RY = new Float64Array(k);
yield Array.from({length: k}, (_, i) => [RX[i], RY[i]]);
for ([RX[0], RY[0]] of processMotions(motions)) {
for (let i = 1; i < k; ++i) {
[RX[i], RY[i]] = moveTail(RX[i], RY[i], RX[i - 1], RY[i - 1]);
}
yield Array.from({length: k}, (_, i) => [RX[i], RY[i]]);
}
}
Insert cell
visualizeRopeMotion(motions)
Insert cell
{
const set = new Set();
for (const ropePosition of processRopeMotions(motions)) {
set.add(ropePosition[k - 1].join());
}
return set;
}
Insert cell
function* visualizeRopeMotion(motions) {
const positions = Array.from(processMotions(motions));
const ropePositions = Array.from(processRopeMotions(motions));
const tailPositions = ropePositions.map((rope) => rope[k - 1]);
for (let i = 0; i < positions.length; ++i) {
yield Plot.plot({
grid: true,
height: 640,
x: {domain: d3.extent(positions, ([x]) => x)},
y: {domain: d3.extent(positions, ([, y]) => y)},
marks: [
Plot.line(tailPositions.slice(0, i)),
Plot.line(ropePositions[i], {stroke: "red"})
]
});
}
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more