//#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 "controller.h"
#define TEXT_SCALE (0x44)
#include <assert.h>
#define IN_ROM __attribute__ ((section(".text")))
#define NULL 0
#define EOF (-1)
#endif
// ###########################################################################

// 0 and smaller terminates!
int xstrlen (const char *s) {
  int c = 0;
  while ((signed int) (*(s)++) > 0) c++;
  return c;
}

const char matrix[6][6] = {  // 1 block, 6 down, 5 across+1 for \x80
   {'A', 'B', 'C', 'D', 'E', 0x80},
   {'F', 'G', 'H', 'I', 'J', 0x80},
   {'K', 'L', 'M', 'N', 'O', 0x80},
   {'P', 'Q', 'R', 'S', 'T', 0x80},
   {'U', 'V', 'W', 'X', 'Y', 0x80},
   {'Z', '<', 'O', 'K', '>', 0x80}
};

extern void syncPrintStrd (const int a, const int b, const void *u);
#define xPrint_Str_d syncPrintStrd

char *get_word (int screen_y) {
  int y;
  long int cx, cy;
  static unsigned int next = 0;
  static char input_line[7] = { ' ', ' ', ' ', ' ', ' ', 0x80, '\0' };
  char *input;

  input = &input_line[1]; // extra space for bug or could add prompt

  if (button_1_3_pressed ()) {if (next) next -= 1;}  // B3 is erase
  input[next] = 0x80; input[next+1] = '\0';

  cx =  (Vec_Joy_1_X + 128) / (255 / 6) - 1; // default center position
  cy = (-Vec_Joy_1_Y + 127) / (255 / 6) - 2;
  if (cx < 0) cx = 0;  if (cx > 4) cx = 4;
  if (cy < 0) cy = 0;  if (cy > 5) cy = 5;

  if ((button_1_4_pressed ())) { // B4 is accept
    if ((cy == 5) && (cx > 0)) { // accept word
      if (next == 4) {           // if all 4 letters entered
        next = 0; // reset for next word to be input
        return input;
      }
    } else {                     // accept letter
      if (next < 4) {            // if there is room
        input[next++] = matrix[cy][cx]; input[next] = (char) 0x80; input[next+1] = '\0';
      }
    }
  }

  dp_VIA_t1_cnt_lo = TEXT_SCALE;        // scale
  Reset0Ref ();
  Intensity_a (0x4f);
  // Display the letters of the word entered so far:
  xPrint_Str_d (120, -100, input_line);
  // and draw the choices
  for (y = 0; y <= 5; y++) xPrint_Str_d (screen_y + (5 - y) * 20 - 60, - 60, matrix[y]);

  Reset0Ref ();
  // Highlight the cursor
  Intensity_a (0x2f);
  #define SQUARESIZE 15
  if ((cy == 5) && (cx > 0)) { // the 'enter' box
    Moveto_d (screen_y + (5 - (int) cy) * 20 - 60 + 3, 20 - 60 + 10);
    Draw_Line_d (0, SQUARESIZE * 5 + 6); Draw_Line_d (-SQUARESIZE, 0);
    Draw_Line_d (0, -(SQUARESIZE * 5 + 6)); Draw_Line_d (SQUARESIZE, 0);
  } else {
    Moveto_d (screen_y + (5 - (int) cy) * 20 - 60 + 3, (int) cx * 20 - 60 + 10);
    Draw_Line_d (0, SQUARESIZE); Draw_Line_d (-SQUARESIZE, 0);
    Draw_Line_d (0, -SQUARESIZE); Draw_Line_d (SQUARESIZE, 0);
  }
  return NULL; // until a full word has been entered...
}
// ###########################################################################
#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

// Variables extracted from main()
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];                  // needs to be writable

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
}

