1pub const WORDS: [&str; 256] = [
12 "acorn", "amber", "anchor", "apple", "apron", "javelin", "attic", "autumn", "badge", "bagel",
13 "bamboo", "banjo", "barrel", "basket", "beacon", "beetle", "bison", "blanket", "blossom",
14 "bottle", "bridge", "broom", "bubble", "bucket", "biscuit", "button", "cabin", "cactus",
15 "camel", "candle", "canoe", "canyon", "carpet", "carrot", "castle", "cedar", "cello", "cherry",
16 "chimney", "custard", "circus", "clover", "cobalt", "coconut", "coffee", "comet", "compass",
17 "copper", "coral", "denim", "cradle", "peacock", "cricket", "crystal", "cupcake", "curtain",
18 "daisy", "dolphin", "domino", "donkey", "dragon", "drum", "eagle", "echo", "elbow", "flamingo",
19 "engine", "falcon", "feather", "fiddle", "finch", "fossil", "fountain", "garden", "garlic",
20 "gecko", "ginger", "glacier", "goblet", "goose", "granite", "guitar", "hammer", "hammock",
21 "sailor", "harvest", "hazel", "helmet", "heron", "beaver", "honey", "iceberg", "igloo",
22 "island", "ivory", "jacket", "jaguar", "jasmine", "jelly", "jigsaw", "jungle", "kayak",
23 "kettle", "kitten", "koala", "ladder", "lantern", "lemon", "leopard", "lettuce", "lizard",
24 "llama", "lobster", "kangaroo", "lotus", "magnet", "mango", "marble", "prairie", "parsnip",
25 "glove", "gorilla", "mosaic", "muffin", "mushroom", "napkin", "nectar", "needle", "paprika",
26 "nutmeg", "oasis", "octopus", "olive", "onion", "orbit", "orchid", "ostrich", "otter",
27 "oyster", "oatmeal", "pyramid", "porridge", "panda", "toucan", "pasta", "peanut", "pebble",
28 "pelican", "pencil", "penguin", "saffron", "piano", "pickle", "pigeon", "pillow", "pirate",
29 "nebula", "magpie", "poodle", "poppy", "potato", "pretzel", "pumpkin", "puppet", "puzzle",
30 "quilt", "rabbit", "raccoon", "radish", "rainbow", "raisin", "raven", "ribbon", "river",
31 "spinach", "rocket", "rooster", "rubber", "saddle", "salmon", "tortoise", "satchel", "scarf",
32 "scooter", "shadow", "sheep", "shovel", "silver", "sketch", "loafer", "snail", "soccer",
33 "sofa", "sparrow", "spider", "sponge", "spoon", "squirrel", "stable", "stapler", "sticker",
34 "stork", "summer", "sunset", "sweater", "tablet", "clarinet", "teapot", "temple", "tennis",
35 "thimble", "thunder", "wombat", "tiger", "toaster", "turnip", "tractor", "trumpet", "tulip",
36 "tunnel", "vulture", "turtle", "umbrella", "unicorn", "velvet", "violet", "trombone",
37 "volcano", "waffle", "wagon", "walnut", "walrus", "goblin", "wasabi", "harp", "window",
38 "snowman", "sapphire", "pudding", "zebra", "zipper", "zucchini", "bronze", "cobweb", "dinghy",
39 "flannel", "gravel", "hedgehog", "kiwi", "lagoon", "mammoth", "platypus", "pistol", "quartz",
40 "sardine", "lentil",
41];
42
43#[must_use]
46pub fn code_from(bytes: [u8; 4]) -> String {
47 bytes
48 .iter()
49 .map(|byte| WORDS[usize::from(*byte)])
50 .collect::<Vec<_>>()
51 .join(" ")
52}
53
54#[cfg(test)]
55mod tests {
56 use super::{WORDS, code_from};
57
58 #[test]
59 fn pairing_words_are_distinct_lowercase_short_and_two_hundred_and_fifty_six() {
60 let mut seen = std::collections::BTreeSet::new();
61 for word in WORDS {
62 assert!(
63 word.len() >= 3 && word.len() <= 8,
64 "{word} is not short enough to say"
65 );
66 assert!(
67 word.bytes().all(|byte| byte.is_ascii_lowercase()),
68 "{word} is not lowercase ascii"
69 );
70 assert!(seen.insert(word), "{word} is listed twice");
71 }
72 assert_eq!(seen.len(), 256);
73 }
74
75 #[test]
76 fn pairing_code_takes_one_word_per_byte() {
77 assert_eq!(code_from([0, 1, 2, 255]), "acorn amber anchor lentil");
78 let code = code_from([7, 7, 7, 7]);
79 let words: Vec<&str> = code.split(' ').collect();
80 assert_eq!(words, ["autumn"; 4]);
81 }
82}