#define CLI 1
#ifdef CLI
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#define IN_ROM 
#else
#include <vectrex.h>
#include <assert.h>			
#define IN_ROM __attribute__ ((section(".text")))
#define NULL 0
#define EOF (-1)
#endif

#define uint16_t unsigned long
#define WORDS 2547
// The word list has been sorted (roughly) by frequency of the words
// in common use.  (The sort program is in ~/src/IPA/spell/sort-by-freq.c)

// This way, the game can make sure that the words it suggests are
// not too obscure.
#define SIMPLE_WORDS 1000

// This array is a bit vector in which we mark whether a word is
// compatible with the scoring so far - if it isn't, that word is
// eliminated from the set of remaining possible solutions.
// This is the only data of any significant size that needs to
// be in RAM - all the other large arrays are stored in ROM.
static char eliminated[WORDS/8+1];

const char const *word[WORDS] IN_ROM = {
  "that", "this", "with", "from", "your", "have", "more", "will", 
  "home", "page", "free", "time", "they", "site", "what", "news", 
  "only", "when", "here", "also", "help", "view", "been", "were", 
  "some", "like", "than", "find", "date", "back", "list", "name", 
  "just", "over", "year", "into", "next", "used", "work", "last", 
  "most", "data", "make", "them", "post", "city", "such", "best", 
  "then", "good", "well", "info", "high", "each", "very", "book", 
  "read", "need", "many", "user", "said", "does", "mail", "full", 
  "life", "know", "days", "part", "real", "item", "must", "made", 
  "line", "send", "type", "take", "area", "want", "long", "code", 
  "show", "even", "much", "sign", "file", "link", "open", "case", 
  "same", "both", "game", "care", "down", "size", "shop", "text", 
  "rate", "form", "love", "john", "main", "call", "save", "card", 
  "jobs", "food", "sale", "teen", "room", "join", "west", "look", 
  "left", "team", "week", "note", "live", "plan", "cost", "test", 
  "come", "cart", "play", "less", "park", "side", "give", "sell", 
  "body", "east", "club", "road", "gift", "hard", "four", "blue", 
  "easy", "star", "hand", "keep", "baby", "term", "film", "head", 
  "cell", "self", "away", "once", "sure", "cars", "tell", "able", 
  "gold", "arts", "past", "five", "upon", "says", "land", "done", 
  "ever", "word", "bill", "talk", "nude", "kids", "true", "else", 
  "mark", "rock", "tips", "plus", "auto", "edit", "fast", "fact", 
  "unit", "meet", "feel", "bank", "risk", "town", "girl", "toys", 
  "golf", "loan", "wide", "sort", "half", "step", "none", "lake", 
  "fire", "chat", "loss", "face", "base", "near", "stay", "turn", 
  "mean", "king", "copy", "drug", "pics", "cash", "seen", "port", 
  "stop", "soon", "held", "mind", "lost", "tour", "menu", "hope", 
  "wish", "role", "came", "fine", "hour", "bush", "huge", "kind", 
  "move", "logo", "nice", "sent", "band", "lead", "went", "mode", 
  "fund", "male", "took", "song", "late", "fall", "idea", "tool", 
  "hill", "maps", "deal", "hold", "safe", "feed", "hall", "anti", 
  "ship", "paid", "hair", "tree", "thus", "wall", "wine", "vote", 
  "ways", "rule", "told", "feet", "sexy", "door", "cool", "uses", 
  "java", "pass", "fees", "skin", "ring", "boys", "deep", "rest", 
  "pool", "mini", "fish", "pack", "born", "race", "rape", "debt", 
  "core", "sets", "wood", "rent", "dark", "host", "fair", "gets", 
  "dead", "mike", "trip", "poor", "eyes", "farm", "lord", "hear", 
  "goes", "wife", "hits", "zone", "jack", "flat", "flow", "path", 
  "laws", "skip", "diet", "army", "gear", "lots", "firm", "jump", 
  "ball", "goal", "sold", "wind", "palm", "pain", "oral", "ford", 
  "edge", "root", "pink", "shot", "cold", "foot", "mass", "heat", 
  "wild", "miss", "task", "soft", "fuel", "walk", "wait", "rose", 
  "pick", "load", "tags", "guys", "cock", "drop", "rich", "seem", 
  "hire", "gave", "ones", "tits", "rank", "died", "inch", "snow", 
  "camp", "fill", "gone", "fort", "gene", "disc", "boat", "icon", 
  "ends", "cast", "felt", "soul", "aids", "flag", "atom", "iron", 
  "void", "disk", "desk", "vice", "duty", "bear", "gain", "lack", 
  "knew", "zoom", "blow", "clip", "wire", "tape", "acid", "cent", 
  "null", "zero", "roll", "bath", "font", "beta", "fail", "jazz", 
  "bags", "wear", "rare", "bars", "dual", "rise", "bird", "lady", 
  "dell", "seat", "bids", "toll", "cape", "mine", "whom", "math", 
  "dogs", "moon", "fear", "wars", "kept", "beat", "arms", "hide", 
  "slow", "nine", "spot", "grow", "rain", "onto", "bass", "hole", 
  "pets", "ride", "pair", "runs", "yeah", "evil", "euro", "peak", 
  "dick", "salt", "bell", "lane", "kill", "ages", "plug", "cook", 
  "bike", "lose", "seek", "kits", "soil", "matt", "exit", "keys", 
  "wave", "holy", "acts", "mesh", "dean", "poll", "bond", "jean", 
  "visa", "pure", "hell", "lens", "draw", "warm", "suck", "babe", 
  "crew", "legs", "rear", "node", "lock", "mile", "bowl", "tank", 
  "navy", "dish", "slot", "gray", "demo", "hate", "rice", "loop", 
  "vary", "milk", "boot", "push", "dear", "beer", "earn", "twin", 
  "bits", "suit", "chip", "char", "echo", "grid", "pull", "nick", 
  "plot", "pump", "exam", "beds", "grey", "bold", "scan", "aged", 
  "bulk", "cute", "para", "seed", "peer", "meat", "bang", "bone", 
  "bugs", "gate", "tone", "busy", "neck", "wing", "tiny", "rail", 
  "tube", "belt", "luck", "dial", "gang", "cake", "semi", "cafe", 
  "till", "shoe", "sand", "seal", "lies", "pipe", "deck", "thin", 
  "sick", "dose", "lets", "cats", "folk", "okay", "hist", "lift", 
  "mall", "fell", "yard", "pour", "dust", "butt", "kent", "adds", 
  "ward", "roof", "kiss", "rush", "yoga", "lamp", "glad", "wins", 
  "rack", "boss", "solo", "tall", "nova", "wake", "drum", "ease", 
  "orgy", "tabs", "pine", "tend", "gulf", "rick", "hunt", "mill", 
  "burn", "labs", "sole", "laid", "clay", "weak", "wise", "odds", 
  "sons", "leaf", "silk", "wolf", "fits", "kick", "meal", "hurt", 
  "slip", "cuts", "mars", "caps", "pill", "meta", "mint", "spin", 
  "wash", "aims", "soap", "axis", "guns", "hero", "punk", "duke", 
  "pace", "wage", "dawn", "coat", "doll", "reed", "mice", "temp", 
  "vast", "wrap", "mood", "quiz", "beam", "tops", "shut", "thou", 
  "mask", "coal", "lion", "beef", "hats", "surf", "hook", "cord", 
  "crop", "sing", "tons", "hang", "damn", "hood", "fame", "eggs", 
  "ruby", "stem", "drew", "tune", "corn", "puts", "grew", "trek", 
  "ties", "brad", "jury", "tail", "lawn", "soup", "byte", "nose", 
  "trim", "quit", "lung", "sees", "bull", "cole", "mart", "tale", 
  "docs", "coin", "fake", "cure", "arch", "bomb", "harm", "deer", 
  "oven", "noon", "mate", "chef", "isle", "slim", "spec", "midi", 
  "tied", "dale", "boob", "oils", "sept", "unto", "pays", "lang", 
  "stud", "fold", "slut", "pole", "bend", "glen", "lips", "pond", 
  "tire", "chad", "josh", "drag", "ripe", "rely", "nuts", "nail", 
  "span", "joke", "pads", "inns", "cups", "foam", "poem", "asks", 
  "bean", "bias", "swim", "loud", "rats", "stat", "thee", "ruth", 
  "pray", "pope", "jeep", "bare", "hung", "mono", "tile", "ciao", 
  "knee", "prep", "pros", "cant", "duck", "dive", "raid", "volt", 
  "dirt", "geek", "sink", "grip", "watt", "pins", "polo", "horn", 
  "frog", "logs", "snap", "swap", "flip", "buzz", "nuke", "boom", 
  "calm", "fork", "troy", "sims", "tray", "sage", "cave", "wool", 
  "eyed", "grab", "oops", "trap", "fool", "dies", "jail", "lace", 
  "ugly", "hart", "rows", "gods", "poly", "ears", "fist", "mere", 
  "cons", "taxi", "worn", "shaw", "expo", "deny", "trio", "cube", 
  "rugs", "crap", "fate", "oval", "tier", "earl", "cite", "mess", 
  "rope", "dump", "hose", "pubs", "mild", "clan", "sync", "mesa", 
  "hull", "shed", "memo", "tide", "funk", "reel", "bind", "rand", 
  "buck", "acre", "lows", "aqua", "pest", "reef", "jill", "sofa", 
  "tent", "hack", "dare", "hawk", "lamb", "junk", "poet", "epic", 
  "sake", "lean", "dude", "alto", "gore", "cult", "dash", "cage", 
  "ping", "flux", "rage", "rays", "acne", "undo", "halo", "gays", 
  "exec", "doom", "bite", "myth", "weed", "dice", "quad", "dock", 
  "mods", "hint", "buys", "pork", "barn", "fare", "bald", "mold", 
  "dame", "herb", "idle", "cove", "flex", "hash", "lazy", "carb", 
  "pens", "worm", "deaf", "mats", "mime", "keen", "peas", "owns", 
  "zinc", "guru", "levy", "bras", "pale", "gaps", "tear", "nest", 
  "gale", "idol", "moss", "cork", "dome", "heel", "yang", "dumb", 
  "feat", "glow", "oaks", "norm", "ware", "jade", "foul", "keno", 
  "seas", "pose", "goat", "sail", "bolt", "gage", "urge", "neon", 
  "ours", "lone", "cope", "lime", "kirk", "spas", "jets", "yarn", 
  "knit", "pike", "bent", "mama", "coil", "lily", "joey", "tilt", 
  "bead", "leak", "bulb", "iris", "stir", "pile", "wade", "pony", 
  "leap", "swan", "scat", "nets", "bash", "neat", "bump", "aunt", 
  "crow", "gram", "sits", "toes", "bust", "cola", "gems", "outs", 
  "foil", "amps", "tick", "vans", "glue", "cone", "olds", "ramp", 
  "pear", "clue", "duff", "scam", "beck", "tome", "prof", "sins", 
  "hath", "prop", "maid", "haha", "rods", "pigs", "maya", "deed", 
  "papa", "warn", "cops", "peso", "vent", "dots", "mugs", "vase", 
  "homo", "pier", "saga", "gran", "mayo", "lisp", "chin", "wont", 
  "hubs", "soda", "tomb", "prom", "cubs", "pulp", "pots", "slam", 
  "crib", "noun", "crab", "hike", "bore", "cows", "peel", "bake", 
  "heal", "tote", "sour", "sock", "bail", "tees", "mist", "verb", 
  "chic", "vest", "tens", "puma", "rant", "gill", "rude", "sang", 
  "curl", "deli", "vine", "vale", "limo", "rust", "avid", "bets", 
  "fade", "monk", "pooh", "torn", "heck", "bark", "lynx", "roms", 
  "odor", "flew", "apex", "curb", "deco", "coke", "webs", "prod", 
  "cane", "fury", "wore", "dues", "gigs", "plea", "prey", "lick", 
  "ness", "whip", "prog", "bins", "bout", "hank", "fond", "sore", 
  "fiat", "noel", "cans", "aide", "lieu", "reds", "knob", "dove", 
  "mack", "sung", "ally", "holt", "dull", "bees", "sigh", "mock", 
  "bats", "melt", "faux", "pant", "hype", "rite", "turf", "berg", 
  "muse", "tyne", "lust", "luna", "lien", "vein", "hale", "tiff", 
  "bait", "dent", "macs", "sums", "lame", "fuse", "pops", "amid", 
  "knot", "tate", "coop", "kris", "regs", "plum", "loft", "lump", 
  "halt", "aero", "bury", "duct", "lend", "pans", "ions", "rams", 
  "gown", "ruin", "tuna", "wipe", "haul", "duly", "obey", "mare", 
  "kite", "heap", "eats", "flea", "pals", "hail", "herd", "calf", 
  "rave", "jerk", "flap", "diva", "taps", "oath", "gala", "tang", 
  "riot", "fats", "ritz", "lush", "grim", "flop", "toss", "pity", 
  "woke", "cuff", "reps", "eddy", "cues", "colt", "offs", "jars", 
  "hips", "wigs", "hunk", "chap", "tele", "harp", "phat", "tack", 
  "sack", "peek", "secs", "sued", "toby", "opal", "toon", "viva", 
  "blew", "lava", "vail", "envy", "shah", "bots", "stag", "rash", 
  "boil", "vain", "maze", "rode", "amen", "warp", "zeta", "brew", 
  "kern", "coup", "fore", "alps", "subs", "limb", "limp", "mute", 
  "dart", "robe", "mast", "cozy", "comb", "alas", "chop", "onyx", 
  "hoop", "nope", "dire", "gull", "rims", "shin", "flaw", "pane", 
  "vibe", "teas", "anon", "ribs", "barb", "huns", "aura", "sect", 
  "nous", "mole", "owed", "buff", "clad", "fled", "aces", "lied", 
  "bloc", "hugs", "owls", "pimp", "gimp", "hemp", "inks", "wink", 
  "fife", "stub", "tort", "dams", "mach", "spur", "skis", "pact", 
  "lulu", "vita", "ibis", "mule", "kiwi", "duel", "mead", "gong", 
  "bays", "gaze", "hulk", "cyan", "axes", "haze", "pits", "ants", 
  "tuck", "slab", "lure", "kart", "ling", "tubs", "mags", "hers", 
  "grin", "spit", "acme", "rove", "chow", "aria", "dirk", "scar", 
  "dorm", "pies", "saws", "dine", "slap", "jaws", "ante", "bred", 
  "tout", "hare", "tory", "veil", "peck", "helm", "jess", "jays", 
  "chew", "teak", "sane", "dune", "mana", "lest", "blur", "punt", 
  "mojo", "dime", "carp", "dusk", "lent", "aloe", "puff", "claw", 
  "tyre", "wand", "taco", "weld", "writ", "typo", "damp", "fern", 
  "lore", "gyms", "arid", "jive", "spun", "loch", "balm", "figs", 
  "chit", "lays", "drip", "mans", "pint", "maxi", "liar", "opus", 
  "mage", "teal", "bard", "reap", "tidy", "vets", "bows", "beau", 
  "rang", "laps", "pong", "vows", "soar", "flee", "woes", "stew", 
  "hush", "lama", "akin", "dads", "hays", "soak", "hymn", "quay", 
  "weir", "dram", "burr", "slug", "lira", "jams", "dyes", "yell", 
  "fins", "rake", "suns", "bunk", "stab", "dyke", "seam", "omit", 
  "darn", "ammo", "linn", "veto", "clam", "nerd", "guts", "bans", 
  "buds", "sire", "ding", "coma", "thug", "sham", "loaf", "skid", 
  "poop", "whey", "curt", "moth", "mash", "germ", "atop", "kemp", 
  "puck", "moor", "lube", "sway", "toad", "eros", "malt", "pods", 
  "clap", "paws", "poke", "dope", "kiln", "jock", "dyed", "wasp", 
  "fuss", "swat", "sine", "bray", "roar", "gall", "jugs", "apes", 
  "slit", "cine", "beep", "toms", "slid", "nana", "raft", "brow", 
  "vars", "fink", "deem", "flax", "tart", "tram", "iced", "bile", 
  "heir", "loco", "feds", "loom", "grub", "slew", "duet", "ohms", 
  "muck", "hoax", "wary", "riff", "mace", "lids", "pore", "oily", 
  "whoa", "joys", "grit", "nays", "sinh", "sues", "tame", "oats", 
  "wilt", "ting", "emit", "rink", "numb", "scot", "pave", "airy", 
  "hobo", "hops", "airs", "dole", "wick", "owes", "peat", "tofu", 
  "twat", "sunk", "perm", "lair", "lacy", "wren", "arcs", "ayes", 
  "heed", "boon", "pawn", "tore", "dunk", "snip", "mutt", "ouch", 
  "dips", "digs", "womb", "joss", "kohl", "pups", "lido", "daft", 
  "gilt", "trad", "taxa", "sled", "elan", "refs", "coax", "lees", 
  "alum", "doth", "plow", "smut", "foes", "blot", "imam", "hove", 
  "rial", "sewn", "rift", "peep", "judo", "mays", "oboe", "lobe", 
  "gosh", "mica", "lads", "sumo", "urea", "zeal", "bong", "gent", 
  "hind", "ache", "yoke", "tins", "loot", "gasp", "tint", "silt", 
  "lint", "blob", "roam", "stun", "trey", "fang", "weep", "giga", 
  "ergo", "moan", "sank", "bale", "smog", "keel", "fart", "cosy", 
  "seer", "vial", "huff", "gust", "musk", "lice", "skim", "rune", 
  "welt", "veal", "rags", "posh", "mink", "itch", "dill", "rigs", 
  "moot", "agar", "rein", "buoy", "hive", "newt", "dung", "lark", 
  "hoes", "ruff", "zoos", "scum", "bran", "faro", "giro", "cots", 
  "fret", "gums", "glib", "gees", "vile", "brio", "peri", "loci", 
  "hula", "foxy", "putt", "yeas", "cram", "hens", "hogs", "fray", 
  "gags", "rips", "sash", "lire", "raja", "boar", "mite", "spar", 
  "redo", "nome", "brat", "wits", "anew", "loon", "hone", "sips", 
  "wort", "nuns", "tuba", "jest", "mort", "repo", "gnus", "jolt", 
  "skew", "cyst", "fowl", "pate", "snug", "orca", "nook", "rosy", 
  "howl", "hobs", "ogre", "sped", "yogi", "pats", "dojo", "gait", 
  "meek", "stow", "bibs", "cabs", "hump", "beet", "geld", "pegs", 
  "meow", "lash", "ills", "omen", "brig", "tuff", "coda", "defy", 
  "foss", "kilt", "whit", "coos", "vino", "clog", "yeti", "sill", 
  "buns", "nils", "lain", "holm", "tots", "tors", "furl", "hogg", 
  "muon", "afar", "fawn", "etch", "flue", "emir", "mobs", "gout", 
  "rubs", "bobs", "bane", "thaw", "eels", "shun", "daze", "trot", 
  "woof", "davy", "wham", "begs", "mull", "bode", "urns", "quid", 
  "kilo", "nods", "parr", "dork", "sari", "mitt", "yawn", "feud", 
  "brut", "gist", "zips", "tact", "rife", "huts", "silo", "eras", 
  "mend", "mums", "tern", "lass", "rota", "jute", "prim", "pang", 
  "swag", "opts", "mano", "furs", "whim", "pied", "nigh", "ales", 
  "sump", "zest", "wisp", "sift", "ooze", "fume", "brag", "muff", 
  "snag", "yank", "shag", "hues", "lags", "spat", "ices", "ahem", 
  "wavy", "crux", "obit", "slag", "skit", "kelp", "vamp", "iota", 
  "bled", "pita", "slum", "fuzz", "toil", "garb", "pars", "twig", 
  "wept", "edgy", "jigs", "burg", "rook", "pall", "trig", "moat", 
  "swam", "hazy", "hoof", "frag", "vise", "lute", "pram", "brim", 
  "chum", "glut", "neve", "sacs", "soot", "roux", "vane", "mane", 
  "kink", "rhea", "sown", "beak", "rung", "twas", "loam", "romp", 
  "czar", "mush", "foal", "gogo", "noes", "pail", "loin", "leer", 
  "nave", "hows", "leek", "puss", "oars", "clot", "soya", "joes", 
  "morn", "glug", "rout", "ploy", "magi", "puke", "glee", "hams", 
  "hoot", "pina", "bott", "kale", "huck", "juke", "jinx", "tics", 
  "tora", "fido", "aver", "pugs", "tala", "cols", "milt", "wart", 
  "naps", "gush", "ogle", "buss", "hiss", "rusk", "gory", "bony", 
  "moll", "mews", "cask", "brie", "oxen", "bums", "mops", "nota", 
  "fend", "veer", "nips", "debs", "glob", "ream", "ores", "boll", 
  "shim", "ides", "gnat", "amok", "arty", "smug", "dons", "yule", 
  "lugs", "bate", "pert", "tsar", "cosh", "burp", "wert", "cusp", 
  "bade", "revs", "yolk", "boos", "cull", "maul", "ahoy", "haar", 
  "poms", "yelp", "gyro", "luge", "sear", "egos", "pare", "viol", 
  "tarp", "puny", "miso", "fizz", "foci", "drab", "flak", "yuck", 
  "quod", "ably", "lard", "hypo", "swab", "rind", "rote", "ruse", 
  "muss", "spud", "croc", "elms", "feta", "onus", "bier", "lull", 
  "lino", "shew", "elks", "tutu", "raps", "alms", "biff", "swot", 
  "asps", "mote", "wold", "boas", "idem", "hark", "thud", "weds", 
  "perk", "firs", "rump", "pent", "sago", "rive", "tabu", "gawk", 
  "hock", "heft", "lewd", "dupe", "bogs", "tosh", "loup", "swig", 
  "fete", "duns", "fain", "pips", "sirs", "cowl", "slat", "goon", 
  "pica", "taut", "kola", "snob", "crud", "tine", "racy", "awry", 
  "lode", "spay", "toke", "clef", "pelt", "wadi", "goof", "ankh", 
  "dank", "zany", "toga", "puns", "hilt", "roan", "nags", "wily", 
  "dodo", "cogs", "talc", "pomp", "noms", "spew", "gulp", "lurk", 
  "pend", "toot", "snot", "hurl", "dory", "nary", "ibex", "orbs", 
  "razz", "zing", "toed", "scab", "phew", "wail", "crag", "tass", 
  "eves", "minx", "dens", "quin", "purr", "nits", "oust", "bask", 
  "gash", "dubs", "odes", "wane", "oyez", "fads", "ovum", "dene", 
  "slaw", "nabs", "whig", "tugs", "meld", "lyre", "deft", "husk", 
  "hick", "honk", "turd", "cuss", "pout", "mire", "nett", "saps", 
  "shiv", "balk", "sark", "robs", "idly", "ewes", "gast", "waxy", 
  "loos", "mien", "rede", "abet", "kerb", "curd", "barf", "blip", 
  "icky", "doss", "sows", "wimp", "moos", "oryx", "yams", "rend", 
  "kine", "rots", "rood", "dado", "whet", "doer", "seep", "sods", 
  "sobs", "purl", "sawn", "muds", "wean", "juju", "dink", "imps", 
  "pupa", "suds", "okra", "bren", "snub", "prat", "dims", "derm", 
  "scud", "sops", "slur", "uric", "tusk", "twee", "shoo", "sate", 
  "yore", "slop", "bozo", "twos", "hake", "gaol", "tarn", "fags", 
  "tare", "gaga", "flay", "fess", "hots", "sett", "ilex", "whee", 
  "awed", "twit", "ruck", "slog", "flog", "topi", "wile", "duds", 
  "deet", "rime", "goad", "spry", "coot", "jabs", "oink", "pews", 
  "brae", "jots", "ursa", "plop", "grog", "mell", "runt", "cede", 
  "teem", "bonk", "duos", "suet", "inky", "hewn", "vole", "syne", 
  "flan", "axed", "jags", "quip", "shod", "iffy", "saki", "wove", 
  "bide", "bevy", "flit", "dour", "kegs", "nosy", "dabs", "posy", 
  "ghee", "vend", "abut", "eons", "luff", "teat", "dais", "pith", 
  "gaff", "chug", "laud", "buts", "goer", "peed", "bods", "peal", 
  "coir", "kook", "nobs", "vats", "trod", "nape", "hols", "weft", 
  "teds", "lase", "goos", "gins", "reek", "wets", "kens", "hums", 
  "vacs", "bung", "rapt", "otic", "leet", "pees", "rasp", "doze", 
  "wonk", "tats", "dint", "ells", "gape", "sone", "wows", "bole", 
  "craw", "tuft", "toft", "flam", "nibs", "ails", "cued", "slob", 
  "glum", "hems", "serf", "boxy", "woks", "hued", "hoar", "jamb", 
  "whys", "fens", "cads", "abed", "ruts", "ulan", "prow", "suss", 
  "dace", "wags", "maim", "kudu", "tush", "espy", "rums", "tipi", 
  "curs", "zits", "gunk", "vies", "lope", "errs", "roup", "faze", 
  "ajar", "fobs", "irks", "nosh", "byes", "lout", "mete", "wads", 
  "swop", "togs", "jibe", "haws", "gobs", "raze", "hasp", "wain", 
  "pyre", "apse", "souk", "tope", "lorn", "nock", "tows", "dewy", 
  "weal", "koan", "puce", "epee", "stet", "tars", "amyl", "teed", 
  "yobs", "dibs", "emus", "yurt", "caws", "lade", "wend", "wiry", 
  "snog", "tuts", "exes", "dray", "haft", "iglu", "fogs", "daws", 
  "loth", "trow", "sibs", "blab", "gyre", "frit", "achy", "arum", 
  "sags", "lath", "woos", "gild", "wino", "wyle", "lank", "skat", 
  "aced", "plod", "faun", "hebe", "tyro", "rill", "tamp", "oast", 
  "gird", "gnaw", "pock", "tyke", "scag", "ebbs", "laze", "drat", 
  "clod", "waif", "kith", "sulk", "cobs", "dhow", "kips", "dolt", 
  "rids", "knap", "adze", "clew", "ewer", "floe", "oldy", "guff", 
  "nubs", "lilt", "wees", "ashy", "efts", "lobs", "jogs", "zaps", 
  "dews", "daub", "ulna", "adit", "murk", "wist", "coif", "flab", 
  "ouzo", "ossa", "toff", "vair", "gads", "khat", "yaks", "skua", 
  "veep", "clop", "wive", "zags", "kins", "tike", "ghat", "bilk", 
  "vied", "sorb", "fibs", "bops", "snit", "nowt", "erne", "rues", 
  "dote", "ergs", "scow", "mown", "pash", "sews", "rile", "nide", 
  "pawl", "neap", "kapa", "arks", "rhos", "moke", "frap", "waft", 
  "jeer", "impi", "skee", "swum", "yawl", "agog", "doff", "wynd", 
  "hags", "egad", "juts", "gabs", "etui", "mope", "ogee", "stob", 
  "maws", "bawl", "woad", "busk", "sloe", "lops", "roue", "yaws", 
  "tuns", "ecus", "loll", "chaw", "tufa", "jowl", "zonk", "kadi", 
  "utas", "eggy", "boff", "gelt", "tzar", "conk", "skag", "unco", 
  "wych", "avow", "hews", "dozy", "poky", "roil", "mows", "oohs", 
  "stye", "zebu", "miff", "boyo", "grot", "byre", "raki", "eked", 
  "gamp", "harl", "whin", "idyl", "vagi", "corm", "wens", "ulva", 
  "neuk", "ulus", "dins", "bawd", "fops", "hoed", "lour", "gibe", 
  "hadj", "mazy", "awls", "moil", "phut", "uvea", "hies", "sots", 
  "upas", "hied", "jape", "skeg", "dunt", "dugs", "braw", "hods", 
  "yips", "rued", "sups", "nark", "puds", "yaps", "oafs", "odic", 
  "taws", "fugs", "iamb", "trug", "goys", "orra", "frug", "peke", 
  "prig", "gley", "jilt", "auks", "ilea", "albs", "ekes", "keek", 
  "cloy", "gybe", "oxid", "eyas", "joky", "spiv", "gawp", "aped", 
  "lyes", "aery", "awes", "tivy", "scut", "yowl", "surd", "oozy", 
  "zigs", "pleb", "frow", "enow", "zees", "drib", "winy", "jink", 
  "drub", "tups", "shmo", "mump", "smew", "wost", "sned", "sild", 
  "nogs", "sizy", "girn", "dopy", "snib", "pipy", "zeds", "xyst", 
  "ogam", "knar", "knur"
};

