Published
Edited
Dec 13, 2021
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data = parse(input)
Insert cell
folds = getFolds(input)
Insert cell
matrix = matrixer(data)
Insert cell
folded = doFold(matrix, folds)
Insert cell
oneFoldOfData = dots(fold(matrix, folds[0]))
Insert cell
Insert cell
parse = (text) => text.split("\n").map(k => k.split(",").map(Number)).filter(x => typeof x[1] === "number")
Insert cell
// takes a matrix
// returns count of "#" in matrix
dots = (paper) => paper.flat().filter((x) => x === "#").length
Insert cell
// takes text input
// returns object list of folding instructions
getFolds = (input) =>
input
.split("\n")
.filter(k => k.startsWith("fold along"))
.map(
k => (
([along, crease]) => ({along, crease: +crease})
)
(
k
.split(" ")[2] // only pick last entry
.split("=")
)
)
Insert cell
// takes list of plain data of [x, y] positions
// returns a two-dimensional matrix with "#" in the proper cells
matrixer = (data) => {
const max = (data, i) => d3.max(data, x => x[i])
const matrix = Array.from({length: max(data, 1) + 1})
.map(() => new Array(max(data, 0) + 1).fill(" "));
data.forEach(d => matrix[d[1]][d[0]] = "#");
return matrix;
}
Insert cell
// folding UP and LEFT are similar; LEFT only needs a double transpose
fold = (paper, {along, crease}) => {
const identity = (x) => x;
const transpose = ({"y": identity, "x": d3.transpose})[along];
return transpose(folder(transpose(paper), crease));
}
Insert cell
// takes a matrix and list of folds
// returns the resulting matrix with all folds applied
doFold = (matrix, folds) => {
folds.forEach(f => matrix = fold(matrix, f));
return matrix;
}
Insert cell
// takes the source matrix and crease position
// returns the lower part of the matrix merged with the upper part
folder = (matrix, crease) => matrix
.reverse()
.slice(crease + 1, matrix.length)
.reverse()
.map((row, r) => merge(row, matrix[r]))
Insert cell
// takes two rows
// returns the merger of the two rows with "#" when either has a "#"
merge = (l1, l2) => l1.map((e, i) => e === "#" || l2[i] === "#" ? "#" : ".")
Insert cell
// takes a list of plain data (numbers)
// returns the data as a list of objects
objectify = (data) => data.map((y, r) => y.map((x, c) => ({r, c, x}))).flat()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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