Characteristic muddling, so I sync diary (12)
length
straight
anagram hint
anagram
banner ad
giant ad
another
giant ad
button
text box
Data source
Database
Processing
Backend
Frontend
Data source
we need a big list of valid English words and phrases
also known as... a dictionary
Comprehensive, but unwieldy 🫤
kaikki.org to the rescue
raw XML dump
kaikki.org
machine-readable JSON
anagram database
Given a word as input,
I want all words that are anagrams of that word
DESIGNERS
Query
Result
DESIGNERS INGRESSED REDESIGNS
What's an anagram?
The same letters in a different order
Definition: the "anagram key" of a given word is the letters of the word sorted in alphabetical order (with spaces removed)
DESIGNERS INGRESSED REDESIGNS
DEEGINRSS
If two words have the same anagram key, they are anagrams of each other
Let's make our database a
Map(anagram key → list of words)
db = {
...,
"DEEGINRSS": [
"DESIGNERS",
"INGRESSED",
"REDESIGNS"
],
...
}
query = "DESIGNERS"
key = toAnagramKey(query)
result = db[key]
Lots of possibilities!
Maybe we don't need a database??
Could our "database" be simply a Rust HashMap inside the backend app?
JSON
Data processing pipeline - first attempt
kaikki.org
bash
jq
word
list
backend
codegen using Rust
fn generate_code(hashmap: HashMap<String, Vec<String>>) -> Scope {
let mut scope = Scope::new();
scope.import("std::collections", "HashMap");
let function = scope
.new_fn("build_map")
.allow("dead_code")
.ret("HashMap<& 'static str, Vec<& 'static str>>");
function.line("HashMap::from([");
for (k, vs) in hashmap {
let values = vs
.into_iter()
.map(|x| format!("\"{}\"", x))
.collect::<Vec<String>>()
.join(", ");
function.line(format!("(\"{}\", vec![{}])", k, values));
}
function.line("])");
scope
}
Using Rust to generate Rust
$ head src/database/data/generated.rs
use std::collections::HashMap;
#[allow(dead_code)]
fn build_map() -> HashMap<& 'static str, Vec<& 'static str>> {
HashMap::from([
("AACEEHHIMNORRTT", vec!["MORE THATCHERIAN"])
("ACCDEGIMNOPT", vec!["DECOMPACTING"])
("AACEEGHILMOPRST", vec!["ALPHAGEOMETRICS"])
("EEHMNNOT", vec!["MENTHONE"])
("DEENSUV", vec!["VENDUES"])
$ wc -l src/database/data/generated.rs
924713 src/database/data/generated.rs
$ cargo build --release
Compiling hello v0.1.0 (/Users/chris/code/dusty-study/netlify/functions/hello)
thread 'rustc' has overflowed its stack
fatal runtime error: stack overflow
error: could not compile `hello` (bin "hello")
$ head src/database/data/generated.rs
use std::collections::HashMap;
#[allow(dead_code)]
fn build_map() -> HashMap<& 'static str, Vec<& 'static str>> {
HashMap::from([
("AACEEHHIMNORRTT", vec!["MORE THATCHERIAN"]),
("ACCDEGIMNOPT", vec!["DECOMPACTING"]),
("AACEEGHILMOPRST", vec!["ALPHAGEOMETRICS"]),
("EEHMNNOT", vec!["MENTHONE"]),
("DEENSUV", vec!["VENDUES"]),
Oh there's a typo in the generated code, let's fix that...
Good news: this fixes the stack overflow
Bad news: now takes 10+ minutes (maybe forever?) to compile
JSON
Data processing pipeline - second attempt
kaikki.org
bash
jq
word
list
backend
JSON
file
inject
Compile-time injection using include_str!
use std::collections::HashMap;
static JSON: &str = include_str!("anagrams.json");
pub fn build_map() -> HashMap<& 'static str, Vec<& 'static str>> {
serde_json::from_str(JSON).unwrap()
}
$ ls -lh src/database/data/anagrams.json
-rw-r--r-- 1 chris staff 29M Jan 6 15:00 src/database/data/anagrams.json
$ ls -lh target/release/solve
-rwxr-xr-x 1 chris staff 33M Jan 6 15:02 target/release/solve
Only parsing the JSON once
Java
public class Database {
private static final Map<String, List<String>> db = loadDBFromJSON();
}
Scala
object Database:
val db: Map[String, List[String]] = loadDBFromJSON()
Rust
?????
Only parsing the JSON once
use once_cell::sync::Lazy;
static DB: Lazy<HashMap<&str, Vec<& 'static str>>> = Lazy::new(|| {
build_map()
});
JSON
Architecture - recap
kaikki.org
bash
jq
word
list
backend
JSON
file
inject
Frontend
App
Content
Scrambler
Solver
let transform = format!("rotate({} 0 0) translate(0 -75) rotate(-{} 0 0)", rotation, rotation);
rotate
translate
rotate
JSON
Deployment
kaikki.org
bash
jq
word
list
backend
JSON
file
inject
Frontend
run on laptop, commit result to git
Netlify