// apologies for the Bowdlerization of maybe half a dozen words - the word
// list came from scratch.mit.edu which has strict rules about inappropriate
// language for young children.

uint16_t recorded_word[12]; // record the number of the word for each guess.
int recorded_score[12]; // if we can spare the space, use this for verifying scoring.

const char const *prompt[12] IN_ROM = {
  "Your first guess: ",
  "Your second guess: ",
  "Your third guess: ",
  "Your fourth guess: ",
  "Your fifth guess: ",
  "Your sixth guess: ",
  "Your seventh guess: ",
  "Your eighth guess: ",
  "Your ninth guess: ",
  "Your tenth guess: ",
  "Your penultimate guess: ",
  "Your final guess: ",
};

#ifndef TRUE
#define TRUE (0==0)
#define FALSE (0!=0)
#endif

#ifndef CLI
unsigned int _x;
unsigned int _a;
unsigned int _b; 
unsigned int _c; 
void initRandom(unsigned int s1,unsigned int s2,unsigned int s3, unsigned int x0)
{
	_x = x0;
	_a = s1;
	_b = s2;
	_c = s3;
	_x++;
	_a = (_a^_c^_x);
	_b = (_b+_a);
	_c = ((_c+(_b>>1))^_a);
}

uint16_t random8()
{
	_x++;
	_a = (_a^_c^_x);
	_b = (_b+_a);
	_c = ((_c+(_b>>1))^_a);
	return (uint16_t)_c;
}

