1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#![forbid(unsafe_code)]
#![deny(missing_docs)]
#![deny(unused_must_use)]
#![deny(unused_mut)]
use anyhow::{bail, Error, Result};
pub const DICTIONARY_UNIQUE_PREFIX: usize = 3;
pub const DICTIONARY: [&str; 1024] = [
"abbey", "able", "abort", "absorb", "abyss", "ace", "ache", "acid", "across", "acumen",
"adapt", "adept", "adjust", "adopt", "adult", "aerial", "afar", "affair", "afield", "afloat",
"afoot", "afraid", "after", "age", "agile", "aglow", "agony", "agree", "ahead", "aid", "aisle",
"ajar", "akin", "alarm", "album", "alert", "alley", "almost", "aloof", "alps", "also",
"alumni", "always", "amaze", "ambush", "amidst", "ammo", "among", "ample", "amuse", "anchor",
"angle", "ankle", "antic", "anvil", "apart", "apex", "aphid", "aplomb", "apply", "arch",
"ardent", "arena", "argue", "arise", "arm", "around", "arrow", "ascend", "aside", "ask",
"asleep", "aspire", "asylum", "atlas", "atom", "atrium", "attire", "auburn", "audio", "august",
"aunt", "auto", "avatar", "avid", "avoid", "awful", "awning", "awoken", "axe", "axis", "axle",
"aztec", "azure", "baby", "bacon", "bad", "bail", "bakery", "bamboo", "banjo", "basin",
"batch", "bawl", "bay", "beer", "befit", "begun", "behind", "being", "below", "best", "bevel",
"beware", "beyond", "bias", "bid", "bike", "bird", "bite", "blip", "boat", "body", "bogey",
"boil", "bold", "bomb", "border", "boss", "both", "bovine", "box", "broken", "brunt", "bubble",
"budget", "buffet", "bug", "bulb", "bum", "bun", "but", "buy", "buzz", "byline", "bypass",
"cabin", "cactus", "cadet", "cafe", "cage", "cajun", "cake", "camp", "candy", "case", "cat",
"cause", "cease", "cedar", "cell", "cement", "cent", "chrome", "cider", "cigar", "cinema",
"circle", "claw", "click", "clue", "coal", "cobra", "cocoa", "code", "coffee", "cog", "coil",
"cold", "comb", "cool", "copy", "cousin", "cowl", "cube", "cuff", "custom", "dad", "daft",
"dagger", "daily", "dam", "dapper", "dart", "dash", "date", "dawn", "daze", "debt", "decay",
"deft", "deity", "den", "depth", "desk", "devoid", "dice", "diet", "dig", "dilute", "dim",
"dine", "diode", "ditch", "dive", "dizzy", "doctor", "dodge", "doe", "dog", "doing", "donut",
"dose", "dot", "double", "dove", "down", "doze", "dream", "drink", "drunk", "dry", "dual",
"dubbed", "dud", "duet", "duke", "dumb", "dune", "duplex", "dust", "duty", "dwarf", "dwelt",
"dying", "each", "eagle", "earth", "easy", "eat", "echo", "eden", "edgy", "edit", "eel", "egg",
"eight", "either", "eject", "elapse", "elbow", "eldest", "eleven", "elite", "elope", "else",
"elude", "email", "ember", "emerge", "emit", "empty", "energy", "enigma", "enjoy", "enlist",
"enmity", "enough", "ensign", "envy", "epoxy", "equip", "erase", "error", "estate", "etch",
"ethics", "excess", "exhale", "exit", "exotic", "extra", "exult", "fade", "fake", "fall",
"family", "fancy", "fatal", "fault", "fawn", "fax", "faze", "feast", "fee", "felt", "fence",
"ferry", "fever", "few", "fiat", "fibula", "fidget", "fierce", "fight", "film", "fir", "five",
"fix", "fizz", "fleet", "fly", "foam", "focus", "foe", "fog", "foil", "font", "fossil", "fowl",
"fox", "foyer", "frame", "frown", "fruit", "fry", "fudge", "fuel", "full", "fume", "fun",
"future", "fuzz", "gables", "gadget", "gag", "gain", "galaxy", "game", "gang", "gasp",
"gather", "gauze", "gave", "gawk", "gaze", "gecko", "geek", "gel", "germ", "geyser", "ghetto",
"ghost", "giant", "giddy", "gift", "gill", "ginger", "girth", "give", "glass", "glide", "gnaw",
"gnome", "goat", "goblet", "goes", "going", "gone", "gopher", "gossip", "got", "gown", "grunt",
"guest", "guide", "gulp", "guru", "gust", "gutter", "guy", "gypsy", "gyrate", "hair", "having",
"hawk", "haze", "heel", "heft", "height", "hence", "hero", "hide", "hijack", "hike", "hill",
"hinder", "hip", "hire", "hive", "hoax", "hobby", "hockey", "hold", "honk", "hook", "hop",
"horn", "hot", "hover", "howl", "huddle", "hug", "hull", "hum", "hunt", "hut", "hybrid",
"hyper", "icing", "icon", "idiom", "idle", "idol", "igloo", "ignore", "iguana", "impel",
"incur", "injury", "inline", "inmate", "input", "insult", "invoke", "ion", "irate", "iris",
"iron", "island", "issue", "itch", "item", "itself", "ivory", "jab", "jade", "jagged", "jail",
"jargon", "jaunt", "jaw", "jazz", "jeans", "jeer", "jest", "jewel", "jigsaw", "jingle", "jive",
"job", "jock", "jog", "joke", "jolt", "jostle", "joy", "judge", "juicy", "july", "jump",
"junk", "jury", "karate", "keep", "kennel", "kept", "kettle", "king", "kiosk", "kiss", "kiwi",
"knee", "knife", "koala", "lad", "lag", "lair", "lake", "lamb", "lap", "large", "last",
"late", "lava", "lay", "lazy", "ledge", "leech", "left", "legion", "lemon", "lesson", "liar",
"lick", "lid", "lie", "light", "lilac", "lime", "line", "lion", "liquid", "list", "live",
"load", "lock", "lodge", "loft", "logic", "long", "lopped", "lost", "loud", "love", "low",
"loyal", "lucky", "lump", "lung", "lurk", "lush", "luxury", "lymph", "lynx", "lyrics", "macro",
"mail", "major", "make", "male", "mammal", "map", "mate", "maul", "mayor", "maze", "mean",
"memoir", "men", "merge", "mesh", "met", "mew", "mice", "midst", "mighty", "mime", "mirror",
"misery", "moat", "mob", "mock", "mohawk", "molten", "moment", "money", "moon", "mop",
"morsel", "most", "mouth", "mow", "much", "mud", "muffin", "mug", "mullet", "mumble", "muppet",
"mural", "muzzle", "myriad", "myth", "nag", "nail", "name", "nanny", "nap", "nasty", "navy",
"near", "need", "neon", "nephew", "nerve", "nest", "never", "newt", "nexus", "nibs", "niche",
"niece", "nifty", "nimbly", "nobody", "nod", "noise", "nomad", "note", "noun", "nozzle",
"nuance", "nudged", "nugget", "null", "numb", "nun", "nurse", "nylon", "oak", "oar", "oasis",
"object", "occur", "ocean", "odd", "off", "often", "okay", "older", "olive", "omega", "onion",
"online", "onto", "onward", "ooze", "open", "opus", "orange", "orb", "orchid", "order",
"organ", "origin", "oscar", "otter", "ouch", "ought", "ounce", "oust", "oval", "oven", "owe",
"owl", "own", "oxygen", "oyster", "ozone", "pact", "page", "palace", "paper", "past", "pat",
"pause", "peel", "peg", "pen", "people", "pepper", "pest", "petal", "phase", "phone", "piano",
"pick", "pierce", "pimple", "pirate", "pivot", "pixel", "pizza", "plead", "pliers", "plus",
"poetry", "point", "poke", "pole", "pony", "pool", "pot", "pouch", "powder", "pray", "pride",
"prune", "pry", "public", "puck", "puddle", "puff", "pulp", "punch", "puppy", "purge", "push",
"putty", "pylon", "python", "queen", "quick", "quote", "radar", "raft", "rage", "rake",
"rally", "ram", "rapid", "rare", "rash", "rat", "rave", "ray", "razor", "react", "rebel",
"recipe", "reduce", "reef", "refer", "reheat", "relic", "remedy", "repent", "rerun", "rest",
"return", "revamp", "rewind", "rhino", "rhyme", "rib", "rich", "ride", "rift", "rigid", "rim",
"riot", "rip", "rise", "ritual", "river", "roar", "robot", "rodent", "rogue", "role", "room",
"rope", "roster", "rotate", "rover", "royal", "ruby", "rude", "rug", "ruin", "rule", "rumble",
"run", "rural", "sack", "safe", "saga", "sail", "sake", "salad", "sample", "sand", "sash",
"satin", "save", "scenic", "school", "scoop", "scrub", "scuba", "second", "sedan", "seed",
"setup", "sew", "sieve", "silk", "sip", "siren", "size", "skate", "skew", "skull", "slid",
"slow", "slug", "smash", "smog", "snake", "sneeze", "sniff", "snout", "snug", "soap", "sob",
"soccer", "soda", "soggy", "soil", "solve", "sonar", "soot", "sort", "sow", "soy", "space",
"speed", "sphere", "spout", "sprig", "spud", "spy", "square", "stick", "subtly", "suede",
"sugar", "sum", "sun", "surf", "sushi", "suture", "swept", "sword", "swung", "system", "tab",
"tacit", "tag", "taint", "take", "talent", "tamper", "tan", "task", "tattoo", "taunt",
"tavern", "tawny", "taxi", "tell", "tender", "tepid", "tether", "thaw", "thorn", "thumb",
"thwart", "ticket", "tidy", "tier", "tiger", "tilt", "timber", "tint", "tip", "tire", "tissue",
"titan", "today", "toffee", "toilet", "token", "tone", "top", "torn", "toss", "total", "touch",
"tow", "toxic", "toy", "trash", "trend", "tribal", "truth", "try", "tube", "tuck", "tudor",
"tuft", "tug", "tulip", "tune", "turn", "tusk", "tutor", "tuxedo", "twang", "twice", "tycoon",
"type", "tyrant", "ugly", "ulcer", "umpire", "uncle", "under", "uneven", "unfit", "union",
"unmask", "unrest", "unsafe", "until", "unveil", "unwind", "unzip", "upbeat", "update",
"uphill", "upkeep", "upload", "upon", "upper", "urban", "urge", "usage", "use", "usher",
"using", "usual", "utmost", "utopia", "vague", "vain", "value", "vane", "vary", "vat", "vault",
"vector", "veer", "vegan", "vein", "velvet", "vest", "vexed", "vial", "vice", "video",
"viking", "violin", "viper", "vital", "vivid", "vixen", "vocal", "vogue", "voice", "vortex",
"vote", "vowel", "voyage", "wade", "waffle", "waist", "wake", "want", "warp", "water", "wax",
"wedge", "weird", "went", "wept", "were", "whale", "when", "whole", "wide", "wield", "wife",
"wiggle", "wild", "winter", "wire", "wise", "wives", "wizard", "wobbly", "woes", "woke",
"wolf", "woozy", "worry", "woven", "wrap", "wrist", "wrong", "yacht", "yahoo", "yank",
];
pub fn word_at_index(i: usize) -> String {
if i > 1023 {
panic!("attempt to access index {} but dictionary-1024 only has 1024 elements", i);
}
DICTIONARY[i].to_string()
}
pub fn index_of_word(word: &str) -> Result<usize, Error> {
if word.len() < 3 {
bail!("each word must have at least three characters");
}
let word = &word[..3];
for i in 0..1024 {
if &DICTIONARY[i][..3] == word {
return Ok(i);
}
}
bail!("word prefix '{}' was not found in dictionary", word);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic_tests() {
for i in 0..1024 {
let word = word_at_index(i);
let index = index_of_word(&word).unwrap();
if index != i {
panic!("mismatch");
}
}
for i in 0..1024 {
let mut word = word_at_index(i);
word += "b";
let index = index_of_word(&word).unwrap();
if index != i {
panic!("mismatch");
}
}
for i in 0..1024 {
let mut word = word_at_index(i);
word.truncate(3);
word += "a";
let index = index_of_word(&word).unwrap();
if index != i {
panic!("mismatch");
}
}
for i in 0..1024 {
let mut word = word_at_index(i);
word.truncate(3);
let index = index_of_word(&word).unwrap();
if index != i {
panic!("mismatch");
}
}
index_of_word("aaron").unwrap_err();
index_of_word("ab").unwrap_err();
}
}