Public
Edited
Oct 28, 2022
2 forks
Importers
12 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
eliminationScore = (word) => {
const exclude = new Set(gray);
// per possible remaining answer
return (
d3.sum(
answers.map((answer) => {
// if it's the answer, it'll eliminate all but itself
if (word === answer) return answers.length - 1;

// see how green, yellow, and gray change
const next = {
exclude: new Set(exclude),
green: green.slice(),
yellow: yellow.slice()
};
for (const l of word) if (!answer.includes(l)) next.exclude.add(l);
for (const [i, [l, a]] of d3.zip(word, answer).entries()) {
if (l === a) next.green[i] = l;
else if (!next.exclude.has(l)) next.yellow[i] += l;
}

// check if the cache already has this configuration
if (cache.has(next)) return cache.get(next);

// count how many answers would be eliminated
const include = new Set(
next.yellow.concat(next.green).flatMap((l) => Array.from(l))
);
const match = new RegExp(
d3
.zip(next.green, next.yellow)
.map(([g, y]) => (g ? g[0] : y ? `[^${y}]` : "."))
.join("")
);
const delta =
answers.length -
d3.count(
answers,
(w) =>
w.match(match) &&
d3.every(include, (l) => w.includes(l)) &&
d3.every(w, (l) => !exclude.has(l))
);

// update cache
cache.set(next, delta);
return delta;
})
) /
answers.length /
answers.length
);
}
Insert cell
cache = answers, new d3.InternMap([], JSON.stringify)
Insert cell
Insert cell
frequencyScore = (word) =>
Array.from(new Set(word))
.map((l) => (include.has(l) ? 0 : frequencies.get(l)) || 0)
.reduce((sum, s) => sum + s)
Insert cell
frequencies = d3.rollup(
answers.flatMap((w) => Array.from(w)),
(r) => r.length,
(d) => d
)
Insert cell
Insert cell
answers = {
const exclude = new Set(gray);
return words.answers.filter(
(w) =>
w.match(match) &&
d3.every(include, (l) => w.includes(l)) &&
d3.every(w, (l) => !exclude.has(l))
);
}
Insert cell
include = new Set(yellow.concat(green).flatMap(l => Array.from(l)))
Insert cell
gray = grayInput.toUpperCase()
Insert cell
Insert cell
words = {
const text = await FileAttachment("words@2.csv").text();
const [answers, allowed] = text
.trim()
.toUpperCase()
.split("\n")
.map((line) => line.split(","));
return { answers, allowed: allowed.concat(answers) };
}
Insert cell
Insert cell
wordsOld = {
const text = await FileAttachment("words.csv").text();
const [answers, allowed] = text
.trim()
.toUpperCase()
.split("\n")
.map((line) => line.split(","));
return { answers, allowed: allowed.concat(answers) };
}
Insert cell
difference = {
const answers = new Set(words.answers);
const allowed = new Set(words.allowed);
return {
answers: wordsOld.answers.filter((w) => !answers.has(w)),
allowed: wordsOld.allowed.filter((w) => !allowed.has(w))
};
}
Insert cell
function input(label) {
const form = htl.html`
<form style=${{
font: "13px/1.2 var(--sans-serif)",
display: "flex",
flexDirection: mobile ? "column" : "row",
alignItems: "baseline"
}}>
<label style="width: 127px">${label}</label>
<div>
${[0, 1, 2, 3, 4].map(
(i) => htl.html`
<input type="text" spellcheck="false" autocomplete="off" style="width: 2em; font: inherit;" onkeyup=${(
e
) => {
form.value[i] = e.target.value.toUpperCase();
e.target.dispatchEvent(new CustomEvent("input", { bubbles: true }));
}} />
`
)}
</div>
</form>
`;
form.value = new Array(5).fill("");

return form;
}
Insert cell
mobile = matchMedia("(max-width: 640px)")
Insert cell
Insert cell
import {matchMedia} from "@mootari/match-media"
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