uint16_t random(void) {
  return (random8() << 8 | random8()) ^ (random8()<<4);
}

static inline int isalpha(int c) {
  return ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')));
}
static inline int isupper(int c) {
  return (('A' <= c) && (c <= 'Z'));
}
static inline int islower(int c) {
  return (('a' <= c) && (c <= 'z'));
}
static inline int tolower(int c) {
  return c-'A'+'a';
}

#endif

static int score(const char *hidden_word, const char *guess, int *bulls, int *cows) {
  char my_word[5], my_guess[5];
  int p;
  for (p = 0; p < 4; p++) {      // make writable
    my_word[p] = hidden_word[p];
    my_guess[p] = guess[p];
  }
  
  *bulls = 0; *cows = 0;
  for (p = 0; p < 4; p++) {
    if (my_guess[p] == my_word[p]) {
      // remove from further consideration:
      my_word[p] = ' ';
      my_guess[p] = '_';
      *bulls += 1;
    }
  }
  if ((my_guess[0] != '_') && (my_guess[0] == my_word[p=1] || my_guess[0] == my_word[p=2] || my_guess[0] == my_word[p=3])) {
    my_word[p] = ' '; *cows += 1;
  }
  if ((my_guess[1] != '_') && (my_guess[1] == my_word[p=0] || my_guess[1] == my_word[p=2] || my_guess[1] == my_word[p=3])) {
    my_word[p] = ' '; *cows += 1;
  }
  if ((my_guess[2] != '_') && (my_guess[2] == my_word[p=0] || my_guess[2] == my_word[p=1] || my_guess[2] == my_word[p=3])) {
    my_word[p] = ' '; *cows += 1;
  }
  if ((my_guess[3] != '_') && (my_guess[3] == my_word[p=0] || my_guess[3] == my_word[p=1] || my_guess[3] == my_word[p=2])) {
    my_word[p] = ' '; *cows += 1;
  }
  return *bulls * 5 + *cows;
}