void ShowGuesses (int guesses, int highlight) {
  int i, j;
  char vword[24];
  int y = 127 - 28;

  Wait_Recal ();
  check_buttons ();
  // check_joysticks();
  Joy_Analog ();
  Reset0Ref ();
  Intensity_a (0x50);

  i = 0;
  if (guesses)
    for (;;) {
      int bulls, cows, score;
      uint16_t w;

      w = recorded_word[i];
      score = recorded_score[i];
      cows = score % 5;
      bulls = score / 5;
      for (j = 0; j < 4; j++) vword[j] = word[w][j];
      vword[4] = (char) (i == highlight ? '<' : ' ');
      vword[5] = ' ';
      vword[6] = ' ';
      vword[7] = ' ';
      vword[8] = ' ';
      vword[9] = ' ';
      vword[10] = ' ';
      j = 5;
      while (bulls-- > 0) vword[j++] = '\x65';
      while (cows-- > 0) vword[j++] = '\x64';
      if ((i + 6) < guesses) {
        vword[9] = ' ';
        w = recorded_word[i + 6];
        score = recorded_score[i + 6];
        cows = score % 5;
        bulls = score / 5;
        for (j = 0; j < 4; j++) vword[10 + j] = word[w][j];
        vword[10 + 4] = (char) (i + 6 == highlight ? '<' : ' ');
        vword[10 + 5] = ' ';
        vword[10 + 6] = ' ';
        vword[10 + 7] = ' ';
        vword[10 + 8] = ' ';
        vword[10 + 9] = '\x80';
        vword[10 + 10] = '\0';
        j = 15;
        while (bulls-- > 0) vword[j++] = '\x65';
        while (cows-- > 0) vword[j++] = '\x64';
      } else {
        vword[9] = '\x80'; vword[10] = '\0';
      }
      Print_Str_d (y, -110, vword);     // "HELL \x65\x64\x64\x80"
      y = y - 18;
      i += 1;
      if ((i >= guesses) || (i >= 6)) break;
    }
  // remove hint when too much text on screen and would flicker...
  // Would be nice to fade this out when guesses == 6 ...
  if (guesses < 6)
    Print_Str_d (127 - 6, -110, "WORD  BULL=\x65 COW=\x64\x80");
  // Redraw time only verges on unacceptable when number of guesses is high.
}

#define OK 0
#define NONE 127
#define STATE_GET_HUMANS_GUESS 1
#define STATE_SHOW_COMPUTERS_WORD 2
#define ACTION_HUMAN_QUIT 1
int IO (int STATE) {
  switch (STATE) {
  case STATE_GET_HUMANS_GUESS:
    // Let player enter a word at next slot in ladder.
    // Don't allow any bad characters
    {
      unsigned int i;

      guesses = 0;
      i = 0;
      for (;;) {
        char *humans_guess;
        ShowGuesses (guesses, NONE);
        humans_guess = get_word(-60);
        if (humans_guess) {
          Print_Str_d (-120, -100, "YOUR GUESS: \x80");
          Print_Str_d (-120, 40, humans_guess);
        }
        i += 1;
        if (i == 100) {
          i = 0; guesses += 1;
        }
        if (guesses == 13) guesses -= 1;
      }
    }
    // if the human quits, return ACTION_HUMAN_QUIT
    // however at the moment there is nothing in the GUI that would let them quit.
    return OK;
    break;

  case STATE_SHOW_COMPUTERS_WORD:
    // The human gave up.  Show them what the word was for a few seconds, then return.
    return OK;

  default:
    ;
  }
  return OK;                    // actually, not OK but we'll worry about that later.
}

#define COMPUTER 0
#define HUMAN 1
int main (void) {
  int i = 1;

  for (guesses = 0; guesses < 12; guesses++) {
  recorded_word[guesses] = (unsigned long) guesses *2L;

    recorded_score[guesses] = i;
    i++;
    if (i == 9)
      i = 10;
    if (i == 13)
      i = 20;
  }
  guesses = 12;

#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];
    // INIT!!! (human supplies the word, computer guesses...) 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 (c == '\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;
  }
  // INIT!!!! (computer supplies the word, human guesses...) 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);
#ifdef CLI
retype_humans_guess:
#endif
  guess[4] = '\0';
  for (;;) {
    p = 0;
    bulls = 0;
    cows = 0;
#ifdef CLI
    fprintf (stderr, "%s", prompt[guesses]);
#endif

#ifndef CLI
    if (IO (STATE_GET_HUMANS_GUESS) == ACTION_HUMAN_QUIT) {
      IO (STATE_SHOW_COMPUTERS_WORD);
      goto restart;
    }
#else
    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) {
          fprintf (stderr, "Your guess has to be a word of four letters.  Try again.\n");
          goto retype_humans_guess;
        }
        break;
      } else {
        // silently ignore bad character
#ifdef DEBUG
        fprintf (stderr, "\nbad character '%c'\n", c);
#endif
      }
    }
#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;
}