First, we'll search all the choices for the given row/column, then we check their StringTake[ ... , {3,-3}]
with transpose and return the first item it finds.
I hardcoded the loops (since the structure probably won't change).
ClearAll[solveCrazyEight];
solveCrazyEight[horizontalWords_,verticalWords_]:=Block[{h1Choices,h2Choices,h3Choices,h4Choices,v1Choices,v2Choices,v3Choices,v4Choices},
{h1Choices,h2Choices,h3Choices,h4Choices,v1Choices,v2Choices,v3Choices,v4Choices}=
DictionaryLookup[StringExpression@@Riffle[#,Repeated[_,{4}]],IgnoreCase->True]&/@Catenate@Outer[StringTake,{horizontalWords,verticalWords},{2,-2}];
Do[If[StringTake[{v1,v2,v3,v4},{3,-3}]==(StringJoin/@Transpose@Characters[StringTake[{h1,h2,h3,h4},{3,-3}]]),Return[{h1,h2,h3,h4,v1,v2,v3,v4}]]
,{h1,h1Choices},{h2,h2Choices},{h3,h3Choices},{h4,h4Choices},{v1,v1Choices},{v2,v2Choices},{v3,v3Choices},{v4,v4Choices}]//AbsoluteTiming
]
Example:
The first timing is for the whole operation, second is for finding the right combination:
solveCrazyEight[{"cols", "uned", "phue", "haal"}, {"hoee", "ocon", "apif", "tril"}] // AbsoluteTiming
(* Out: {0.121019, {0.0132017, {"conceals", "unearned", "physique", "habitual",
"honeybee", "occasion", "aperitif", "tranquil" }}} *)
As for the other puzzle, it takes a little more time:
solveCrazyEight[{"leds", "mani", "ints", "vice"}, {"knff", "poes", "stts", "maed"}] // AbsoluteTiming
(* Out: {0.438258, {0.32986, {"leotards", "macaroni", "inkblots", "violence",
"knockoff", "potables", "starlets", "marooned" }}} *)
DictionaryLookup["ho" ~~ Repeated[_, 4] ~~ "ee"]
? $\endgroup$DictionaryLookup["ho"~~___~~"ee" && Length[#] == 8&]
$\endgroup$