static void eliminate(uint16_t word_index) { // use a bit array to keep trackl of eliminated words.
  uint16_t index;
  int bit;
  index = word_index >> 3;
  bit = 1 << (word_index&7); // assuming 1<<0 == 1 is implemented correctly.
  eliminated[index] |= bit;
}

static int is_eliminated(uint16_t word_index) {
  uint16_t index;
  int bit;
  index = word_index >> 3;
  bit = 1 << (word_index&7);
  return (eliminated[index] & bit) != 0;
}

void dump_marks(int guesses) {
  int i;
#ifdef CLI
  fprintf(stderr, "You can check the scoring here.\n\n    Word Score\n");
#endif
  for (i = 0; i < guesses; i++) {
    int bulls, cows, score;
    uint16_t w;
    w = recorded_word[i];
    score = recorded_score[i];
    cows = score%5; bulls = score/5;
#ifdef CLI
    fprintf(stderr, "%2d: %s ", i+1, word[w]);
    while (bulls-- > 0) fprintf(stderr, "+");
    while (cows-- > 0) fprintf(stderr, "?");
    fprintf(stderr, "\n");
#endif
  }
#ifdef CLI
  fprintf(stderr, "\n");
#endif
}

void check_scores(const char *hidden_word, int guesses) {
  int i;
#ifdef CLI
  fprintf(stderr, "         Score   Actual\n");
  fprintf(stderr, "    Word By You  Score\n");
#endif
  for (i = 0; i < guesses; i++) {
    int chars, bulls, cows, my_score, your_score;
    uint16_t w;
    w = recorded_word[i];
    your_score = recorded_score[i];
    cows = your_score%5; bulls = your_score/5; chars = 4-(bulls+cows);
#ifdef CLI
    fprintf(stderr, "%2d: %s ", i+1, word[w]);
    while (bulls-- > 0) fprintf(stderr, "+");
    while (cows-- > 0) fprintf(stderr, "?");
    while (chars-- > 0) fprintf(stderr, " ");
    fprintf(stderr, "    ");
#endif
    my_score = score(hidden_word, word[w], &bulls, &cows); chars = 4-(bulls+cows);
#ifdef CLI
    while (bulls-- > 0) fprintf(stderr, "+");
    while (cows-- > 0) fprintf(stderr, "?");
    while (chars-- > 0) fprintf(stderr, " ");
    if (your_score != my_score) fprintf(stderr, "   <--- looks like you mis-scored that one...");
    fprintf(stderr, "\n");
#endif
  }
#ifdef CLI
  fprintf(stderr, "\n");
#endif
}

#define COMPUTER 0
#define HUMAN 1
int main(void) {
  uint16_t w, temp, p, words = WORDS; // sizeof(word)/sizeof(word[0]);
  int bulls, cows, guesses, humans_score, turn;
  char *saved_word;
  char guess[5]; // need to be writable

#ifndef CLI
  for (;;) {
    Wait_Recal();
  }
#endif
  
#ifdef DEBUGGING_SCORES
  humans_score = score("wasp", "pall", &bulls, &cows);
  fprintf(stderr, "score(wasp, pall) = %d, bulls = %d, cows = %d\n", humans_score, bulls, cows);
  exit(0);
#endif
  
  //fprintf(stderr, "%d words from %s to %s\n", words, word[0], word[words-1]);
  turn = HUMAN;
#ifdef CLI
  fprintf(stderr, "\nI'll pick a word first, it'll give you a chance to learn the scoring system\n"
                  "before you have to score my guesses...\n\nIMPORTANT NOTE TO REMEMBER: All words have 4 letters.\n\n");
#endif
 restart:
  turn = (HUMAN+COMPUTER) - turn;
  if (turn == HUMAN) {
    int valid = 0, awarded_score;
    char *computers_guess;
    for (w = 0; w < 2564/8+1; w++) eliminated[w] = 0;
#ifdef CLI
    fprintf(stderr, "I want you to think of a word with FOUR LETTERS and I'll try to\n"
                    "guess it.  For every letter in your word that matches a letter in the\n"
                    "same place in my word, you award me a '+'.  For each of the remaining\n"
                    "letters in your word, if they appear anywhere in my word, You\n"
                    "give me a '?'.\n\n");
#endif
    // srandom((unsigned int)clock());
    computers_guess = (char *)word[temp = random()%/*words*/SIMPLE_WORDS];
    guesses = 0;
#ifdef CLI
    fprintf(stderr, "My first guess is: %s\n\n(use '+' and '?', or '0' if none.)\n", computers_guess);
#endif
    recorded_word[guesses] = temp;
    guesses += 1;
  next_try:
#ifdef CLI
    fprintf(stderr, "What's my score?: ");
#endif
    valid = FALSE; bulls = 0; cows = 0; 
    for (;;) {
      int c = '\n';
#ifdef CLI
      c = fgetc(stdin);
#endif
      if (c == EOF) {
#ifdef CLI
        fprintf(stderr, "You give up?  OK, I win. Your turn to guess next.\n");
#endif
        dump_marks(guesses);
        goto restart;
      }
      if (c == '+' || c == '?' || c == '0') valid = valid | TRUE;
      if (c == '+') bulls += 1;
      if (c == '?') cows += 1;
      if (c == '\n') {
        if (!valid) {
#ifdef CLI
          fprintf(stderr, "Remember, for every letter in your word that matches a letter in the\n"
                          "same place in my word, you award me a '+'.  For each of the remaining\n"
                          "letters in your word, if they appear anywhere in my word, You\n"
                          "give me a '?'.  Enter '0' if I didn't guess any letters correct at all.\n\n"
                          "What's my score?: ");
#endif
          continue;
        } else break;
      }
    }
    awarded_score = bulls*5 + cows;
    recorded_score[guesses-1] = awarded_score;
    if (bulls == 4) {
#ifdef CLI
      fprintf(stderr, "Woo hoo!  I won, in %d guesses!\n\n", guesses);
#endif
      dump_marks(guesses);//
      goto restart;
    }
    if (guesses == 12) {
#ifdef CLI
      fprintf(stderr, "Well, that was 12 guesses and I didn't get it.\n");
#endif
     retype_humans_secret_word:
      for (;;) {
#ifdef CLI
        fprintf(stderr, "What was your word?\n");
#endif
        p = 0;
        for (;;) {
          int c = '\n';
#ifdef CLI
          c = fgetc(stdin);
#endif
          if (c == EOF) {
#ifdef CLI
            fprintf(stderr, "\nYou quit? OK.\n");
#endif
            dump_marks(guesses);//
            goto restart;
          }

          if (isalpha(c)) {
            if (isupper(c)) c = tolower(c);

            if (p < 4) {
              guess[p++] = (char)c;
            } else {
              p = 5; // signal to '\n' code that the word was too long
            }
          } else if (c == '\n') {
            if (p != 4) {
#ifdef CLI
              fprintf(stderr, "Your word had to be a word of four letters.  Try again.\n");
#endif
              goto retype_humans_secret_word;
            }
            break;
          } else {
            // silently ignore bad character
#ifdef DEBUG
            fprintf(stderr, "\nbad character '%c'\n", c);
#endif
          }
        }
        // was it a valid word?
        for (w = 0; w < words; w++) {
          for (p = 0; p < 4; p++) {
            if (guess[p] != word[w][p]) break;
            if (p==3) goto was_valid;
          }
        }
#ifdef CLI
        fprintf(stderr, "There's the problem... \"%s\" was not a word you could use.  You lose.\n", guess);
#endif
      was_valid:
#ifdef CLI
        fprintf(stderr, "I think there may have been a scoring error.  Let's check:\n\n");
#endif
        check_scores(guess, guesses);
        goto restart;
      }
      dump_marks(guesses);//
      goto restart;
    }
#ifdef CLI
    fprintf(stderr, "OK, so I scored %d bulls and %d cows.\n", bulls, cows);
#endif
    for (w = 0; w < words; w++) {
      int xbulls, xcows; // check
      // assume the hidden word was word[i].
      // If it were, is the score the player awarded for my guess compatible with that word?
      int test_score = score(word[w], computers_guess, &xbulls, &xcows);
      if (test_score != awarded_score) eliminate(w);
      // when you are down to 3 bulls, and there are multiple choices left for the last letter,
      // human players usually do something smarter than try them all one by one.
    }
    temp = 0;
    for (w = 0; w < words; w++) {
      if (!is_eliminated(w)) {
        temp += 1;
#ifdef DEBUG
        fprintf(stderr, "%s ", word[w]);
        if ((temp&7) == 7) fprintf(stderr, "\n");
#endif
      }
    }
#ifdef CLI
    fprintf(stderr, "\n");
#endif
    if (temp == 0) {
#ifdef CLI
      fprintf(stderr, "OK, I'm out of ideas.\n"
                      "I'm pretty sure that either you're using a word I don't know,\n"
                      "or you mis-calculated one of the scores you awarded me earlier.\n");
#endif
    re_enter_humans_secret_word:
      for (;;) {
#ifdef CLI
        fprintf(stderr, "What was your word?\n");
#endif
        p = 0;
        for (;;) {
          int c = '\n';
#ifdef CLI
          c = fgetc(stdin);
#endif
          if (c == EOF) {
#ifdef CLI
            fprintf(stderr, "\nYou quit?  OK.\n");
#endif
            dump_marks(guesses);//
            goto restart;
          }

          if (isalpha(c)) {
            if (isupper(c)) c = tolower(c);

            if (p < 4) {
              guess[p++] = (char)c;
            } else {
              p = 5; // signal to '\n' code that the word was too long
            }
          } else if (c == '\n') {
            if (p != 4) {
#ifdef CLI
              fprintf(stderr, "Your word has to be a word of four letters.  Try again.\n");
#endif
              goto re_enter_humans_secret_word;
            }
            break;
          } else {
            // silently ignore bad character
#ifdef DEBUG
            fprintf(stderr, "\nbad character '%c'\n", c);
#endif
          }
        }
        // was it a valid word?
        for (w = 0; w < words; w++) {
          for (p = 0; p < 4; p++) {
            if (guess[p] != word[w][p]) break;
            if (p==3) goto was_indeed_valid;
          }
        }
#ifdef CLI
        fprintf(stderr, "There's the problem... \"%s\" was not a word you could use.  You lose.\n", guess);
#endif
        goto restart;
      was_indeed_valid:
#ifdef CLI
        fprintf(stderr, "I think there may have been a scoring error.  Let's check:\n\n");
#endif
        check_scores(guess, guesses);
        goto restart;
      }
    } else if (temp == 1) {
#ifdef CLI
      fprintf(stderr, "I think I've guessed it!\n\n");
#endif
    } else {
#ifdef DEBUG
      fprintf(stderr, "There are %d possible words this could be!\n\n", temp);
#endif
    }
    // find non-eliminated word 'temp'...
    temp = random()%temp; // eg random(4) is 0..3
    computers_guess = "zzzz"; // delete when sure OK
    for (w = 0; w < words; w++) {
      if (!is_eliminated(w)) {
        if (temp == 0) {
          computers_guess = (char *)word[temp = w];
          break;
        }
        temp -= 1;
      }
    }

    bulls = 0; cows = 0;
#ifdef CLI
    fprintf(stderr, "My next guess is: %s\n\n(use '+' and '?', or '0' if none.)\n", computers_guess);
#endif
    recorded_word[guesses] = temp;
    guesses += 1;
    goto next_try;
  }

  guesses = 0;
#ifdef CLI
  fprintf(stderr, "I'm thinking of a word.  You can offer valid words as guesses.\n"
                  "For every letter in your word that matches a letter in the same\n"
                  "place in my word, I'll award you a '+'.  For each of the remaining\n"
                  "letters in your word, if they appear anywhere in my word I'll\n"
                  "give you a '?'.\n");
#endif
  // srandom((unsigned int)clock());
  saved_word = (char *)word[temp = random()%/*words*/SIMPLE_WORDS];
  //fprintf(stderr, "Saved word set to word %d: %s\n", temp, saved_word);
 retype_humans_guess:
  guess[4] = '\0';
  for (;;) {
    p=0; bulls=0; cows=0;
#ifdef CLI
    fprintf(stderr, "%s", prompt[guesses]);
#endif
    for (;;) {
      int c = '\n';
#ifdef CLI
      c = fgetc(stdin);
#endif
      if (c == EOF) {
#ifdef CLI
        fprintf(stderr, "\nYou quit?  The word was \"%s\"\n", saved_word);
#endif
        dump_marks(guesses);//
        goto restart;
      }

      if (isalpha(c)) {
        if (isupper(c)) c = tolower(c);

        if (p < 4) {
          guess[p++] = (char)c;
        } else {
          p = 5; // signal to '\n' code that the word was too long
        }
      } else if (c == '\n') {
        if (p != 4) {
#ifdef CLI
          fprintf(stderr, "Your guess has to be a word of four letters.  Try again.\n");
#endif
          goto retype_humans_guess;
        }
        break;
      } else {
        // silently ignore bad character
#ifdef DEBUG
        fprintf(stderr, "\nbad character '%c'\n", c);
#endif
      }
    }
    for (w = 0; w < words; w++) {
      for (p = 0; p < 4; p++) {
        if (guess[p] != word[w][p]) break;
        if (p==3) goto valid;
      }
    }
#ifdef CLI
    fprintf(stderr, "Sorry, \"%s\" is not a word you can use.  Try another one.\n", guess);
#endif
    continue;
  valid:
#ifdef CLI
    fprintf(stderr, "%s: ", guess);
#endif
    humans_score = score(saved_word, guess, &bulls, &cows);

    recorded_word[guesses] = w;
    recorded_score[guesses] = humans_score;
    guesses += 1;

#ifdef CLI
    for (p = 0; p < bulls; p++) fprintf(stderr, "+");
    for (p = 0; p < cows; p++) fprintf(stderr, "?");
    if (humans_score == 0) fprintf(stderr, "Washout!  Zip!  Nada!");
    fprintf(stderr, "\n");
#endif
    if (bulls == 4) {
#ifdef CLI
      fprintf(stderr, "You win!\n");
#endif
      dump_marks(guesses);//
      goto restart;
    }
    if (guesses == 12) {
#ifdef CLI
      fprintf(stderr, "That's your last guess.  I win.  My word was '%s'\n", saved_word);
#endif
      dump_marks(guesses);
      goto restart;
    }
  }
  return 0;
}
