Creation doesn't create multiple copies of a word, created a large grid for the puzzle
authorNeil Smith <neil.git@njae.me.uk>
Fri, 16 Jun 2017 07:41:21 +0000 (08:41 +0100)
committerNeil Smith <neil.git@njae.me.uk>
Fri, 16 Jun 2017 07:41:21 +0000 (08:41 +0100)
04-word-search/04-wordsearch.txt [new file with mode: 0644]
04-word-search/huge-unpadded-wordsearch.txt [new file with mode: 0644]
04-word-search/huge-wordsearch-1500.txt [new file with mode: 0644]
04-word-search/huge-wordsearch-old.txt [new file with mode: 0644]
04-word-search/huge-wordsearch.txt [new file with mode: 0644]
04-word-search/wordsearch-creation.ipynb
04-word-search/wordsearch-exploratory-solving.ipynb [new file with mode: 0644]
04-word-search/wordsearch-solution.ipynb [new file with mode: 0644]
04-word-search/wordsearch-solving.ipynb [deleted file]

diff --git a/04-word-search/04-wordsearch.txt b/04-word-search/04-wordsearch.txt
new file mode 100644 (file)
index 0000000..f5a13ab
--- /dev/null
@@ -0,0 +1,2101 @@
+100x100
+smuiclacphysicsihcnebrevilingdroskcabllupcsowygnitnacsipblustedpesnipilafeldrigclenquireddetnawnufly
+eqdbmnutmegsvtzdtelbanimretanmelptseikwagewoodpeckerstirwaszbdrrdypicksnzikylhsiroobsuspectingsexevd
+cgnittacdliwffisuoniallivsegasplraftstyevcsgcdemrofsnartrmlaydzescpopxehsfannysdiscriminationdoeypen
+nnytimavwharfrepjstswashbucklerswklqimkeosulxnopratpsitaoorsrtrjtthnsmxrelabelesrssstribiscutsddvbrs
+eidgkdesivedaiajshegdtgrgniyugyshohaabrmedgpantedsobeysodgmraoozdteosaboundgfjsmbttpygjujedorhdvboeh
+tverediwtczdtlwdeiaryehacrierhsrmccosiantnnbestridikysreepegarotedadrpslaropausesubepnrdissoteiailld
+narddypasjitligihpesubsrwewfgciuuhfsntizsgingivitislublefotkcuhschrmsensitisedeugnveleygbutsiyjcflud
+eernefunuaiindrsilnsethiokutttaeiapgodsteknerdhlngemldlrslhtrhobnobsizsvdlocdtrszbnjnbpieoizwillkarf
+shiensetnhaepslnnaietundowigvidtrptsrsayiewreogudoecniebbyofugamwhmtntwsufaulcdsmlptbeondrancoeersak
+onhpnnktstsdovgsdicvevqeypblohdoaseomtcdrbaatgnrgdnaiaejspdtscrsoratzdntmrgenqnomiroixqgslltmsbfduee
+lasxiiasehcnerdjomoidodedsoayvebrawnufhcrtrtsgiaxgdekmkrtfodkinoirfekkaagvsermuroalabsreraehsuxxnoet
+grderahepeeweeusiutdirnohmaccsmardrztienunpdeehbomeyxruyralgeskucnoveltiesseirfdpyebuttocksntqlaodne
+nrrsglsmxdupsdwrgoielalgmccuikisexoaaltwfniaidcbtgednzcpoeoatsqoszdgratefullytisportingsweepersaapys
+iawlbpsleeyhgorhulnnstulleemntlgtnmttpssostidstienstcbfnnhggcstegsugaringinsighthrsniftersmmfwicdeoi
+ntabemghsstenongideckefombnlrarlxynieuplplsznnendirswunfgsiehsuensdelbafetkzinterposexldsurtimreelhu
+oegleoaeiusdrixklisecdiaiprovesoatllsdsayebsawrasieeterrlaesihztixsllihygrellapractisedatcneeavgggpr
+sdebzczioferrsexdiadatergthrivelpdagearetrfhststsavrbyriymsrecharupocketbooktrotxextuvznwkunlkaqggtb
+ayrewatmerseespumonebatlnoisemorhcdrnadaubistpoeehiouxcpogaesnsuuyratchetswishereatjingsepnfepckaose
+eosafgcffsrrhsawretpadaspitgewuheaiggiivrllcaamkvgntrodtbsidtutpjnrgretemarapecnarussaugaylcfrpantet
+rretarcurneicwgnpellagraupmsixcdswniodknelgnaaetinusmlomsgibehfedtslabprowldenimnushiedrkaqndltillss
+ntoimlleatgbtlrcsxsehsesitengamedinkafgnonnxtladtabmvkifuentblwaaroeegniyartropieseitoobsnolemedtpuu
+ubqfilentigrigafassevissimagingslgiryuoriitoarnsahaseigodniiyelwblmupwthguorbkobmilkiaxhfeedingspptr
+nanyydnerxaewaryrriaemackintoshwftrsbnasnhsukntrksragasketrpcsraarliptereinterpretingieycoudeggiwtnp
+msrgnylmnkraslitloeettosplinesobtihfgnlgtktmrxealwassetpiykusurbvgijzeejgpkxclrtssfdnrtonnaccordshoa
+aihikersaebkawarrtssraodcrgckrpyekbruesuorhnpennaobwgmoversabidgriwcsketchesuesartetsicgswollefdebcs
+zleticilliozaenkfuftsrnvzylogeldilsrrrcrinoautnitrlbroeidribuiwaeireakrstmioieiadxesnnlrolocsidazdms
+srsyamajsmedlkssrdloyeagevapwanespcemorhucilkxamhroouevilamsidvarcemgtqggezgfdeaerosyygnideerbnquoit
+reprobatesdiyruovasbsidboddubehksoehnssseevklieepuoaetlairetsigamtorocevinneedmspwtnpfincisesuhctulc
+smvrnttsdldfysbcontrollablelfsraleaveseuslvpsavsgbtrshalvesylsuougibmaesesimcpgopavhshortensrszzazip
+vebaeioliedpmsuesilangisgynainhcazingsyymqoqueryingdoreopenedhsendlessasolbbsqlrlsnikskcubetbrknifed
+jiklruonsflefilbsnwodwohsnittupnitfstdretsenohlcrcvsmphngnimirgnidaetsemohgbbaamongstljykwucustomers
+doionfghfaalsotejhlrgmewhiieelbbgniretnuasuqsuiouoazeggqrhrisnoituloswselppitueaowymrioutrrbfruitspa
+veydjogonywisiutvosplithsejlhpesseieinveighingqymnlerlbukfpineappleeunkagfieensrealiseadelaarjeevell
+rkertuiegvgcbodleoievtwhtiiyiomravrsetransducersafelaatemptspbjhkrudenifiudktdscalesfratreaopinionql
+tddyoveterinaryoenrnedaebapgowjuiniepsalmistyxadtinnlenvdnakiebrashereatmneirdsnaecomfaeiidedpskfzii
+kfpbgdtacoseizlfsrfgimrblebehopnrideraemsnfhropatdcdriuieyjnilvmschkhkweentaoutsmartedwlooaefiekydmb
+fewestegwhcpuviacpfrenisreesbtgcktshueckfttuzbemteecaswlpggdaypipmrniakrqeasedoberofmrrqltnhphqdefpn
+dyesightingateonspalfngsdqfbxcellistottrnscchhdesshlhefleindegaasmeatewnulcsekytmrgyoaoecoiilanlatao
+hddrafobjectkatrsaehgdeertiprrzyalndegmreioascontrritspanloieinwiumlzwaoaiissziicnetuimidictatorialo
+renemidmuiretcabgsnwrnhegnoigimletslrywdenreftmdiectrsygdmgrssvsealplyrobcllugxxibegusnmqebycrpsguap
+npstekcolsopyhbnsthtschngpsteppeseesoadwcaibraesvsrhiireediprikvrcrlpydniapisenbibanaoicarlyagrflsss
+epksewpfsbkymacinimincislpsvsvyifxrpaotoirdfzmtoreoomharntseseltiuazaeeslrxarebiajdahvalaslprnoarbez
+soeykbongothistlektasssiidsregsleaiarlreogaiweevilggwznttagrwniaiddroasiioemsoinsaepnnavtrnadidllucs
+illoloverwhelmednilnicneegeetcndjasdmduvrchpnnrfzlurdloarnasenilesabemtdtulestkxuiepctesaerrigdekiup
+rpriyewmjoqxltmivbalqnrigdnglcniinfdamavaoitsgrskseaeyipikliserpcrtheoryysabushnolreerilpedknniesohw
+oproponentsmetliekacotroinaoltrenlinnsidutbgrelrucqpgetgemdklciportosipuaegamitgeplpyautgefegoniarcu
+ecaudalyokelrsttynoiifilipiklstsrrtftaenvoyeuristichnludtaqbgsewinngnirabrergentuleaugsnofgdfrgdlibd
+hahconfigurationontntzghhtomrbtoteorfsgyguostsefninyoranpsaqtllumsaqodnbecrbdysseoluetatzxpdwhesieee
+tpalsygrarcdeobivcsrscinapbtmanirsfmeuliuqnartodayebracpnneowyuaplncaninevnegxeduynrargueuieatllgngp
+ixfleshyukesedteemeueruptingtahmlhirugmvrccontrastedhbehugniblpsueiayamsidadinrealahrenyyrrntcwantoy
+fefmyoginsnnearnisieripenessjedsmethelnaabsromalgtentrrxnilrkgmjlemigfieryedopiwvttanwiafhnisrsseeth
+nonhumanvcknnsnteayuemsncupolargiitapthigreideewosireipieirnooaespoanrcbqygkemwlfieefhdwsppehwmubdkw
+bywordswjtosiohmetlestnemegagnedlnstcontyanlaprimessnbmshockerhleydesseheotossealraodauaascpraardpga
+outlastedtaocsbbcrxmgjeenilefileeavgotsiulrfordssgtrsettautnessbdebbadieilppfurvpopwylleemnsiuoelksg
+ddetsyrtemntalngnpwesuccocddyplqppdeisifmrlpimplyntzecggndsuitcaseskarksnflomdtnekrahecsuetsawfpnpcn
+iawaitssbskoedamenelphzijeuhauwpieudrvzvennerraytudtcpasbsencactlocnrcaltifsretaehccsrnempollenagtii
+essertsimdaehrsciagdrphststrcocrnvstesidiayejswheosedmerqhhltviuakacooksussocondoretsaocnofktptdnnls
+ssrettabiesarptgciideyhitaeidodohbvcynenmsncoesiqyvgvrcuaxauclbcearhgiyhladhniblebiluncraakussenioli
+retsimdtluweoolrssfaajxsendnszehoqaxoeesgdtpmoppetsgueeuamoseyumcyganhtlaibeodetoormoisterpejltolial
+sbtrsyhbbdtprleinmtddesrtaetjhpilusrlrtdssoqderunettceirlteslhcsneofisxaenssregnifrettubudnodgasbtha
+sfeergalebiamfsnouieiobattlaebebeicbdweejrruostolgpozsorslslvleiodefdrietvdniqtadjectivesswdrfgeaapr
+widrisitultscrbdccninelelipahgnimeqeisldpjierweqianeubcetoiwsbikcusenerqniiceslaysxrpbmcedunupagnrnt
+fcclimocleiasoaegsgignduearteudtutolkjugambolbnsrvyibvoxrerniipmupfdetezmysaatrcmpeatoaarfetmftaeuqn
+okideokoslbcewnrxnrsospsnsszreeifelatrinemsnxnaeieeetbcsiurvgiesolqsrtcjyrlinaujstelsneqcpatceeyypte
+owdmmeldeargisiraeipeatsenyecsnvfriilatticeworkndlrfesgnihsalpslagfosuunsprlvarnucjotkptardslassgpcc
+tryltdndlgeehysamtuhtlcsoitmpscelcascadinghlsiceasiyrseovexeditsnghfshpaslpuadicsoasislliiumtocsguie
+wynifnpseydscetdsofacyyiledfiqelihslanifbstslewrevevrycvygetxrhipnestsetoahdstaupsetxneascaearjmisvd
+euamraessliuraeicccecnttmstneroynlstodopolansonsadetieeoinoeoeouwiegarrubqyaitovtdeposittdaatnarwael
+apmeitrrussrarrazqaaraiosgypgbgagsgieunuteworpwartrnmcbrfdcoddsihrpnbearlusddlltpoesyrrtjsyljalwtghe
+rpisasmtoutgidqlsuilctnlgnabiopsyngnbilacwsiibgepeiogstutfnheescseiimptaweiecoaegesdeuyuyfeynominees
+aictrsiarorerromgdiipoirfiwgnilratsnibuohortcgnisaefzedrtslrreylcknlooelahckasrvregisdraeslatheriwhr
+yekopuspalirtuneenfmresmonbslartueneiloqebeakoihstlhirruqapaptaaonilculirskrsqtnnsntaarttdetcartsbao
+bsenobsrclcyamnmeiphrpleenufdeniapeptllnsvkvslkyamymceufsrmawussraneonasdaiutdylsasetmaeacanoesroefm
+ruoejoioeatwptmrtkcaarqtgestappinggprodosicahfnmolimiydflecugtudihgvocieiunlerugpshietetniksgipdntmn
+flierrooicsrliacagunfirejpwhimsdphaatngrreucasueufnrmnilisihiduinnlibetdnqgerfoceaodidsdewotwokrgals
+latconnmtfoessepaimedcsatdeducesddshsvvaunfxnsrnvgszkugiettgdldtgrqnhqykgdnawnekrnilseisnoopingisgil
+obmibsssylasirralfpameeviecerggeesemrbegecuebvtstoadspynveaelmhdiresonantgtanaugseitiiruolevtizfreao
+uppgdarnsspegnicieersylbatonarpgfhrsodomychaiserelbmuhvgrtnsstseebedliwmoqlarpobncmpryenrapturetertv
+tvawrdzsponccwtfsrnclennutrcainoaapnbhodepbfrolicsaktziuogrosseforpqfdbrazzesbolaopaneseifidocselgee
+vesjeegvojmooeoeslsthukexwudrarnwanxlkestjacvhscgliatesrohcqsdellennekgiqnslueafsalbtkncttclawsrigrn
+ozpbdbycrenekrsindekyasascetredsdodislbrejlrstgocnobscuredhhabsecurerechaliconsfnciacesixcoupledoanl
+tlmeicsihqmaximaltedynnwsdstssldoemtiebeedmdnbnngvgnippohcaeetsmespodtfmesosdnesjaloperpetuatingbosi
+eegggclassroomssniiralitlpsspsewbidtlelpduyedoicsgumgwfswdnmgfotopaetnrtvlsmovrnsfhfsmpilingcppuiafe
+dahhjnprnhwepecnarpeetixyeeredsrtezeredeldmdepkrnmnpqfgsiucsunneaegsueotisaiecreisueyirknittingsbdbr
+rtyeenickinglfygenlxrdigwsievneetfcevthaeeolnaceoiwispsenmedeielgrwblmncertrntdxsibdpsaostokenismdad
+aeedlafgiuigoarnccgezonchnnlktihttfiasllggalwqitcpcencrpttmteldnnutixisbkiilhgeamyseprzkmrhnmldneild
+tvwkibpeatnhwlozifgiigdugtwoafglrtrwizsnwpaiauleaencrorpoaaekiueoissoaihdszanryognhkaaeccceuyegcehad
+ifaitnmsephymsvstaxfstrqhlowziiirdendhiornplpesyecbeboigarxcrldhtslpgrnahswasitsraiortdemysvtjaindne
+berlyinacaepaeateliyortuetlclofnsirrdrooerleystfdcvlvuytireypiiaidamcyrlessdnoluvyzpcsggsidaimraoect
+unloijrerrrcnssacsetuoaaccbpdymciuakfdpreuegatsopasetznlapsnirnmfkzsztynctrgratoeectsoainarepnrmrbet
+tgibpsridceottensigittnrntnalaesfsnnseysworddcgtlrdedoygstrlrnggisimxaoinoscvrcharsapcngmesiamnmkkdu
+tnkyeuejuuselpscatelhdaaarlegabnaeimriohkinderouaydplerylksleegheueevtteleaeezzaipddpismnmntfgfowcsp
+eietdrimpqankffhpyaietgntwtyrbusesgallivantsdyicelxuydpunerjuyttdysinadlcrovejtloeeitsludgeuijnrcipt
+rbredgyperimusoejsrbayetimikesplkdebrutrepnumnbrklwmbanpserahfosmtdimieiscovsrdrvtyraomissluafioisiu
+nbisluelornaaorsteoastrireitliugselttitndxadgsweiufpreiiadmsbnemilqgcrtrnsiepeclrrapteswovasidfvcgro
+uupceraowdyedtgtstulteoneucertsicitnamoraincoatkubfearedkhayyeutycacyclhwlgrcjoeematrvilvendedaeisin
+trxrmgmsinimefestaniridihueiokfkdedutingamsnoynacqndecayswceagdoarakagcelniesvsndwomagpinupjyrlfdntd
+sgeosdrenblurbscaldahomnnoncncimonoxatkineticrseqorhnarksokurlsqplrreteaiheeeerepwrylykpdtubesuerogi
+qmsaesuohdraugzuiecvemsgigtycnangiopatawdrieroawjsonscallopedsesiwpratstclfddoiastelfaelihbumblersru
+itekrandomisessvrraayrgripestsivitcellocsbawsshapeliestmjgnitontoofhylluftsaobwsocilacidlocatedlrsee
+aberrant
+aberrant
+aboriginals
+abound
+absently
+abstracted
+accidents
+accountability
+accreditation
+achieve
+acidly
+acrostic
+actionable
+activist
+acute
+adapter
+addle
+adjective
+adjourned
+adjudges
+adjurations
+adjuring
+adorns
+adulterating
+aerial
+aerodynamics
+aesthetics
+aflame
+afternoons
+agates
+aggregate
+aggrieving
+agings
+agrarians
+aimed
+airlines
+airmailed
+alderman
+align
+alive
+allergy
+allusive
+along
+aloof
+alternate
+alumni
+amalgamate
+ambiguously
+ambition
+ambles
+amends
+amity
+amongst
+amorously
+ampule
+analgesia
+angular
+anions
+antennae
+antimatter
+antipastos
+antiperspirants
+antiseptic
+antitoxins
+aplenty
+applications
+appropriated
+approximate
+arcade
+archdeacon
+argosy
+aristocrat
+armed
+armful
+around
+ascetic
+aspiring
+asset
+assumed
+assurance
+atelier
+atheist
+atrophies
+attenuation
+attire
+auction
+audacious
+augustest
+automates
+availability
+avenger
+avidly
+awaits
+awarding
+awkwardest
+babbles
+babies
+backhand
+backslide
+backtracked
+bacterium
+bagel
+balanced
+baldest
+balling
+balmy
+balsa
+banister
+banjoes
+banks
+barbed
+barbeques
+bards
+bareback
+barge
+baring
+barley
+barrister
+baselines
+baseness
+basil
+basting
+bathe
+batter
+baulk
+bawling
+beatify
+bedfellows
+beetles
+befogs
+begot
+belches
+belief
+belladonna
+bells
+bemoaned
+bench
+benchmarks
+benefitted
+bereavements
+bereft
+bestrid
+bestride
+betaken
+bethinks
+bewitches
+biased
+biassing
+bicycles
+biennials
+bight
+billowing
+bimbo
+binging
+biopsy
+biotechnology
+birdie
+birthright
+bisexual
+bitingly
+blackguards
+blanched
+blankest
+blasphemes
+bleeder
+blithely
+bloods
+blown
+blundering
+blurb
+blurt
+boards
+boastfully
+boatswain
+bodies
+bodkins
+boilers
+bombardment
+bongo
+bookkeeper
+boorishly
+booties
+bordered
+bossy
+botches
+bothers
+bottles
+bottomless
+boughs
+bowels
+braggers
+brasher
+bravery
+break
+breaststrokes
+breathy
+breech
+breeding
+brier
+brigands
+brink
+brisket
+broncho
+brooms
+brought
+brownest
+bruise
+bucket
+buckskins
+bucolic
+budging
+buggers
+bulks
+bulldozer
+bully
+bumblers
+bunglers
+bungles
+burrows
+bursitis
+busily
+busybodies
+butterfingers
+butternuts
+buttocks
+bywords
+cabals
+cactus
+cadavers
+cadge
+caftan
+caged
+caked
+calcium
+calicos
+callously
+calms
+cameraman
+cancelled
+candidacy
+canine
+canister
+cannot
+canoes
+canyons
+capitalise
+caramel
+caressed
+cargoes
+carousel
+carouser
+cascading
+caster
+castigate
+castigator
+catalogued
+catapult
+catcall
+caudal
+cellist
+certifications
+chaffed
+chainsaws
+chairwomen
+chaise
+chance
+chancels
+chanty
+chapped
+chaps
+charge
+chars
+chastisements
+chauvinism
+cheaper
+cheaters
+cheers
+cheques
+chiefs
+chiffon
+chimaera
+chime
+chirp
+choir
+chopping
+chores
+christen
+chromes
+chronometer
+cistern
+citadels
+civet
+civilises
+clacks
+clamours
+clapped
+clarified
+classier
+classrooms
+claws
+cleanse
+clearinghouse
+clicked
+climaxing
+clincher
+clinging
+clocking
+clocks
+clung
+clutch
+coalesced
+coaster
+coccus
+codding
+codifies
+coevals
+coexisted
+coldest
+collar
+collectivists
+colonialist
+colors
+comatose
+combats
+commandeered
+commas
+commend
+commentator
+complains
+completing
+complimenting
+compromise
+conceal
+concertinaed
+conciliated
+concluding
+concordant
+concourse
+concrete
+condemns
+condor
+confide
+configuration
+confining
+confront
+congaed
+congesting
+congregates
+conjunctive
+connection
+conniver
+conscience
+consortia
+constellation
+constructing
+contaminate
+contested
+contrasted
+controllable
+contumacious
+contuses
+conversions
+convicts
+convinces
+cooper
+copulate
+copyrighted
+cords
+corked
+corms
+corpse
+costars
+costliest
+cotyledon
+coupled
+coupon
+courtships
+coves
+covets
+cowbirds
+crafty
+cranial
+crated
+crater
+crayfishes
+crazy
+credenza
+creeks
+cremate
+crewed
+crier
+crispier
+croak
+croupy
+cruet
+cubic
+culling
+cupola
+curdles
+curdling
+curfews
+curiosity
+curler
+custard
+customers
+cutesiest
+cutoffs
+cycled
+dabbed
+daguerreotype
+daiquiri
+daisy
+dallying
+damming
+damps
+dandies
+dandled
+dangling
+dapperest
+darns
+dazed
+deacon
+deadpanning
+dears
+deathblow
+deaths
+debarks
+debauches
+decamping
+decay
+decentralising
+decoded
+decree
+deduces
+deductibles
+deeming
+defecation
+defender
+deformity
+delayed
+delis
+deludes
+demagnetises
+denotes
+dentures
+denying
+dependence
+dependent
+deploys
+deposit
+deposition
+deputy
+desecrate
+desensitised
+deserted
+despot
+detect
+detox
+deviated
+devised
+devolved
+devotees
+devour
+devours
+dictated
+dictatorial
+differently
+diffusing
+dimensional
+diminuendo
+dinned
+direst
+dirtying
+disable
+disassociating
+disavows
+discolor
+disconnecting
+discontentedly
+discontents
+discrimination
+discursive
+discusses
+disgruntled
+dishonor
+disillusioning
+disinherit
+dismal
+dismay
+disowns
+disparages
+disparaging
+displays
+displease
+disported
+dispossessed
+disprove
+disrobing
+dissimulates
+distrusts
+divesting
+divulged
+divvied
+dogged
+dogies
+dogtrot
+dogwoods
+dominant
+dosed
+dosing
+doted
+douche
+downstage
+dowsed
+draft
+drape
+drawn
+drenches
+driblet
+drifter
+drivel
+drollery
+dross
+drowsy
+duding
+dulls
+dusts
+dynamic
+dynamism
+eager
+eardrum
+earnings
+eastern
+echelons
+editorial
+educates
+effusion
+egalitarians
+egotist
+eighteenths
+electrifies
+electrify
+electrolyte
+elevated
+elides
+elsewhere
+elucidated
+embarrassingly
+embed
+embezzle
+emery
+empty
+enabled
+enabling
+encrusts
+endless
+endow
+enemy
+enervating
+engagement
+engineers
+engorged
+enjoyable
+enlists
+enquired
+enrapture
+entertains
+entreat
+entreaties
+epaulette
+epiglottises
+epitaphs
+epoxies
+equability
+equivocated
+eradicating
+erupting
+escape
+estranged
+evacuates
+evades
+evict
+evidenced
+examiners
+excavations
+exceptionable
+excruciatingly
+excursion
+executing
+executives
+exertions
+exited
+expectorant
+expectorates
+expend
+expense
+expire
+explicated
+exploitative
+expostulates
+expressive
+extemporised
+extincted
+extort
+extraction
+extraditions
+eyetooth
+fabled
+fabricates
+facades
+facet
+facilitate
+facts
+faeces
+fagots
+fainted
+fairies
+faithless
+falsest
+falsifying
+falsity
+fanny
+fasten
+faulted
+faunas
+favored
+fazes
+fealty
+feared
+feedings
+feinting
+feminism
+fettle
+feverishly
+fewest
+fiery
+fiestas
+finals
+finch
+finis
+finked
+firewalls
+firsthand
+fitted
+fixers
+flaps
+flashed
+flashers
+flattery
+fleeced
+fleshy
+flier
+flinching
+flings
+flippest
+floating
+florae
+flour
+fluidly
+fluke
+flummox
+fluxing
+foams
+foamy
+fogeys
+folds
+foolishness
+footnoting
+footwear
+foppish
+forbearing
+fords
+forebodes
+forefront
+foreordained
+fores
+forge
+forgetful
+fouler
+fountainheads
+fractures
+frankfurter
+fraternises
+fraud
+freaky
+freeman
+freestyles
+freighter
+friar
+fried
+friends
+friendship
+fries
+frigid
+frillier
+frills
+frippery
+frolics
+frosty
+frowsy
+frugality
+fruiting
+fruits
+fryer
+fucker
+fuddled
+fulminated
+fumbled
+funnel
+funner
+funniness
+furious
+furriest
+fused
+gabardines
+gadabout
+gages
+galleons
+gallivants
+gambol
+gamete
+gamines
+gaping
+gardens
+garnet
+garoted
+garret
+gashing
+gasket
+gawkiest
+gawkily
+gecko
+genome
+genre
+gentle
+gentled
+geographers
+getup
+gewgaw
+gibber
+gifting
+gimlets
+gimme
+gingersnap
+gingivitis
+girdle
+girds
+gladdened
+glade
+glades
+glamors
+glances
+glider
+glitches
+glues
+glyph
+goals
+goblets
+golfs
+gonna
+gopher
+grace
+graded
+gratefully
+gravestone
+great
+greenish
+greenness
+greyish
+griming
+grimy
+grinder
+grinned
+gripes
+grovels
+growling
+growls
+grubbing
+gruesomer
+grumpier
+guardhouse
+guess
+guild
+guiltier
+gummy
+gunfire
+guying
+gybes
+haggle
+hairdo
+hairstylists
+halfpence
+haloed
+halves
+handbooks
+handcar
+handiest
+handmaiden
+handspring
+hankering
+happen
+harem
+harken
+harming
+hasps
+hatch
+havoc
+headhunter
+headmistress
+headway
+heady
+heaps
+hearsay
+hearses
+heaving
+height
+heliotropes
+hellhole
+helmets
+hereabout
+heroins
+hideouts
+hikers
+hills
+hinterland
+hisses
+hitch
+hitches
+hoarseness
+hobnobs
+hokiest
+holiday
+homegrown
+homesteading
+honester
+honking
+hooks
+hopscotches
+horns
+horseshoeing
+horsetail
+hospital
+hugest
+hugged
+humanity
+humbleness
+humbler
+hunch
+hydroponics
+hying
+hymens
+hyped
+hypersensitivities
+hypertext
+hypos
+iambs
+icing
+identified
+idlers
+ikons
+illicit
+immediacy
+immerses
+immobile
+impalas
+implementing
+imprecations
+impregnable
+impresarios
+impresarios
+impulse
+incises
+incubus
+indigents
+industrialised
+inertia
+infests
+infinitesimally
+informational
+infractions
+infringements
+infusion
+inhere
+inheritance
+inimitable
+input
+inseam
+insight
+insists
+instalment
+institution
+insufficiency
+insulation
+insulted
+intent
+intercede
+intercepts
+interconnect
+interference
+interfering
+interlinking
+intermarries
+interpolated
+interpose
+intones
+inveighing
+invent
+inventors
+inverses
+irons
+irradiates
+irreparably
+irrevocable
+isotropic
+itched
+jabbed
+jaguar
+japans
+jeeps
+jellying
+jewelry
+jibbing
+jibed
+jinnis
+jiving
+jobbing
+jokes
+jolted
+jovially
+joyrode
+junket
+juntas
+juvenile
+keepsakes
+kennelled
+keynotes
+khaki
+khakis
+kilobytes
+kinder
+kindles
+kinetic
+kitty
+kneel
+knifed
+knits
+knitting
+knuckles
+koshered
+kowtowed
+krone
+laborious
+laced
+ladling
+laity
+landmark
+lapidaries
+lather
+latrine
+latticework
+laughingstock
+laughter
+lavisher
+lawfulness
+laymen
+lazes
+lazied
+lazies
+leaflets
+leaves
+lessors
+letter
+levee
+libel
+liefest
+lifeline
+likes
+limbo
+limed
+limestone
+limit
+limping
+liner
+lithography
+liveries
+llanos
+loath
+lobby
+located
+lockets
+loftiest
+lollipops
+longish
+loony
+lotto
+loveliness
+loves
+lurked
+lusted
+lyrical
+mackintosh
+magisterial
+magnitude
+magnolias
+mails
+mainlined
+makeups
+malarial
+mammas
+mandrill
+manifestoes
+marchers
+mares
+markedly
+martinis
+martins
+masques
+masterpieces
+matchbox
+maternally
+mathematically
+matrons
+mausoleum
+maximal
+mayhem
+meadowlark
+mealy
+medias
+mediator
+medicated
+meekly
+mellowest
+melodically
+melon
+mental
+mentioned
+meringues
+merinos
+messiahs
+metacarpus
+metastasis
+meteorological
+methodologies
+metres
+midriffs
+miked
+mikes
+miller
+mills
+mined
+minicam
+minuends
+mirror
+mirth
+misadventure
+mischief
+misgivings
+misinforms
+misread
+missile
+missives
+mister
+mistime
+mitre
+mitten
+mixer
+mocks
+modal
+moiety
+moister
+moisturising
+molasses
+moleskin
+molested
+monarchic
+monetarily
+monopolised
+monthlies
+mooning
+mooted
+moppets
+morbid
+mornings
+morsel
+mortgage
+motels
+mothballing
+motherboard
+motionless
+motorcars
+moused
+mouths
+movable
+movers
+muffling
+mullahs
+multiplexers
+multiplexes
+mummers
+muralists
+musicians
+musings
+mussel
+mussiest
+mutate
+myopia
+nagged
+naively
+nakedly
+nanny
+napalming
+narks
+narrated
+nasal
+nationalising
+naturalised
+nearby
+neglect
+nerds
+nestle
+neutrals
+newsletters
+nicking
+nicotine
+niece
+nightmare
+noddy
+noisily
+nominees
+nonhuman
+nonplused
+nosegays
+notably
+notified
+noughts
+novelties
+nuncio
+nurse
+nurture
+nutmegs
+oasis
+obeyed
+obeys
+object
+obliges
+obscured
+obscures
+obsequiousness
+obsequy
+occupation
+oceans
+octal
+oddest
+okayed
+onomatopoeia
+onsets
+opaques
+operation
+opinion
+oppressor
+orals
+orated
+orations
+oriented
+ornery
+osteopaths
+ostracism
+ouster
+outcomes
+outdistances
+outlasted
+outlaws
+outputted
+outrageously
+outsmarted
+outvoted
+overcrowded
+overlain
+overland
+overnights
+overrules
+overtakes
+overturns
+overwhelmed
+owned
+oxbows
+oxygenates
+oyster
+padded
+paging
+pained
+paled
+pales
+palliate
+palsy
+panic
+panier
+pantaloons
+panted
+parallels
+parameter
+parental
+parked
+parsley
+partner
+passions
+pasting
+patina
+patriarchies
+pauses
+pawned
+pawpaw
+paymasters
+peacock
+pearlier
+peccary
+pecked
+peculiarities
+peddle
+pediments
+pedometer
+peewee
+pelagic
+pellagra
+pencil
+penning
+peppery
+percussionist
+permissions
+perpetuating
+perspiration
+perusals
+petiole
+phallic
+philander
+phoneying
+physicking
+physics
+pianos
+piazza
+piazze
+picks
+piece
+pigskin
+pilaf
+piling
+piloting
+pimply
+pineapple
+pinhole
+pining
+pinned
+pinup
+piton
+pizazz
+placarding
+placket
+plane
+planked
+plaque
+plateful
+players
+plexuses
+plighted
+ploddings
+plopped
+plowman
+plummeting
+plunge
+plusher
+pocketbook
+poesy
+poetical
+poignancy
+point
+poised
+poked
+pokey
+pollen
+poltergeists
+poltroons
+polyp
+poplin
+popularising
+popularity
+pornographers
+portico
+portraying
+postage
+postcard
+potion
+potter
+pounce
+pounding
+practices
+practised
+pragmatic
+prance
+prancer
+prawning
+prearrange
+precautionary
+preceding
+preceptor
+precipice
+preps
+presage
+price
+priests
+primes
+prodding
+professor
+profitably
+prohibitionists
+prohibitively
+promulgating
+pronged
+propane
+propellers
+proper
+properties
+proponents
+proposals
+propulsion
+protestors
+protrusion
+proves
+prowl
+prudery
+psalmist
+pukes
+puking
+pullbacks
+pumice
+pumped
+punchiest
+purebreds
+purulence
+puzzles
+qualifier
+quarantining
+quartette
+quash
+querying
+quieter
+quiets
+quirkier
+quoit
+rabbinate
+raceway
+racism
+radial
+radiant
+rafts
+ragamuffin
+raged
+raiment
+raincoat
+rajahs
+raked
+rambunctiousness
+ramming
+randomises
+rapids
+raptures
+rasps
+ratchet
+ratified
+ravel
+raves
+ravings
+rawer
+razed
+razzes
+reads
+realise
+realising
+rebut
+receive
+recliner
+recompenses
+reconnected
+reconnoiters
+recreation
+rectifications
+recuperate
+redirected
+redistricts
+redoing
+redundant
+reedy
+reefs
+reforests
+refuels
+regale
+regally
+regularly
+rehabbed
+rehearsed
+reigns
+reimbursed
+reindeers
+reinterpreting
+reinvents
+reissues
+reiterates
+relabel
+relates
+remake
+remunerated
+renal
+rending
+rends
+rents
+reoccur
+reopened
+repackage
+repatriate
+repeal
+repealed
+reprobates
+reproduce
+reproducing
+rereads
+resells
+resemble
+resistance
+resolved
+resonant
+retail
+retardants
+retards
+retching
+retreading
+retrieved
+retrievers
+return
+revalues
+revaluing
+reviling
+revised
+reward
+rewires
+rewrote
+rhapsodised
+ricing
+ricksha
+ridiculousness
+rightful
+ripeness
+riskiest
+rivalled
+robbers
+robotics
+rogue
+rolls
+romanticist
+rooted
+rosebuds
+rotting
+roundups
+rouses
+routs
+roving
+royal
+ruffling
+rugby
+rummaging
+runner
+rusks
+rusted
+rustlers
+sabbatical
+saboteurs
+sacerdotal
+sachets
+sacrificed
+sages
+sandhog
+sandiest
+sashes
+satellited
+sauna
+sauntering
+savager
+savories
+savory
+savouries
+savoury
+sawed
+sayings
+scabbiest
+scald
+scale
+scalloped
+scalpel
+scandalised
+scanting
+scants
+scarabs
+scenic
+schlock
+scholar
+scholarship
+scofflaw
+scoops
+scored
+scoring
+scoured
+scowled
+scrappy
+screechy
+scribes
+scrolling
+scuffles
+scull
+scums
+sealant
+seaplane
+seasick
+seaway
+securer
+sedans
+sedately
+sedatest
+seeded
+seers
+selfishness
+selflessness
+semen
+seminars
+sensitised
+sentences
+sentient
+septette
+serest
+serum
+setter
+settling
+severing
+sexed
+shabby
+shacks
+shadier
+shakeup
+shameless
+shanghaiing
+shapeliest
+shark
+sheaf
+shearers
+sheepish
+sheikhs
+shepherd
+shied
+shillelagh
+shirred
+shittiest
+shocker
+shockingly
+shocks
+shoos
+shortens
+shorting
+shovelling
+showdowns
+showiest
+shrew
+shriller
+shuck
+shutters
+sibyl
+sickbed
+sidelights
+sierra
+sighted
+sighting
+signalise
+sillier
+silted
+simmering
+simplification
+singsonged
+sisterhoods
+sketches
+sketchiest
+skews
+skylight
+slashed
+slavish
+slays
+sleepless
+sleepy
+slicking
+sliders
+slink
+slovenlier
+sluttish
+smeared
+smelly
+smirk
+smoked
+smoldered
+smudgier
+snacks
+snaky
+snappiest
+snifters
+snippet
+snivelling
+snobbish
+snooping
+snuff
+soakings
+soaped
+sobbing
+sodomy
+softly
+softness
+sogginess
+solar
+solemnises
+solicitors
+solidifies
+solutions
+songs
+sophists
+sophomoric
+sounded
+southeast
+spacy
+spanning
+speckle
+spines
+spirit
+spitted
+splashing
+splices
+splines
+split
+splits
+splotched
+spoonbill
+sporting
+spotlighted
+sprats
+spreading
+spumone
+squared
+squashed
+squashiest
+squeeze
+squirms
+squirmy
+stabling
+stair
+stalks
+stanchest
+stand
+stank
+starling
+starter
+starved
+stationing
+staunchly
+steeds
+stencilled
+steppes
+stepson
+sterilised
+stiffed
+stiffening
+stigmatising
+stilettos
+stilled
+stoic
+stoniest
+stores
+stout
+straightaway
+straw
+streetcar
+strikeout
+striped
+stripteases
+striving
+stroll
+strongly
+structural
+strumpet
+studies
+studiously
+styes
+styles
+stymie
+subbing
+subcontractors
+subjoining
+sublime
+suborns
+subscribers
+subway
+sudden
+sugaring
+suitcase
+sulfurous
+sumps
+sunnier
+supercharger
+superficial
+suppuration
+surfaced
+surgery
+surgical
+surpass
+surplused
+suspecting
+swabs
+swanked
+swarms
+swashbucklers
+swathes
+sweeper
+sweet
+swirly
+swisher
+switchback
+switcher
+swoon
+swordsmen
+synching
+syringed
+table
+tabled
+tacos
+talkative
+tamales
+tames
+tanager
+tango
+tapping
+taprooms
+tarpon
+tarry
+tarts
+tasted
+taupe
+tautness
+tawdrier
+taxonomic
+taxying
+teapot
+tearoom
+techs
+tedious
+tedium
+teeming
+teepees
+telegraphing
+telephonic
+telexed
+tempest
+tempts
+tenderfeet
+tenured
+terminable
+terrapins
+terrarium
+territorials
+terrorists
+thaws
+theirs
+theorise
+theory
+thickset
+thirsted
+thirsts
+thistle
+thoughtfulness
+thoughtlessness
+threatened
+threshes
+thrive
+thronged
+thronging
+throttles
+throwback
+thrust
+thundered
+thunders
+thymuses
+tiebreaker
+tiled
+tinges
+tinsmiths
+tipplers
+tipples
+tipsiest
+tipsily
+tittles
+toads
+today
+togae
+toggle
+tokenism
+tolling
+toolbar
+topside
+torpedoing
+torso
+tortes
+tortoiseshell
+torus
+totally
+toupees
+towel
+track
+traducing
+tragicomedies
+trample
+tranquil
+tranquilest
+transducers
+transformed
+transited
+transposes
+treadle
+treasonous
+tribe
+trimming
+trivialises
+troika
+trots
+trunking
+trustworthier
+trysted
+trysts
+tubeless
+tubes
+tulip
+tulle
+tumbler
+tuneful
+tunnel
+turbojets
+turnkey
+turtledove
+tusked
+tweak
+tweeted
+twerp
+twigged
+twiggier
+twiggy
+twilight
+twill
+twittered
+tykes
+typed
+typewriter
+tyrannises
+tyrannosaurus
+ukuleles
+unable
+unclasping
+uncles
+uncut
+undaunted
+undemocratic
+undergrowth
+undresses
+unearths
+unfurnished
+universe
+unperturbed
+unplumbed
+unproved
+unreasoning
+unrolling
+unscramble
+unstressed
+unsupervised
+unthinkingly
+unwanted
+uplifts
+uppermost
+uprisings
+upset
+upside
+urbanising
+ushers
+utensils
+uvulas
+vacationer
+valence
+valid
+valise
+valueless
+veils
+velour
+vended
+verbalises
+veterinary
+vexed
+vexes
+vibes
+vibrated
+viburnum
+villager
+villainous
+villas
+virgins
+visas
+visitations
+vitiation
+vogue
+voiced
+volunteers
+voyeuristic
+waddling
+wagers
+wails
+wainscotting
+waistband
+waive
+walkways
+wallpaper
+wanner
+warding
+warlike
+warlocks
+warrantied
+warrants
+washbowls
+waste
+watched
+waterbed
+watering
+waylay
+waywardness
+weaken
+weaker
+wedged
+weedier
+weedy
+weepies
+weevil
+westward
+whaler
+wharf
+whims
+whinnied
+whorehouses
+whose
+wider
+wight
+wildcatting
+wildebeests
+wiling
+windstorms
+wines
+wingtips
+wired
+wises
+wispiest
+wisps
+woman
+wonderfully
+wonderment
+woodpeckers
+woodsy
+woofs
+wordiness
+worldly
+worsening
+worthiest
+wraith
+wrapped
+wrapper
+wrathful
+wreckers
+writs
+wryly
+wryness
+xenon
+yakked
+yogins
+yokel
+youngest
+yuckiest
+yummy
+yuppies
+zebra
+zigzagged
+zings
+zippering
+zither
+zithers
+zoology
+zygotes
\ No newline at end of file
diff --git a/04-word-search/huge-unpadded-wordsearch.txt b/04-word-search/huge-unpadded-wordsearch.txt
new file mode 100644 (file)
index 0000000..46eaaf1
--- /dev/null
@@ -0,0 +1,1250 @@
+100x100
+smuiclacphysics.hcnebrevilingd..skcabllup.s...gnitnacs..blusted.....pilafeldrig..enquireddetnawnu...
+e....nutmegs.t..telbanimret...e..tseikwagewoodpeckerstirwas.b.r...picksn...ylhsiroobsuspectingsexevd
+cgnittacdliw..isuoniallivsegas.lrafts.y.vcs..demrofsnart.mla...e.c....e..fannysdiscrimination.oe..e.
+nnytima.wharfrep.stswashbucklersw....m.eos...noprat....ao.rs....t.h..m.relabele..sss...b.sc.ts..vb.s
+eid..desivedaia.shegdtg.gniyugys.o..a.rme.gpantedsobeysodgm.a....t.osabound...s.bttp...uje.orhd.boe.
+tverediw...dtlw.eiar.ehacrierhsrmccosiant.nbestridi..sreepegarotedadr.slaropauses..e..rdis.oteia.lld
+nardd.p...itli.i.pesu.srwe...ciuuhfsnti.sgingivitislubl.fotkcuhs..rmsensitisedeu...eleygbutsiyjcf.u.
+eerne.u..aiin.r.i.nset.ioku..taeia.gods.e.n..dh.n.emld.r.lht.hobnobsi.s..l.c.trs...jnb.ieoizw.llka.f
+shiense.nhae.s.n.aietun.owig.idtrp.srsayi.w..ogu.oecnie..yo.u...whmt.t..u.a.lcds...tb.ondran.oeersa.
+.nhpnnktsts...g.d.cve.qe.pblohdoaseomtc.r.a.tgnrgdnaiae.spd.sc.sora...nt.r.en.no..ro...g.l..msbfdue.
+.asxiiasehcnerdj.moido.edsoayvebr.w.ufh.rtr.sgiaxgdekm.rtfo.k.noir.....ag.se..ur.al..sreraehsu.xnoet
+gr.erah.peeweeu.i.tdir..h.acc.mard..tie.u.pdeehbo.eyx.u.ralge.kucnoveltiesseirfdp..buttocksn..laodne
+nr.sgls..d..sdwrg.iela...c.uikise.o.altwf.i.idcbtged...poeoatsqo...gratefully..sportingsweepersaa..s
+iaw.bp...e.hgor.ulnnstullee.ntl.t.mttps.os..d.tienstc...nhggcst.gsugaringinsight..snifters.....cde.i
+nta..m..ssteno..i.eckef..b...ar..y.ieu.lpls.n.endirswu..gsiehs..n.delbaf....interpose..dsurt..r.el.u
+oeg..oae.usdr..kl..ecd.aiproveso..llsdsayeb.a.ra.iee.er.l.esih.ti.sllihygrellapractisedatcneea..gg.r
+sdeb.cziofe.r.e.d..da..rgthrive.p.agearetr.hs.stsavr..riy.srec.ar.pocketbooktrotxe.....nw.unlk..gg.b
+a.re.a.m.rs.espumoneb.t..o.semorhc.rnadau.istp.eehio..cpoga.sn.uuyratchetswisher.....n.se..fepc.aos.
+e.saf...fsrrh.a.retpada...t.....e.iggiiv.llcaam.vgnt.o.t.sidtu.pj.r.retemarapecnarussau.a.l.frpante.
+rretarcurne.c.g.pellagra...s...d.wni.dk.elgnaae.inusm..msgibehfedtsl..prowldenimn.shiedrka...l.il.ss
+n..i..leatgbt.rc..s..sesitengamedinkafgnonn.tladta.m....uentbl.aa.oeegniyartrop.eseitoobsnoleme.tpuu
+ub.f.lent.gri.afassevissimagingslgiryuoriit...nsahaseigodniiyelwb..upwthguorb.obmil....hfeedings..tr
+.a.yydne..aew.ryrri.emackintoshw.trsbnasnh.u..trksr.gasketrpc.raar..ptereinterpretingie....deggiwtnp
+.s..nyl...raslitloeett.splinesobtih.gnlgtkt.r.ealwasset....usu.bvgi..eej......rtss.dnrtonnaccords.oa
+.ihikers..bkawa.rtssrao...gc.r.yek..ues..rhn.ennaob.gmovers.bid.riwcsketches.esar.etsi.gswollefdebcs
+.leticilli.zaen..uftsrnv..log..dils.rrc..noau.nitrlbr.eidrib.iwa.irea..st...ieiadxe.n.lrolocsid....s
+sr...m....edl.s...loyeage.ap...e.pc....h..ilk.am.roouevilamsidv.r.e.gt..ge.gfdeaer.s.ygnideerbnquoit
+reprobatesdiyruovasbs.d.oddu..hks..h.s..e..kliee.uoae.lairetsigamt.r..e..nneedmsp.t.p.incisesuhctulc
+s.vr.t.sdld..s.controllablel.s.aleavese..l..s..s.btrshalvesylsuougibma.s.sim.pgo.avhshortensr.zzazip
+.ebae.oliedpmsuesilangisg..a..hc.zingsyy..oqueryingdoreopened..endless...l.bs.lrlsnikskcub.t..knifed
+jiklruons.lefilbsnwodwohsn.ttupnit..tdretsenohl..cvsm...gnimirgnidaetsemoh..baamongst..y.wucustomers
+doionfgh.a.lsotej.....e.h.iee...gniretnuas..s..o.oa.e.g.r...snoitulos.selppitue..w...io.trrbfruits..
+.eydj.g.n..i.iutvosplithsejlhp.s.eieinveighing..mnl.rlbu..pineapple....a.f.e.nsrealiseadel.ar.eevell
+r.ertu.e..gc..dleoi....htiiyi.m.avr..transducers.fe.aatempts.b.....d.n.f.ud.t.scales.r.tr.aopinion.l
+.d.yoveterinaryoenrn..a.bapg.wjuin..psalmist.x...innlenvd...iebrashereat.ne...snaeco..aeiide.ps...ii
+..pb.dtacosei.l.sr.gim.b.eb.ho.nrideraems....opa.dcdri.ie..n.lv.sc.k.kweent.outsmartedwl.oaef.ek..mb
+feweste....p.v.a.p..enisreesbtg..t.h.e.k.tt..bem.eecas.lpggday.ipmrn.akrqeasedoberofmrr.l.nhp..de.pn
+dy.sighting...o.spalfngsd..b.cellistott.nscc.hdesshlhe.leinde.aas.ea.ewnulcsekytmrg.oa..co..la...tao
+.ddr..object...r.aehg.ee..ipr......degmreioascontrrits.an.oieinw.umlzwaoa.iss..i.netu.midictatorialo
+.e.em..muiretcab.sn.rnh.gnoigimletslry.denreftmdie.trsygdm.rssvsealplyrobcll.gx.i.egusnm..b.c.ps..ap
+.pstekcolsopyh..s...schngpsteppes.esoadwcaib.aesvsrhiiree.iprikvrc.l.ydniapisenb.banaoicar.yagr...ss
+ep.sew......macinimin.islp..s....xrpaotoirdf.mto.eoomharntse.elti.a.a.eslrxarebiajdahvalaslprnoarbez
+so.ykbongothistlektass.iidsreg..e.ia.lreogaiweevilgg..n.tagrw.ia.d.r..s.ioemsoinsa.pnnavtr.adidllucs
+il.oloverwhelmednilni.neegee.cnd.as.mduvrch.n.r..lurd.oarnasenilesab..t.tul.stkxuie.ctesae.rigd.....
+rp..y.......l..ivbal.nrigdn.l.ni.n.damava..t.g...seaeyi.ik..se...rtheoryysab.shnolreeril.edknniesohw
+oproponents.etli.kacotr.in.o.t.en.innsidu...relruc.pgetge.d.lciportosi...ega.itgeplpyautge.egon.ar..
+ecaudalyokelrst.ynoiif.l.piklstsrrtf.aenvoyeuristichnludta.b.se.i.ngnirabrer.entuleaugsno.gd.rgdlibd
+h..configurationontnt.g...omr.toteo.fsg.g..stsefni.yora.psa.t.l.msa.....e.rbd.sseol.e.at.x.dwhesieee
+tpalsy.r..c.e..ivcsrscinap.tma.irsfm.uliuqnartoday..racp.neo..u.plncaninev.eg.eduynr.rg.e.ieat.lgngp
+..fleshyuk.s.dteeme.eruptingtah.lhir.gm.r.contrastedhbe.ugni..p.uei.yamsidad.nreal..r.ny.rrntc.antoy
+....yogins..earnis..ripeness.edsmethe.na.bsromalgte.trr.ni..k.m.lemigfieryed..iwvtta.wia.hnis.ss.eth
+nonhuman..knnsnte...e...cupolargiitapt.igreideew.s.re.pie....oaespo.nrcb.y.ke.wlfiee.hdws.p...mu.d..
+bywords...osiohme..estnemegagnedlnstcon.ya...primessn.mshockerhleyd..sehe.t.ssealra.daua.s....ar....
+outlastedt.ocsb.c.x....enilefileeavgotsi.lrfordssgt..ettautnessbdebbadieil.p.ur.po.w.lle......oe.k.g
+ddetsyrte.n..l.gnp.esuccocddypl.ppdeisi..rlpimplyn..ecg..dsuitcases.a.ksnfl.mdtnekrahecs.etsawfpn.cn
+iawaitss.s..e.a.e..lp....euhauwpi.udrv.ve..er.a..udt..as.se...ctlocn.c.ltifsretaehcc.rnempollenag.ii
+essertsimdaehrsci.gdr...tstrcocrn.stesidi..ejs...o.e..erq..lt.i.akaco.ksussocondoretsaocno....tdnnls
+s.rettab.es.rptgc.ide..itaeidodohb.cynen.sn.o....y..vrcua..uclb.earhgiyhla.hn..lebil..c..ak..senioli
+retsim.tlu.eoo.rssfaa.xsendns.ehoqa.oeesgdtpmoppets.ueeu.moseyu.cygan.tlaib..detoormoisterpe.l.olial
+......hbbdtpr..inmt.desrtaetjhpilu.rlrtdsso.derunettceirltesl.csneofis.aenssregnifrettub...od.asbtha
+sfeergalebia.f.noui.iobattlae.ebei.bdwe..r..os...gpoz.orslsl.le.odefdr..tvdn...adjectivess.dr.geaapr
+....isitultscrbdccn.n.lelipa.gnime..is.dp....we..ane.b..toi..bikc.sener..ii.eslays.rp..c.du..pagnr.t
+f..limocleiasoaegsgignduear..udtut.l...gambol.nsrv.ib.o.re.ni..mupfdete..ysa.t....ea.oa..fetm.taeu.n
+o.ideokoslb.ewnr.nrso.psnss.reeifelatrinems....ei..etb.s..rvg...ol..rtc.y.lin.u..t.lsne.cp.tceeyypte
+owd.mel.ear.isir.eipeatsenye.snvfr..latticeworkndlrfesgnihsalpslagf.suunsprlv...u..otk.tardslassgpcc
+t.yltd.dl.e.hysam.uhtl.so.tm.scelcascadinghl..c.asiyrse.vexed.tsng.fshpaslpua..c.oasislliiumtocsguie
+wynifnpseydscetdso.acyyi.e..i.elihslanifbstsle.r.vevrycv.....rhi.ne.tsetoahdstaupset..eascae.rj.isvd
+euamrae.sliuraeicccecnttmstner.yn.st....olansonsade.ieeoi...oeo..i.ga.rubqyaito..deposittdaat.a.wael
+apmeitr.ussrarra..aaraiosgy...g.g.gie...tewor.wart.n.cbrfd.odds.hrpnb.ar.usddlltpoesyrr.js.l...wt.he
+rpisasmtoutgid.l..ilctnl.nabiopsy.gnbi..cwsii.gepei.g..u.fn.ee.cseiimptaweiecoae..s.euyu...ynominees
+.ictrsiarorerr..gdiipoi.fiwgnilratsnibu.hortcgn.saef.e.rtslrre.lcknlooelahcka.rvre.isdraeslather...r
+yekopuspalirtu.eenf.re.m.nbslartueneiloqebeakoihstlhi.ru...ap.aaonilculirskrs..nnsntaarttdetcartsbao
+.s.n.bsrclcyamnmei.h.pl..nu.deniapeptllns.kvslky.mymce.fs.mawussrane.nasdaiut.ylsasetmae.canoes.oe.m
+...e.oio.at.ptmrt.c..r...estappinggp.odos.cahfnm..imi.dfl.c.gtudihgv.cieiunlerugpshietetniksgipdnt..
+flierroo.cs.liac.gunfire.pwhimsd..aa..grr.ucasue...rmn.lis.hidu.n..i.etdnqgerfoceaodidsdewotwokrgals
+latconnm.f.e..epaimedc...deducesddshs..aunfx..rn....kugie.tgdl..g..n..y.g.nawn.krnilse.snoopingisgil
+obmibsss..asir..l..a.eeviecerggee.em....ecue..tstoadspynveael....resonantgtan.ugseiti.ruolev...freao
+u..gdarnsspegniciee.sylbatonarpgfhrsodomychaiserelbmuh.grtnsstseebedliw.o.la.p..ncmpr.enrapturetertv
+t...rd...oncc.t.srnclennut.cainoaap...od..bfrolics.k....o.rosseforp...brazzesb.laopa.eseifidoc.elgee
+v...ee..o..ooe.eslsth.ke...drarnwan.l.es..a...sc.liatesrohc.sdellennekgi..s.u.af.albtkn...clawsrigrn
+o..bdbyc....krsindekyasa..etredsdodi.l.re.l..tgo.nobscuredhh..securere..al.c.nsfn.iace.i.coupledoanl
+t.mei.si..maximaltedynn.sdstss.doem.iebe.dm.n.nng.gnippohca....m....dt..eso.dnes.a.operpetuatingbo.i
+eegggclassroomss...ral.t.pssp.ewbidtlelpd.yedoic.g.....s.dnm..otopaetn.t.lsmov..sfh.s.piling....i..e
+dahh.n...h..pecnarpeeti.yeeredsrte.ere.e..mdepkrn.np....iucsun..ae...eotisaie..eis.ey.rknittings..br
+rt.eenickinglfy...l.rdig..ie.neet.cev.ha.eo.naceo.wispsenme.eie.gr..lmncertrntdxs.bdpsao.tokenismda.
+...dla.g..i.oar.cc.e.onchnn.ktihttfi.s.lgg.lwqitcp.en.rpttmt.ldnn.ti.i.bkii.hgeamyseprzk.r..mld.e.l.
+.vwkibp.a.n.wlo.ifg..g.ugtw.afglrtr.i..nwpa.auleae.crorpoaaek.ueo.ssoai.ds.a.ryognhkaaec..euye.ce.ad
+..ai.nmseph.msvsta..st.qh.ow.iiirden..iornp.pes.ec.eboigarxcrld.tslp.r.ahsw.sitsra.ortde..svt.a.ndne
+b.rl.inacae.aeatel.yortuetl.l.fn.irr.rooe..e.s..dcv.vuytireypii.i.a.c.rlessdnoluvy.pcsggsidaim.aoect
+u.loi.rerrr.nssacs.tuoaac.bp.y..iuakfdpr..egatsopasetznlapsni.nmf.zs.tynctrgrato..c.so.in.repnr.rbet
+tgibps.idceott.nsi.ittnrntnalaesfsnnseysword.c..lrdedoygst.lrnggisi.xaoinoscvrcharsa.cngmesiamn.kkdu
+tnkye.e.uusel..cat.lh.aaa.legabnaei.r...kinderou.y.pler.lksleeg.e.eevtteleaeezzaipddpis.nmntfgfo.csp
+eietd..mpqankffh.yaie.gnt.....use.gallivants..ic.l.uydpuner.uyttdysinadlcrove....ee.tslu.geuijnrcipt
+rbred..peri.usoe.srbayetimikespl.debrutrepnu.n.rkl.mb.npsera.fosm.dimieiscovsrd.vtyr.om...l..fioisiu
+nbisl.e.or.a..rs.eoastrireitliugselttit.....g..e.u.pr..iadmsbnemil.gcrt..siepeclrrapteswovasidfvcgro
+uupcer.o..y.d.gtstulte.ne...rtsicitnamoraincoatk.bfearedkhayyeutycacyc.hwlgrc.oeematr...vended.ei.i.
+trxrm.msinimefe.tani.i.ih..i.....edutingamsnoynac..decay..ceagd.ara.a.celnie.vsndwo...pinup...l.dntd
+sgeosdrenblurbscalda.o.nn.n..cimonoxatkinetic..e....narks.k.rl..pl.r.teaihe.eer.pwryly...tubes.e..g.
+..saesuohdraug..ie.v.m.gig.ycnangiop.tawdrier..w....scallopedsesiwp.atstcl.ddo.astelfael..bumblers..
+.t.krandomises..rr.a..gripestsivitcellocsbawsshapeliest..gnitontoofhylluftsaobwsocilac..located..s..
+abound
+abstracted
+accidents
+activist
+acute
+adapter
+addle
+adjective
+adjudges
+adjurations
+adjuring
+adorns
+afternoons
+agates
+aggregate
+agings
+agrarians
+aimed
+airlines
+align
+alive
+allergy
+allusive
+along
+alumni
+ambiguously
+amends
+amity
+amongst
+ampule
+antennae
+antimatter
+antitoxins
+aplenty
+arcade
+aristocrat
+armed
+armful
+around
+ascetic
+aspiring
+asset
+assumed
+assurance
+atelier
+attire
+availability
+avenger
+avidly
+awaits
+awkwardest
+backhand
+backslide
+bacterium
+bagel
+balanced
+baldest
+balmy
+balsa
+banister
+banks
+barbed
+bards
+barge
+baring
+barley
+baselines
+basil
+bathe
+batter
+baulk
+beatify
+bedfellows
+beetles
+begot
+belches
+bells
+bench
+bereft
+bestrid
+biased
+biassing
+bight
+bimbo
+binging
+biopsy
+birdie
+blanched
+bleeder
+blown
+blurb
+blurt
+boards
+boastfully
+bodies
+boilers
+bongo
+boorishly
+booties
+bossy
+botches
+boughs
+bowels
+braggers
+brasher
+bravery
+break
+breathy
+breeding
+brier
+brigands
+brink
+brisket
+brooms
+brought
+bruise
+bucket
+buckskins
+bucolic
+budging
+bully
+bumblers
+bunglers
+burrows
+butterfingers
+butternuts
+buttocks
+bywords
+cabals
+cactus
+cadge
+caged
+caked
+calcium
+calicos
+callously
+cancelled
+canine
+cannot
+canoes
+canyons
+caramel
+caressed
+cargoes
+carousel
+carouser
+cascading
+caster
+castigator
+catapult
+caudal
+cellist
+chaffed
+chaise
+chance
+chanty
+chapped
+chaps
+chars
+cheaters
+cheers
+cheques
+chiefs
+chiffon
+chirp
+chopping
+chores
+christen
+chromes
+chronometer
+cistern
+citadels
+civilises
+classrooms
+claws
+cleanse
+clutch
+coaster
+coccus
+codifies
+coevals
+collar
+collectivists
+comatose
+combats
+commas
+complains
+conceal
+concluding
+concordant
+concrete
+condor
+confide
+configuration
+congaed
+connection
+conniver
+conscience
+contrasted
+controllable
+contuses
+conversions
+convinces
+copulate
+cords
+corms
+costars
+costliest
+cotyledon
+coupled
+coupon
+crater
+crazy
+creeks
+cremate
+crier
+crispier
+croak
+cruet
+cubic
+culling
+cupola
+curdling
+curiosity
+curler
+customers
+cycled
+dabbed
+daiquiri
+daisy
+damming
+damps
+dandled
+dapperest
+darns
+deacon
+dears
+deathblow
+debarks
+decamping
+decay
+decentralising
+decree
+deduces
+delis
+demagnetises
+denotes
+dentures
+dependence
+dependent
+deposit
+deputy
+deserted
+detox
+devised
+devolved
+devotees
+dictatorial
+dinned
+disable
+disavows
+discolor
+discrimination
+dismal
+dismay
+disparaging
+distrusts
+divesting
+divvied
+dogged
+dogies
+dogtrot
+dogwoods
+dominant
+dosed
+doted
+draft
+drenches
+drifter
+drivel
+drollery
+dross
+drowsy
+duding
+dulls
+dusts
+dynamic
+eager
+eardrum
+eastern
+echelons
+electrify
+elides
+elucidated
+embed
+emery
+empty
+enabling
+encrusts
+endless
+endow
+engagement
+engorged
+enquired
+enrapture
+epoxies
+equability
+erupting
+escape
+estranged
+evades
+evict
+evidenced
+excavations
+exited
+expectorates
+expend
+expire
+explicated
+extort
+extraditions
+fabled
+fabricates
+facades
+facilitate
+facts
+faeces
+fagots
+falsest
+falsity
+fanny
+faunas
+fazes
+fealty
+feared
+feedings
+feminism
+feverishly
+fewest
+fiery
+finals
+finis
+fixers
+flaps
+flashed
+flashers
+fleeced
+fleshy
+flier
+flinching
+florae
+fluke
+foams
+foamy
+folds
+footnoting
+footwear
+fords
+forebodes
+fores
+forge
+fouler
+fraud
+freaky
+friar
+fried
+fries
+frigid
+frolics
+frosty
+frowsy
+fruits
+fryer
+fucker
+fuddled
+funnel
+funner
+furriest
+fused
+gages
+gallivants
+gambol
+gaping
+garoted
+garret
+gasket
+gawkiest
+gawkily
+gecko
+genre
+gentle
+gewgaw
+gibber
+gifting
+gimlets
+gimme
+gingersnap
+gingivitis
+girdle
+gladdened
+glade
+glamors
+glances
+glider
+glues
+glyph
+goals
+goblets
+golfs
+gonna
+grace
+graded
+gratefully
+greenish
+greyish
+griming
+grimy
+grinder
+grinned
+gripes
+grovels
+growling
+growls
+grubbing
+gruesomer
+guardhouse
+guess
+guild
+guiltier
+gummy
+gunfire
+guying
+gybes
+hairdo
+halves
+handspring
+hankering
+happen
+harken
+hasps
+hatch
+havoc
+headmistress
+heady
+heaps
+hearses
+heaving
+height
+hikers
+hills
+hisses
+hitch
+hobnobs
+hokiest
+homesteading
+honester
+hooks
+horsetail
+hugged
+humbler
+hunch
+hymens
+hyped
+hypersensitivities
+hypos
+iambs
+icing
+idlers
+ikons
+illicit
+immediacy
+impalas
+impulse
+incises
+inertia
+infests
+infringements
+inhere
+inheritance
+input
+insight
+insists
+instalment
+insulted
+intent
+interference
+interpolated
+interpose
+intones
+inveighing
+invent
+inverses
+irradiates
+isotropic
+jabbed
+jaguar
+japans
+jeeps
+jellying
+jewelry
+jibbing
+jibed
+jiving
+jobbing
+jokes
+jolted
+joyrode
+keepsakes
+kennelled
+keynotes
+khaki
+kilobytes
+kinder
+kindles
+kinetic
+kitty
+kneel
+knifed
+knitting
+kowtowed
+krone
+laced
+laity
+landmark
+lather
+latrine
+latticework
+laughter
+lawfulness
+laymen
+lazes
+lazied
+lazies
+leaflets
+leaves
+lessors
+letter
+levee
+libel
+liefest
+lifeline
+likes
+limbo
+limed
+limestone
+limit
+liner
+lithography
+lobby
+located
+lockets
+lollipops
+longish
+lotto
+loves
+lurked
+lusted
+lyrical
+mackintosh
+magisterial
+magnitude
+mails
+mammas
+mares
+martinis
+martins
+matchbox
+maximal
+mealy
+medias
+meekly
+mellowest
+melon
+merinos
+messiahs
+methodologies
+mikes
+miller
+mills
+mined
+minicam
+mirror
+mirth
+misadventure
+misgivings
+misread
+missile
+missives
+mister
+mitre
+mitten
+mixer
+modal
+moiety
+moister
+moleskin
+monetarily
+mooted
+moppets
+morbid
+mornings
+morsel
+motels
+motorcars
+mouths
+movers
+muffling
+musings
+mutate
+myopia
+nagged
+naively
+nanny
+napalming
+narks
+narrated
+nasal
+nationalising
+naturalised
+nearby
+nerds
+neutrals
+nicking
+nicotine
+noisily
+nominees
+nonhuman
+nosegays
+notably
+notified
+noughts
+novelties
+nurse
+nurture
+nutmegs
+oasis
+obeyed
+obeys
+object
+obscured
+oceans
+octal
+oddest
+okayed
+opaques
+opinion
+orals
+orated
+oriented
+ornery
+outlasted
+outputted
+outsmarted
+outvoted
+overlain
+overturns
+overwhelmed
+owned
+oxbows
+oyster
+padded
+paging
+pained
+pales
+palliate
+palsy
+panic
+panier
+panted
+parameter
+parental
+parked
+parsley
+partner
+patriarchies
+pauses
+pawned
+pawpaw
+peacock
+peccary
+peddle
+pedometer
+peewee
+pellagra
+pencil
+penning
+permissions
+perpetuating
+perusals
+phallic
+physicking
+physics
+piazze
+picks
+piece
+pigskin
+pilaf
+piling
+pimply
+pineapple
+pinhole
+pining
+pinup
+pizazz
+placarding
+placket
+plane
+planked
+plaque
+plateful
+plighted
+plopped
+plowman
+plunge
+pocketbook
+poesy
+poetical
+poignancy
+point
+poised
+poked
+pokey
+pollen
+poltroons
+polyp
+poplin
+portico
+portraying
+postage
+potter
+pounce
+practices
+practised
+pragmatic
+prance
+prawning
+prearrange
+precautionary
+presage
+price
+primes
+prodding
+professor
+prohibitively
+propane
+proper
+proponents
+proposals
+proves
+prowl
+psalmist
+pukes
+puking
+pullbacks
+pumice
+pumped
+quarantining
+quash
+querying
+quieter
+quiets
+quoit
+rabbinate
+raceway
+radial
+radiant
+rafts
+ragamuffin
+raged
+raiment
+raincoat
+raked
+ramming
+randomises
+raptures
+rasps
+ratchet
+ratified
+raves
+razed
+razzes
+reads
+realise
+realising
+rebut
+receive
+rectifications
+recuperate
+redistricts
+redoing
+reedy
+reefs
+regale
+regularly
+reigns
+reindeers
+reinterpreting
+relabel
+relates
+remunerated
+renal
+rending
+rends
+rents
+reopened
+repeal
+reprobates
+resells
+resemble
+resonant
+retail
+retards
+retching
+retreading
+retrieved
+return
+revaluing
+reviling
+rewires
+rewrote
+rhapsodised
+ricksha
+ripeness
+rivalled
+robbers
+rogue
+rolls
+romanticist
+rooted
+rouses
+roving
+ruffling
+rugby
+runner
+rusks
+rustlers
+saboteurs
+sachets
+sages
+sandhog
+sandiest
+sauna
+sauntering
+savager
+savories
+savory
+savoury
+sayings
+scald
+scale
+scalloped
+scalpel
+scanting
+scants
+scofflaw
+scoops
+scored
+scoring
+scowled
+scrappy
+scribes
+scrolling
+scuffles
+scull
+scums
+sealant
+seaway
+securer
+sedans
+seers
+selflessness
+semen
+seminars
+sensitised
+sentences
+septette
+serest
+setter
+severing
+sexed
+shadier
+shakeup
+shameless
+shanghaiing
+shapeliest
+shark
+sheaf
+shearers
+sheikhs
+shied
+shirred
+shittiest
+shocker
+shocks
+shortens
+showdowns
+shrew
+shuck
+shutters
+sickbed
+sierra
+sighting
+signalise
+sillier
+silted
+simmering
+sketches
+sketchiest
+skews
+skylight
+slays
+sleepy
+slicking
+slink
+slovenlier
+smeared
+smelly
+smirk
+smoked
+snaky
+snappiest
+snifters
+snivelling
+snobbish
+snooping
+soaped
+sobbing
+sodomy
+softly
+solar
+solutions
+songs
+sophists
+sounded
+southeast
+spacy
+spanning
+speckle
+spirit
+spitted
+splashing
+splines
+split
+spoonbill
+sporting
+spreading
+spumone
+squeeze
+squirms
+stair
+stalks
+stanchest
+stand
+stank
+starling
+stationing
+steeds
+steppes
+stiffed
+stilettos
+stoniest
+stores
+stout
+straw
+striped
+striving
+stroll
+strongly
+strumpet
+styes
+styles
+subbing
+subjoining
+sublime
+suborns
+subway
+sudden
+sugaring
+suitcase
+suppuration
+surgery
+surpass
+suspecting
+swabs
+swarms
+swashbucklers
+swathes
+sweeper
+sweet
+swisher
+switcher
+swoon
+swordsmen
+table
+tacos
+talkative
+tames
+tanager
+tango
+tapping
+taprooms
+tarpon
+tarry
+tarts
+taupe
+tautness
+tawdrier
+taxonomic
+taxying
+teapot
+tearoom
+tedium
+teeming
+telephonic
+telexed
+tempts
+tenured
+terminable
+terrarium
+thaws
+theirs
+theorise
+theory
+thickset
+thistle
+thrive
+thronged
+thronging
+throttles
+throwback
+thundered
+tiled
+tinges
+tinsmiths
+tipplers
+tipples
+tipsiest
+tittles
+toads
+today
+togae
+toggle
+tokenism
+toolbar
+torso
+torus
+totally
+toupees
+track
+traducing
+tranquil
+transducers
+transformed
+tribe
+trunking
+trysted
+trysts
+tubes
+tulip
+tulle
+tunnel
+tusked
+tweak
+twerp
+twigged
+twiggy
+twilight
+twill
+tykes
+typed
+unable
+uncut
+undaunted
+undresses
+unfurnished
+universe
+unperturbed
+unproved
+unreasoning
+unrolling
+unscramble
+unthinkingly
+unwanted
+uplifts
+uppermost
+uprisings
+upset
+utensils
+uvulas
+valence
+valid
+valise
+veils
+velour
+vended
+veterinary
+vexed
+vexes
+vibes
+viburnum
+villager
+villainous
+villas
+visitations
+vitiation
+vogue
+voyeuristic
+waddling
+wagers
+waive
+warding
+warlike
+waste
+waterbed
+waylay
+weaken
+weaker
+weedier
+weedy
+weevil
+whaler
+wharf
+whims
+whose
+wider
+wight
+wildcatting
+wildebeests
+wiling
+wines
+wired
+wises
+wispiest
+wisps
+wonderfully
+woodpeckers
+wordiness
+wrapped
+writs
+wryly
+xenon
+yogins
+yokel
+youngest
+yummy
+yuppies
+zebra
+zings
+zygotes
\ No newline at end of file
diff --git a/04-word-search/huge-wordsearch-1500.txt b/04-word-search/huge-wordsearch-1500.txt
new file mode 100644 (file)
index 0000000..3f93e59
--- /dev/null
@@ -0,0 +1,1601 @@
+100x100
+smuiclacphysicsihcnebrevilingdroskcabllupcsowygnitnacsipblustedpesnipilafeldrigclenquireddetnawnufly
+eqdbmnutmegsvtzdtelbanimretanmelptseikwagewoodpeckerstirwaszbdrrdypicksnzikylhsiroobsuspectingsexevd
+cgnittacdliwffisuoniallivsegasplraftstyevcsgcdemrofsnartrmlaydzescpopxehsfannysdiscriminationdoeypen
+nnytimavwharfrepjstswashbucklerswklqimkeosulxnopratpsitaoorsrtrjtthnsmxrelabelesrssstribiscutsddvbrs
+eidgkdesivedaiajshegdtgrgniyugyshohaabrmedgpantedsobeysodgmraoozdteosaboundgfjsmbttpygjujedorhdvboeh
+tverediwtczdtlwdeiaryehacrierhsrmccosiantnnbestridikysreepegarotedadrpslaropausesubepnrdissoteiailld
+narddypasjitligihpesubsrwewfgciuuhfsntizsgingivitislublefotkcuhschrmsensitisedeugnveleygbutsiyjcflud
+eernefunuaiindrsilnsethiokutttaeiapgodsteknerdhlngemldlrslhtrhobnobsizsvdlocdtrszbnjnbpieoizwillkarf
+shiensetnhaepslnnaietundowigvidtrptsrsayiewreogudoecniebbyofugamwhmtntwsufaulcdsmlptbeondrancoeersak
+onhpnnktstsdovgsdicvevqeypblohdoaseomtcdrbaatgnrgdnaiaejspdtscrsoratzdntmrgenqnomiroixqgslltmsbfduee
+lasxiiasehcnerdjomoidodedsoayvebrawnufhcrtrtsgiaxgdekmkrtfodkinoirfekkaagvsermuroalabsreraehsuxxnoet
+grderahepeeweeusiutdirnohmaccsmardrztienunpdeehbomeyxruyralgeskucnoveltiesseirfdpyebuttocksntqlaodne
+nrrsglsmxdupsdwrgoielalgmccuikisexoaaltwfniaidcbtgednzcpoeoatsqoszdgratefullytisportingsweepersaapys
+iawlbpsleeyhgorhulnnstulleemntlgtnmttpssostidstienstcbfnnhggcstegsugaringinsighthrsniftersmmfwicdeoi
+ntabemghsstenongideckefombnlrarlxynieuplplsznnendirswunfgsiehsuensdelbafetkzinterposexldsurtimreelhu
+oegleoaeiusdrixklisecdiaiprovesoatllsdsayebsawrasieeterrlaesihztixsllihygrellapractisedatcneeavgggpr
+sdebzczioferrsexdiadatergthrivelpdagearetrfhststsavrbyriymsrecharupocketbooktrotxextuvznwkunlkaqggtb
+ayrewatmerseespumonebatlnoisemorhcdrnadaubistpoeehiouxcpogaesnsuuyratchetswishereatjingsepnfepckaose
+eosafgcffsrrhsawretpadaspitgewuheaiggiivrllcaamkvgntrodtbsidtutpjnrgretemarapecnarussaugaylcfrpantet
+rretarcurneicwgnpellagraupmsixcdswniodknelgnaaetinusmlomsgibehfedtslabprowldenimnushiedrkaqndltillss
+ntoimlleatgbtlrcsxsehsesitengamedinkafgnonnxtladtabmvkifuentblwaaroeegniyartropieseitoobsnolemedtpuu
+ubqfilentigrigafassevissimagingslgiryuoriitoarnsahaseigodniiyelwblmupwthguorbkobmilkiaxhfeedingspptr
+nanyydnerxaewaryrriaemackintoshwftrsbnasnhsukntrksragasketrpcsraarliptereinterpretingieycoudeggiwtnp
+msrgnylmnkraslitloeettosplinesobtihfgnlgtktmrxealwassetpiykusurbvgijzeejgpkxclrtssfdnrtonnaccordshoa
+aihikersaebkawarrtssraodcrgckrpyekbruesuorhnpennaobwgmoversabidgriwcsketchesuesartetsicgswollefdebcs
+zleticilliozaenkfuftsrnvzylogeldilsrrrcrinoautnitrlbroeidribuiwaeireakrstmioieiadxesnnlrolocsidazdms
+srsyamajsmedlkssrdloyeagevapwanespcemorhucilkxamhroouevilamsidvarcemgtqggezgfdeaerosyygnideerbnquoit
+reprobatesdiyruovasbsidboddubehksoehnssseevklieepuoaetlairetsigamtorocevinneedmspwtnpfincisesuhctulc
+smvrnttsdldfysbcontrollablelfsraleaveseuslvpsavsgbtrshalvesylsuougibmaesesimcpgopavhshortensrszzazip
+vebaeioliedpmsuesilangisgynainhcazingsyymqoqueryingdoreopenedhsendlessasolbbsqlrlsnikskcubetbrknifed
+jiklruonsflefilbsnwodwohsnittupnitfstdretsenohlcrcvsmphngnimirgnidaetsemohgbbaamongstljykwucustomers
+doionfghfaalsotejhlrgmewhiieelbbgniretnuasuqsuiouoazeggqrhrisnoituloswselppitueaowymrioutrrbfruitspa
+veydjogonywisiutvosplithsejlhpesseieinveighingqymnlerlbukfpineappleeunkagfieensrealiseadelaarjeevell
+rkertuiegvgcbodleoievtwhtiiyiomravrsetransducersafelaatemptspbjhkrudenifiudktdscalesfratreaopinionql
+tddyoveterinaryoenrnedaebapgowjuiniepsalmistyxadtinnlenvdnakiebrashereatmneirdsnaecomfaeiidedpskfzii
+kfpbgdtacoseizlfsrfgimrblebehopnrideraemsnfhropatdcdriuieyjnilvmschkhkweentaoutsmartedwlooaefiekydmb
+fewestegwhcpuviacpfrenisreesbtgcktshueckfttuzbemteecaswlpggdaypipmrniakrqeasedoberofmrrqltnhphqdefpn
+dyesightingateonspalfngsdqfbxcellistottrnscchhdesshlhefleindegaasmeatewnulcsekytmrgyoaoecoiilanlatao
+hddrafobjectkatrsaehgdeertiprrzyalndegmreioascontrritspanloieinwiumlzwaoaiissziicnetuimidictatorialo
+renemidmuiretcabgsnwrnhegnoigimletslrywdenreftmdiectrsygdmgrssvsealplyrobcllugxxibegusnmqebycrpsguap
+npstekcolsopyhbnsthtschngpsteppeseesoadwcaibraesvsrhiireediprikvrcrlpydniapisenbibanaoicarlyagrflsss
+epksewpfsbkymacinimincislpsvsvyifxrpaotoirdfzmtoreoomharntseseltiuazaeeslrxarebiajdahvalaslprnoarbez
+soeykbongothistlektasssiidsregsleaiarlreogaiweevilggwznttagrwniaiddroasiioemsoinsaepnnavtrnadidllucs
+illoloverwhelmednilnicneegeetcndjasdmduvrchpnnrfzlurdloarnasenilesabemtdtulestkxuiepctesaerrigdekiup
+rpriyewmjoqxltmivbalqnrigdnglcniinfdamavaoitsgrskseaeyipikliserpcrtheoryysabushnolreerilpedknniesohw
+oproponentsmetliekacotroinaoltrenlinnsidutbgrelrucqpgetgemdklciportosipuaegamitgeplpyautgefegoniarcu
+ecaudalyokelrsttynoiifilipiklstsrrtftaenvoyeuristichnludtaqbgsewinngnirabrergentuleaugsnofgdfrgdlibd
+hahconfigurationontntzghhtomrbtoteorfsgyguostsefninyoranpsaqtllumsaqodnbecrbdysseoluetatzxpdwhesieee
+tpalsygrarcdeobivcsrscinapbtmanirsfmeuliuqnartodayebracpnneowyuaplncaninevnegxeduynrargueuieatllgngp
+ixfleshyukesedteemeueruptingtahmlhirugmvrccontrastedhbehugniblpsueiayamsidadinrealahrenyyrrntcwantoy
+fefmyoginsnnearnisieripenessjedsmethelnaabsromalgtentrrxnilrkgmjlemigfieryedopiwvttanwiafhnisrsseeth
+nonhumanvcknnsnteayuemsncupolargiitapthigreideewosireipieirnooaespoanrcbqygkemwlfieefhdwsppehwmubdkw
+bywordswjtosiohmetlestnemegagnedlnstcontyanlaprimessnbmshockerhleydesseheotossealraodauaascpraardpga
+outlastedtaocsbbcrxmgjeenilefileeavgotsiulrfordssgtrsettautnessbdebbadieilppfurvpopwylleemnsiuoelksg
+ddetsyrtemntalngnpwesuccocddyplqppdeisifmrlpimplyntzecggndsuitcaseskarksnflomdtnekrahecsuetsawfpnpcn
+iawaitssbskoedamenelphzijeuhauwpieudrvzvennerraytudtcpasbsencactlocnrcaltifsretaehccsrnempollenagtii
+essertsimdaehrsciagdrphststrcocrnvstesidiayejswheosedmerqhhltviuakacooksussocondoretsaocnofktptdnnls
+ssrettabiesarptgciideyhitaeidodohbvcynenmsncoesiqyvgvrcuaxauclbcearhgiyhladhniblebiluncraakussenioli
+retsimdtluweoolrssfaajxsendnszehoqaxoeesgdtpmoppetsgueeuamoseyumcyganhtlaibeodetoormoisterpejltolial
+sbtrsyhbbdtprleinmtddesrtaetjhpilusrlrtdssoqderunettceirlteslhcsneofisxaenssregnifrettubudnodgasbtha
+sfeergalebiamfsnouieiobattlaebebeicbdweejrruostolgpozsorslslvleiodefdrietvdniqtadjectivesswdrfgeaapr
+widrisitultscrbdccninelelipahgnimeqeisldpjierweqianeubcetoiwsbikcusenerqniiceslaysxrpbmcedunupagnrnt
+fcclimocleiasoaegsgignduearteudtutolkjugambolbnsrvyibvoxrerniipmupfdetezmysaatrcmpeatoaarfetmftaeuqn
+okideokoslbcewnrxnrsospsnsszreeifelatrinemsnxnaeieeetbcsiurvgiesolqsrtcjyrlinaujstelsneqcpatceeyypte
+owdmmeldeargisiraeipeatsenyecsnvfriilatticeworkndlrfesgnihsalpslagfosuunsprlvarnucjotkptardslassgpcc
+tryltdndlgeehysamtuhtlcsoitmpscelcascadinghlsiceasiyrseovexeditsnghfshpaslpuadicsoasislliiumtocsguie
+wynifnpseydscetdsofacyyiledfiqelihslanifbstslewrevevrycvygetxrhipnestsetoahdstaupsetxneascaearjmisvd
+euamraessliuraeicccecnttmstneroynlstodopolansonsadetieeoinoeoeouwiegarrubqyaitovtdeposittdaatnarwael
+apmeitrrussrarrazqaaraiosgypgbgagsgieunuteworpwartrnmcbrfdcoddsihrpnbearlusddlltpoesyrrtjsyljalwtghe
+rpisasmtoutgidqlsuilctnlgnabiopsyngnbilacwsiibgepeiogstutfnheescseiimptaweiecoaegesdeuyuyfeynominees
+aictrsiarorerromgdiipoirfiwgnilratsnibuohortcgnisaefzedrtslrreylcknlooelahckasrvregisdraeslatheriwhr
+yekopuspalirtuneenfmresmonbslartueneiloqebeakoihstlhirruqapaptaaonilculirskrsqtnnsntaarttdetcartsbao
+bsenobsrclcyamnmeiphrpleenufdeniapeptllnsvkvslkyamymceufsrmawussraneonasdaiutdylsasetmaeacanoesroefm
+ruoejoioeatwptmrtkcaarqtgestappinggprodosicahfnmolimiydflecugtudihgvocieiunlerugpshietetniksgipdntmn
+flierrooicsrliacagunfirejpwhimsdphaatngrreucasueufnrmnilisihiduinnlibetdnqgerfoceaodidsdewotwokrgals
+latconnmtfoessepaimedcsatdeducesddshsvvaunfxnsrnvgszkugiettgdldtgrqnhqykgdnawnekrnilseisnoopingisgil
+obmibsssylasirralfpameeviecerggeesemrbegecuebvtstoadspynveaelmhdiresonantgtanaugseitiiruolevtizfreao
+uppgdarnsspegnicieersylbatonarpgfhrsodomychaiserelbmuhvgrtnsstseebedliwmoqlarpobncmpryenrapturetertv
+tvawrdzsponccwtfsrnclennutrcainoaapnbhodepbfrolicsaktziuogrosseforpqfdbrazzesbolaopaneseifidocselgee
+vesjeegvojmooeoeslsthukexwudrarnwanxlkestjacvhscgliatesrohcqsdellennekgiqnslueafsalbtkncttclawsrigrn
+ozpbdbycrenekrsindekyasascetredsdodislbrejlrstgocnobscuredhhabsecurerechaliconsfnciacesixcoupledoanl
+tlmeicsihqmaximaltedynnwsdstssldoemtiebeedmdnbnngvgnippohcaeetsmespodtfmesosdnesjaloperpetuatingbosi
+eegggclassroomssniiralitlpsspsewbidtlelpduyedoicsgumgwfswdnmgfotopaetnrtvlsmovrnsfhfsmpilingcppuiafe
+dahhjnprnhwepecnarpeetixyeeredsrtezeredeldmdepkrnmnpqfgsiucsunneaegsueotisaiecreisueyirknittingsbdbr
+rtyeenickinglfygenlxrdigwsievneetfcevthaeeolnaceoiwispsenmedeielgrwblmncertrntdxsibdpsaostokenismdad
+aeedlafgiuigoarnccgezonchnnlktihttfiasllggalwqitcpcencrpttmteldnnutixisbkiilhgeamyseprzkmrhnmldneild
+tvwkibpeatnhwlozifgiigdugtwoafglrtrwizsnwpaiauleaencrorpoaaekiueoissoaihdszanryognhkaaeccceuyegcehad
+ifaitnmsephymsvstaxfstrqhlowziiirdendhiornplpesyecbeboigarxcrldhtslpgrnahswasitsraiortdemysvtjaindne
+berlyinacaepaeateliyortuetlclofnsirrdrooerleystfdcvlvuytireypiiaidamcyrlessdnoluvyzpcsggsidaimraoect
+unloijrerrrcnssacsetuoaaccbpdymciuakfdpreuegatsopasetznlapsnirnmfkzsztynctrgratoeectsoainarepnrmrbet
+tgibpsridceottensigittnrntnalaesfsnnseysworddcgtlrdedoygstrlrnggisimxaoinoscvrcharsapcngmesiamnmkkdu
+tnkyeuejuuselpscatelhdaaarlegabnaeimriohkinderouaydplerylksleegheueevtteleaeezzaipddpismnmntfgfowcsp
+eietdrimpqankffhpyaietgntwtyrbusesgallivantsdyicelxuydpunerjuyttdysinadlcrovejtloeeitsludgeuijnrcipt
+rbredgyperimusoejsrbayetimikesplkdebrutrepnumnbrklwmbanpserahfosmtdimieiscovsrdrvtyraomissluafioisiu
+nbisluelornaaorsteoastrireitliugselttitndxadgsweiufpreiiadmsbnemilqgcrtrnsiepeclrrapteswovasidfvcgro
+uupceraowdyedtgtstulteoneucertsicitnamoraincoatkubfearedkhayyeutycacyclhwlgrcjoeematrvilvendedaeisin
+trxrmgmsinimefestaniridihueiokfkdedutingamsnoynacqndecayswceagdoarakagcelniesvsndwomagpinupjyrlfdntd
+sgeosdrenblurbscaldahomnnoncncimonoxatkineticrseqorhnarksokurlsqplrreteaiheeeerepwrylykpdtubesuerogi
+qmsaesuohdraugzuiecvemsgigtycnangiopatawdrieroawjsonscallopedsesiwpratstclfddoiastelfaelihbumblersru
+itekrandomisessvrraayrgripestsivitcellocsbawsshapeliestmjgnitontoofhylluftsaobwsocilacidlocatedlrsee
+abound
+abstracted
+acacias
+acanthuses
+accidents
+accosting
+acrobatics
+action
+activist
+acute
+adapter
+adapting
+addle
+adherence
+adjective
+adjudges
+adjurations
+adjuring
+administrate
+adorns
+affairs
+affliction
+afternoons
+agates
+aggregate
+agings
+agitate
+agrarians
+aimed
+airlines
+albumen
+align
+alive
+allegiance
+allergy
+allusive
+alone
+along
+alphabet
+alumni
+ambiguously
+amends
+amity
+amongst
+ampule
+analgesics
+antennae
+anthropocentric
+antimatter
+antiquary
+antitoxins
+aplenty
+appetite
+arcade
+aristocrat
+armed
+armful
+around
+ascetic
+aspiring
+asset
+associated
+assumed
+assurance
+astronomy
+atelier
+atomisers
+attire
+authorise
+availability
+avenger
+avidly
+awaits
+awkwardest
+babes
+backdates
+background
+backhand
+backhands
+backhoes
+backslide
+bacterium
+bagel
+balanced
+baldest
+balmy
+balsa
+bamboo
+bandwagons
+banister
+banks
+barbarism
+barbed
+bards
+barge
+baring
+barley
+baselines
+basil
+bathe
+batter
+baulk
+beatify
+bedfellows
+beepers
+beetles
+beets
+begot
+belches
+bells
+bench
+bereft
+bestrid
+biased
+biassing
+bight
+biked
+bikini
+bimbo
+binging
+biopsy
+birdie
+bivouac
+blackbird
+blanched
+bleeder
+blindfolded
+blown
+blurb
+blurt
+boards
+boastfully
+bodies
+boilers
+bongo
+boorishly
+booties
+bossy
+botches
+bother
+boughs
+bowels
+braggers
+brasher
+bravery
+break
+breathy
+breeding
+brier
+brigands
+brink
+brisket
+bronchus
+brooms
+brought
+bruise
+bucket
+buckskins
+bucolic
+budging
+bugaboos
+bulldogged
+bully
+bumblers
+bunching
+bunglers
+burrows
+butterfingers
+butternuts
+buttocks
+bywords
+cabals
+cactus
+cadge
+caged
+caked
+calcium
+calicos
+callously
+cancelled
+canine
+cannot
+canoes
+canyons
+caramel
+caravan
+caressed
+cargoes
+carousel
+carouser
+cascading
+castanets
+caster
+castigator
+cataclysmic
+catapult
+caudal
+caviare
+cellist
+cervixes
+chaffed
+chair
+chaise
+chambermaid
+chambray
+chance
+chanty
+chapped
+chaps
+characterised
+chars
+cheapened
+cheaters
+cheers
+chemical
+cheques
+chiefs
+chiffon
+chirp
+chopping
+chores
+chowders
+christen
+chromes
+chronometer
+circumspect
+cistern
+citadels
+civilises
+clammed
+clarify
+classrooms
+claws
+cleanse
+clogged
+closeting
+clunking
+clutch
+coaster
+coccus
+cocky
+codifies
+coevals
+collar
+collecting
+collectivists
+colluded
+comatose
+combats
+commas
+commingling
+complains
+components
+conceal
+concertina
+concluding
+concordant
+concrete
+condor
+confide
+configuration
+congaed
+congenitally
+connection
+conniver
+conscience
+consumer
+content
+continual
+contracting
+contraptions
+contrasted
+controllable
+contuses
+conversions
+convinces
+coppice
+copulate
+cords
+corms
+costars
+costliest
+cotyledon
+coupled
+coupon
+courts
+covertly
+crater
+crazy
+creamier
+creatively
+creeks
+cremate
+crier
+crispier
+croak
+crochet
+crofts
+crows
+cruddier
+cruet
+cubic
+cuffing
+culling
+cupola
+curdling
+curiosity
+curler
+currycombs
+customers
+cycled
+dabbed
+daiquiri
+daisy
+damming
+damps
+dandled
+dapperest
+darns
+daydreamed
+deacon
+dears
+deathblow
+debarks
+decamping
+decay
+decentralising
+decree
+deduces
+defectors
+defended
+delis
+demagnetises
+denotes
+denting
+dentures
+dependence
+dependent
+deposit
+deputy
+deserted
+despises
+dethrones
+detox
+devised
+devolved
+devotees
+dictatorial
+dignitaries
+dinned
+directing
+disable
+disavows
+discolor
+disconnects
+discrepancies
+discrimination
+dishevelling
+dismal
+dismay
+disparaging
+disproof
+distrusts
+divesting
+divvied
+dogged
+dogies
+dogtrot
+dogwoods
+dominant
+dosed
+doted
+draft
+drenches
+drifter
+drifts
+drivel
+drollery
+dross
+drouthes
+drowsy
+duding
+dulls
+dusts
+dynamic
+eager
+eardrum
+eastern
+echelons
+ejaculation
+electrify
+elides
+elucidated
+embed
+embroiders
+emery
+emigrated
+empty
+enabling
+enamoured
+encoding
+encrusts
+endless
+endow
+engagement
+engorged
+enquired
+enrapture
+entrusting
+entwine
+entwined
+enuring
+epoxies
+equability
+equivocated
+erupting
+escape
+espressos
+estranged
+eulogy
+evades
+everyplace
+evict
+evidenced
+excavations
+excavators
+exited
+exoduses
+exorcist
+exotically
+expectorates
+expend
+expire
+explicated
+exploding
+extinction
+extort
+extortion
+extraditions
+fabled
+fabricates
+facades
+facilitate
+facts
+faeces
+fagots
+falsest
+falsity
+fanny
+farmhouse
+fathom
+faunas
+fazes
+fealty
+feared
+featherweight
+feebly
+feedings
+feminism
+festoons
+feverishly
+fewest
+fiery
+fight
+finals
+finis
+firmest
+fixable
+fixers
+flaps
+flashed
+flashers
+fleeced
+fleshy
+flier
+flightier
+flinched
+flinching
+florae
+flotation
+fluke
+foams
+foamy
+folds
+footnoting
+footsies
+footwear
+fords
+forebodes
+fores
+forestalling
+forge
+fouler
+fraud
+freaky
+freshens
+friar
+fried
+fries
+frigid
+frolics
+frostbiting
+frosty
+frothing
+frowsy
+fruits
+frustrated
+fryer
+fucker
+fuddled
+fuddles
+funnel
+funner
+furriest
+fused
+gages
+gallivants
+gambol
+gaping
+garoted
+garret
+garrote
+gasket
+gawkiest
+gawkily
+gecko
+generalisation
+genre
+gentle
+gewgaw
+ghosting
+gibber
+gifting
+gimlets
+gimme
+gingersnap
+gingivitis
+girdle
+gladdened
+glade
+glamors
+glances
+glider
+glues
+glyph
+goals
+gobbler
+goblets
+golfs
+gonna
+grace
+graded
+gratefully
+greenish
+greyish
+griming
+grimy
+grinder
+grinds
+grinned
+gripes
+grovels
+growling
+growls
+grubbing
+gruesomer
+guardhouse
+guess
+guidelines
+guild
+guiltier
+gummy
+gunfire
+guying
+gybes
+hairdo
+halves
+handspring
+hankering
+happen
+harken
+harrow
+hasps
+hatch
+hatefully
+havoc
+headmistress
+heady
+heaps
+hearses
+heaving
+height
+hibernates
+hikers
+hills
+hisses
+hitch
+hobnobs
+hokiest
+homesteading
+honchos
+honester
+hoodooed
+hookahs
+hooks
+hoping
+hoppers
+horsetail
+hospice
+hugged
+humbler
+hunch
+hymens
+hyped
+hypersensitivities
+hypnotically
+hypocrisies
+hypos
+iambs
+icing
+idlers
+ikons
+illicit
+immediacy
+impalas
+imploring
+impulse
+inalienable
+inanity
+incessantly
+incises
+incongruously
+inequitable
+inertia
+infests
+infringements
+inhere
+inheritance
+input
+inquiringly
+insight
+insincerity
+insinuates
+insists
+instalment
+instinctive
+insulted
+intact
+intent
+interference
+interpolated
+interpose
+intones
+introspection
+inveighing
+invent
+inverses
+irradiates
+isotropic
+jabbed
+jaguar
+japans
+jeeps
+jellying
+jewelry
+jibbing
+jibed
+jingoistic
+jiving
+jobbing
+jokes
+jolted
+joyrode
+juridical
+keepsakes
+kennelled
+keynotes
+khaki
+kilobytes
+kinder
+kindles
+kinetic
+kitty
+kneel
+knelled
+knifed
+knitting
+kowtowed
+krone
+laced
+laconically
+laity
+landmark
+lather
+latrine
+latticework
+laughter
+lawfulness
+laymen
+lazes
+lazied
+lazies
+leaflets
+leaves
+legalising
+lessors
+letter
+levee
+leveraging
+libel
+liefest
+lifeline
+liftoffs
+likes
+limbo
+limed
+limestone
+limiest
+limit
+lindens
+liner
+liqueur
+lithography
+loadable
+lobby
+located
+lockets
+lollipops
+loneliest
+longish
+lotto
+lotus
+loves
+lurked
+lusted
+luxurious
+lyrical
+mackintosh
+madame
+magical
+magisterial
+magnitude
+mails
+mainstreams
+malls
+mammas
+mandrakes
+mares
+markings
+martinis
+martins
+matchbox
+matchboxes
+matriarchies
+maximal
+mayflowers
+mealy
+medias
+meekly
+mellowest
+melon
+memorial
+merest
+merinos
+messiahs
+methodologies
+micra
+mikes
+miller
+mills
+mined
+minicam
+minivans
+mirror
+mirth
+misadventure
+misgivings
+misread
+missile
+missives
+mister
+mitre
+mitten
+mixer
+mixers
+modal
+moiety
+moistens
+moister
+moisturised
+moldy
+moleskin
+monetarily
+moniker
+mooted
+moppets
+morbid
+mornings
+morsel
+mortician
+motels
+motherland
+motions
+motorcars
+mountaineered
+mousetrapped
+mouthfuls
+mouths
+movements
+movers
+muffling
+mulligatawny
+murky
+musings
+muskier
+mutate
+myopia
+mysteriously
+nagged
+naively
+naivety
+nanny
+napalming
+narks
+narrated
+narrating
+nasal
+nationalising
+naturalised
+naturally
+nearby
+neckerchieves
+needed
+negligence
+nerds
+neutrals
+nicking
+nicotine
+nightshade
+nitrate
+noisily
+nominees
+noncoms
+nonhuman
+nosegays
+notably
+notary
+notified
+noughts
+novelties
+nurse
+nurture
+nutmegs
+oasis
+obeyed
+obeys
+object
+obscured
+obtuser
+oceans
+octal
+oddest
+offing
+okayed
+onomatopoeic
+opaques
+opinion
+oppose
+oppressors
+optical
+orals
+orated
+ordinaries
+oriented
+ornery
+outlasted
+outputted
+outrageous
+outsmarted
+outvoted
+overlain
+overturns
+overwhelmed
+owned
+oxbows
+oyster
+padded
+paging
+pailfuls
+pained
+pales
+palliate
+palsy
+pampered
+pandered
+panic
+panier
+panted
+papaws
+parameter
+parental
+parked
+parsley
+partner
+patriarchies
+pauses
+pawned
+pawpaw
+peace
+peacock
+peccary
+peddle
+pedometer
+peerage
+peewee
+pellagra
+pencil
+penning
+peppercorns
+perimeters
+periwigs
+permissions
+permutations
+perpetuating
+perusals
+perverted
+phallic
+pharmacies
+photosensitive
+physicking
+physics
+piazze
+picaresque
+picks
+piece
+pigeonhole
+pigskin
+pilaf
+piling
+pimply
+pineapple
+pinhole
+pining
+pinup
+pizazz
+placarding
+placket
+plane
+planked
+plaque
+plateful
+pleasantly
+plighted
+plopped
+plowman
+plunders
+plunge
+pocketbook
+poesy
+poetical
+poignancy
+point
+poised
+poked
+pokey
+poling
+pollen
+poltroons
+polyhedra
+polyp
+poplin
+popped
+poring
+portico
+portraying
+possibles
+postage
+potter
+pounce
+practices
+practised
+pragmatic
+prance
+prawning
+prearrange
+precautionary
+preexists
+presage
+price
+primes
+prodding
+professor
+prohibitively
+propane
+proper
+proponents
+proposals
+proud
+proves
+prowl
+psalmist
+psychos
+pukes
+puking
+pullbacks
+pumice
+pumped
+purees
+purling
+putrescence
+quadruplicating
+quarantining
+quash
+queered
+querying
+quieter
+quietness
+quiets
+quipped
+quoit
+rabbinate
+raceway
+radial
+radiant
+radioed
+rafts
+ragamuffin
+raged
+railroads
+raiment
+raincoat
+raked
+ramming
+randomises
+raptures
+rasps
+ratchet
+ratified
+raves
+razed
+razzes
+reads
+realise
+realising
+rebut
+receive
+reconciled
+recruitment
+rectifications
+recuperate
+redcap
+redistricts
+redoing
+reedy
+reefs
+refilling
+refinances
+refurnished
+regaining
+regale
+regularly
+regulates
+reigns
+reindeers
+reinterpreting
+relabel
+relates
+remunerated
+renal
+rending
+rends
+rents
+reopened
+repeal
+reprobates
+resells
+resemble
+resignations
+resonant
+respectively
+restarted
+resuscitators
+retail
+retards
+retching
+retreading
+retrieved
+return
+reupholsters
+revaluing
+reviling
+rewires
+rewrote
+rhapsodised
+ricksha
+ripeness
+rivalled
+robbers
+rogue
+rolls
+romanticist
+rooted
+rotundness
+rouses
+roving
+rudders
+ruffling
+rugby
+runner
+rusks
+rustlers
+ruthlessly
+saboteurs
+sachets
+safeness
+sages
+sandhog
+sandiest
+sarees
+sauna
+sauntering
+savager
+savories
+savory
+savoury
+sayings
+scald
+scale
+scaled
+scalloped
+scalpel
+scanting
+scants
+scofflaw
+scoops
+scored
+scoring
+scowled
+scraggliest
+scrappy
+scribes
+scrolling
+scuffles
+scull
+scums
+seaboard
+sealant
+seaway
+secretive
+securer
+sedans
+seers
+selflessness
+semen
+seminars
+sensitised
+sentences
+septette
+serest
+setter
+severing
+sexed
+shadier
+shakeup
+shakiest
+shameless
+shanghaiing
+shapeliest
+shark
+sheaf
+shearers
+sheikhs
+shied
+shingles
+shirred
+shittiest
+shocked
+shocker
+shocks
+shortens
+showdowns
+shrew
+shuck
+shutters
+sickbed
+sierra
+sighting
+signalise
+sillier
+silted
+silts
+simmering
+sketches
+sketchiest
+skews
+skidding
+skylight
+slays
+sleepy
+slicking
+slink
+slovenlier
+slugging
+smeared
+smelly
+smirk
+smoked
+smooches
+snail
+snaky
+snappiest
+snifters
+snivelling
+snobbish
+snooping
+soaped
+sobbing
+sodomy
+softly
+solar
+solicitous
+solutions
+songs
+sophists
+soughs
+soulful
+sounded
+southeast
+spacy
+spanning
+speakers
+speckle
+spellbinds
+spirit
+spitted
+splashing
+splines
+split
+spoonbill
+sporting
+spreading
+spumone
+squeeze
+squirms
+stair
+stalks
+stall
+stanchest
+stand
+stank
+starling
+statehouses
+stationing
+steeds
+steppes
+stiffed
+stilettos
+stolider
+stoniest
+stores
+stout
+strapping
+straw
+striped
+striving
+stroll
+strongly
+strumpet
+stuck
+styes
+styles
+subbing
+subjoining
+sublimated
+sublime
+suborns
+substantiating
+subway
+sudden
+suffusing
+sugaring
+suing
+suitcase
+sunburning
+superstructure
+suppuration
+surgery
+surmising
+surpass
+surplusing
+suspecting
+swabs
+swarms
+swashbucklers
+swathes
+sweeper
+sweet
+sweeter
+swisher
+switcher
+swoon
+swordsmen
+sycamore
+table
+tacos
+talkative
+tames
+tanager
+tango
+tapping
+taprooms
+tarpon
+tarry
+tarts
+tastelessness
+taupe
+tautness
+tawdrier
+taxonomic
+taxying
+teapot
+tearoom
+tedium
+teemed
+teeming
+telephonic
+telexed
+tempos
+tempts
+tenured
+terminable
+terrarium
+testate
+thaws
+theirs
+theorise
+theory
+thickset
+thistle
+thrive
+thriven
+thronged
+thronging
+throttles
+throwback
+thundered
+tiled
+tinges
+tinsmiths
+tipplers
+tipples
+tipsiest
+tittles
+toads
+toasty
+today
+togae
+toggle
+tokenism
+tolls
+toolbar
+torso
+tortoiseshells
+tortured
+torus
+totally
+toupees
+touting
+track
+traducing
+tranquil
+transcendentalism
+transducers
+transformed
+treacherous
+trebles
+trestles
+tribe
+trinkets
+trunking
+trysted
+trysts
+tubes
+tulip
+tulle
+tunnel
+tusked
+tweak
+twerp
+twigged
+twiggy
+twilight
+twill
+tykes
+typed
+typos
+unable
+unaltered
+unceremonious
+unclean
+unconvinced
+uncorking
+uncut
+undaunted
+undercutting
+underestimating
+undresses
+unease
+unfavourably
+unfurnished
+unhappy
+universe
+unlatching
+unpaved
+unperturbed
+unproved
+unreasoning
+unrolling
+unscramble
+unsentimental
+unstop
+unthinkingly
+untwists
+unwanted
+uplifts
+uppermost
+uprisings
+upset
+utensils
+utility
+uvulas
+valence
+valid
+valise
+varlets
+veils
+velour
+vended
+veterinary
+vexed
+vexes
+vibes
+viburnum
+villager
+villainous
+villas
+visitations
+vitiation
+vogue
+voyeuristic
+waddling
+wagers
+waive
+wallpapered
+walnuts
+waned
+warding
+warlike
+waste
+waterbed
+waylay
+weaken
+weaker
+weedier
+weedy
+weevil
+whaler
+wharf
+whims
+whirlwinds
+whitefish
+whither
+whose
+wider
+wight
+wildcatting
+wildebeests
+wiling
+wines
+winging
+wired
+wises
+wispiest
+wisps
+wonderfully
+woodpeckers
+wordiness
+wrapped
+writs
+wryly
+xenon
+yogins
+yokel
+youngest
+yummy
+yuppies
+zebra
+zests
+zings
+zygotes
\ No newline at end of file
diff --git a/04-word-search/huge-wordsearch-old.txt b/04-word-search/huge-wordsearch-old.txt
new file mode 100644 (file)
index 0000000..d94babb
--- /dev/null
@@ -0,0 +1,1601 @@
+100x100
+yteaspoonfulsicsaretupmocorcimbdpoxesrcutupsmcssixtieslcskqyhsaninecountrywomaneejpropellingqknxqood
+sodasklaisnmythdcjnxksetairporpxeiukxgbegcddiefiwsrybxvgoffkstssretropsnartaknldsahdemuhxeecvspigotr
+tspsecamvndaszlehnetseresdithersencsntgrhrseededbekllgenrcbjnattriapsediepayeeynerrclubfootiacoijmaa
+seoblintzesrtmojapmowggpazdehsawshipcteionesnlibgcmaebfirpctucswgacbbgzhdlgmrwslrleetareportgospeebw
+iixmrmrpcgieiielmselipnnorolopraiieormgwdtoeyslrbngmegavecalrsiddpoaavcrlhsnptsobvlifakerajstridents
+mrdegheeraueabotpxcghleiilmosprnobxhlnhxasiboneaaiimurgdlmnlspreiblneuauoetoieeomieokbbigkioeglibzdu
+ranekuvegckelmenaaanmiditsiamaesmiuiocrgirnfltuntcnuopbiucarelorwaonawvskrjgsalmrirwlscocreolenezels
+adiettepjxaevbfvalpiryidlaicrqbrdtnntaetfrtotectrstgcoienaollymotgngeiiogumnepocossrdtsscinomrahticn
+liltnlrsebivsiavolswiilwondmekdoassaelwycwmailseufntysrurtlmiyusmserafprfaedirpaknseortdesoogxfesued
+apqdchaesesailalllaeesswloeeiiitttcdndoposbnotailmeiishlaidbpnhipiljesrrslpsfknubqohrhywcsvniiltmneb
+fadboonxbefouledlqrpggkpxvgktncnseixybdodluggmiaexsmcsatltfsetgjwisechiorugocvlonhogcaiaulrdtmemettc
+sleonnicetesegfplyisnncedillanihgtuocldeeenbymgsisuotviwtatrslrehirithvwyakntprudentitbydencinirnbod
+ancidecdrknkteaqjgssiiafwsogthamplernsahkirwmgasormlegxyrubodetorreeniessitmitqueerlyrollevgsnvelxvo
+naalosciuwcchcardspodgbsndksauslsrulsaynhabeeetytpisaeaisehtsenalapmctnntescsaidlxbpnptceketgeldfyeb
+dddelkbrnneaiqykcuualnovaaairtunclnnanlscindwershterdetserofeesislslpnettareajberalpmexessissedagdgz
+aeedeuesdmrlrdiumgwsaoirniqagnnjakoxuvutgeusnooggelrspityndevrucleeupsirgrlubfsmsshclkdtownervyrnoad
+luycnxlyvnsssnlowqhnblionmgidgninniksmtbxhdtenlqeamappadlockszgptetrteyrpssaseeyutuhneqiirtivgvninny
+hsserattlesptrndegludnioieqeqecotfcysesirpretnegcduprnpatriotoikbfvissoaareegawttrsubdenmncsprussosr
+vssttoasterrsibkcalvingderrgnillafeblerymselcihevdnkqesgdemialcedpyintpfdrelihenrwksmaqgusyojugairqa
+iiseafileeiosgeiouchatscseeffigiesjsctslsmlrunesozeesvonoisoffocscotltaalkmtbhrriaikjnuiivwcznpydkar
+retdieszliavnfirefightersjvudrerauqsdaslwgoenekorbnupafihmnsmdailynbsidmcaeeampctrliieinnessnzsaoaje
+erooeerrunhiisdmeuattiedataovrmkcabflahuweibdideirrefcfkdprfapgxuiuefedqplyemtuolgyemrnghebrdaixiisn
+tsrscnutfsfstieioegocsrrisrjcbsgninworbfjfawiseribjruusaeeyjgyqyafraaisnaelewoirrflsbecwitgeictmizdi
+rlaerneieeiiskngnioifommsneempiricalxlinlncwrllitrhguaelwntnsreuurparkasaqdudnrohtotosegasdnhsliocnt
+ectsceeplrsonaexaoallhrablanklylgrtseiciujuetzitowajattsoedcecqdaubseetdlehdkphynvfrbhodongedeoglwai
+adrltsivotsnksrgctrthesryrenaloherbsnvnaykpfretsfbazpenyrtqrchbseurdfizzedbebseiprsbeldgrigermadeihs
+dveopgrhdiisupgansnshsdmnrlaitnediseretddsredrosiduliiukqrhmulvviacceptanceeymenowwdognbsollaredpoml
+iayatiapsooybjnsciioidkdwseldnadircstrpsohoreppirntrcnhboaserrerrxtrimaransnndhuoudheirnoswkefalolve
+nerlkvskrnnsclaybstnmoeaasgrossestlpmduillixsxkxisglgcgdbbagemsoabongedifuoksntsodtxkjioiwasfsepesdv
+gswanevoishtljguhaacjtgzrhpromiscuityfrdeyvnicictneliszevimadndbfpendulumstoneaoenncsmomucmieansarao
+stfcccgkiseohetbutrmaeurbrehctapsidwmdrlmkurayhpargorexcilhpaoebsbmaisrlqtrumpedawakgalesnraswkstenr
+beelreaancscdxgeehiireuecowardrteejjeoixmbtrywdraeikttciaishiiresnrubooedeigythratrpmlwzsydindrfmiyg
+vdteeisutuaerpfdjwtiafrfgstateejosrsdthysaeopaeualsxevwpttioolhrgerfvryltrtglhslsaaeoafhtlnseoimrztt
+aisadpaysnflreravineohneilasnruuaeieuccnmliwprhcmuegmncseymnnlssateiitireayesotymrtetzsurgpwtrrraesm
+sbonhldrghicuddovouradersupervenerofhqcdedcsetceocttizkdddeeqedelaqllerohbbalubdtautxiaolzabeaplgese
+tzpeeentpsrvoifoolishkqrtcsonmdsatsnlpcseqpdryarrsastnlneutdbhckllueirrseetuoenasiloreiydyebhiasgrer
+ontratoeuewxvtmpgnihsangzerovbdlotgsausccikhpteaougotanteftnaemcabiafsedasuisaxtlerebnysudurcorhebdr
+pdusdncksitseilddjokemmtvdlsanunabqrbaionusirgrnuniesaancerpdtkenonsixgeirbmlsaisebokrgvogknikladriy
+psoneaassrjurnswoinaktaenargecsliwiiirmdichivcensitajiyusalalhndtaoeeoubaeehyssznmsojsasnoogalijeesc
+ahepdmnuyaymbgnlelffaciihegtrilttilsablzibvjferhlmiktisiqceenoablexddelcrdgritewagtkrahajvsaibaasvea
+gieljtamcudmokcllmpfsctrvisilitfpdilpycpdekitarnywmossnpnqhgdkwpycmermangnqsykpcdontrtmaicsffimrtsre
+epfabnraateeryhoearqeswonicsoeroyaltyloetnrcpuaispgsbrazpgwedtimarmcturfsaeeorpojviseooobgmisleadvlr
+ekioybwftrtrellrmfheersgdtlnnanimalstrnseezaeadrtearuemedxtrmwdneebsseesplmveitpseoeskgkebdjzinzykid
+sheheyaisorepiulkptcleeorotautcahsviteegtcttereenaleclyoyeoysinkgnbhkhaxqbepvtczmrpsteasemitlftrcxeh
+uorcsildnmodeqnyugaitlnnlrmeraelbbutssarrirshltetebpltrnifttlanlrhsxscisyhpoegsmbhdsinnapfvliusalwvt
+rnueanebidsqebsdlfnrsaiitsedargedhksoraenactlcrilcfltblcfntwbgugdpphqiieeirdgteicenanfoggedeycrssite
+sburdgasiqbddjgtuleittckdiyhcppcsxehaptadhseaicofyaieuaabakisnnussasgekieflhasgecaargyaqqsrltgisbedl
+nessehimicgrblmnesomnmstgrarsfiwagepsiseuuwrbsrsliyrnsvimgskicriedldoucjppbrtonhartgglfziieasqietgud
+oeksaseesrroeseoiptjaaemevatntoealsenimcldeskdabgdcatraaaenmhgtstfijdfoliavetlimbispuladelstutaninlo
+ipmyhbtarteoaatcnycrphenlhnsebsvbippzaktsdihidamenqarscdsoauekifoiklhotlceneagkainsxcarrlrgiahgenihq
+tirnualsdhhtfdkouoohirsbttplluladateriringpnakadalistibwhghssslsdovmogckpcdngbadigqeeieovznvfeylkhcg
+anqcgadeescgngpekpcliahsdaoeoevmraaknyfuguglanrtrgelsilaiatxnthearonispkhctegwmdsynamcdsltqfcsrbesre
+pgsselmrahpguibarealpllneulisoseabigngindsitiaenisonymnnpdntuggtwdopiagsierceengutturalserpojeamraan
+uzyyteqogcsanawcrsdtemdntetimpsnlnyeyeidlhsfwnrgniirbtagusesdddxacrmcaledntoovungtecifjsqxannztuimmu
+csexetrovliirirtesnrsrerlnsesuregumsillecioesyfhgopyabshnnstorsiaoakosyaymgttmlflnsrieshfylpgxehnssr
+cupssyhmebagnrydewiidyateprnleeuhpsqaianmltisnkildsylrienrblutmpcrictftnlzkoohoenajwpeqofjyreesmgtse
+oacarneyodesaoirfhpdxnadtoopekdransenzendsodddurpeeesbzoeivfsmllgnoseeyfegnitarrdihsnrmebenumbslasrd
+efryedrxuuodsmmefiprkvnhwtevmcnziupgyuuslnscatuddtdxazbtdakatoaagmyconscriptedtptcscseeswingerprsgri
+rooaweudysharfidssysketaobligeibasnorkelledlepekeaueinlrlgoumirkplvsllotenttlxoosiennevteggunzbteeps
+psspeloiuyzgsoutatlutuasenecsaclperspiringnttigtdrcmuinopbibmihuasirksggtodrooosjsctsblunsawltwntlrw
+otsailsaxuloskclzorirtcinotatacagqsbmoxpdvpzsdeurttsfrnidtkenelnskemmandsioseomhtusieidebisotodbtgia
+vewpvenmavafnrwksuuttactualisationvylapalejndssrslihnnightdeisaeldootilautguyhrpbmfpnrdnselcnefyssvs
+erasebgosyoneifamcnresrowogcucifosbeoarpgiclelqieiosgonsbskrinnuedtbgcizargooitwhibgnghakraathstksim
+rellriyndiofmsfpguiogyybbatmathbwtlfgtusoaaublxnsfnhrnwsebevwyicpifaoieftooimenagenuosfoddorengcioeo
+wdkyplfdreoiaauerbknaynuidgemuhidldibgwghsindimsuncovkizssewavitvlrymgmjkpncueogfiuatbmssoamwtovenrs
+rqlrilingrowlssoucatamaranewroslloeevesnheettdtolihpzrtnsligetcewoodejgdeeeaglvnsdvryscslpsoespseygn
+ireemaselgrubptthnchowslonnflauaflevrnkseusdsualpgetmbberrkroosyfidarlsijrdrageisfomkehhtossorxgtlaa
+tdsbalbegaenileeuscnwrhffcaorcwslpitadaevasmelterscawhselumnobanzstsdolondeomylnlnlgeloacigxezancdsh
+itlincubationdlldimgmocdmmgcmapaelsezgstgewgawssudklnwaaliolsmrxfpdsitgubgsvuysrkewnyerrdebaoeoiuliy
+nrawamenoitatibahocamjersraccfyrnsyanecatascdinpbaekltusniejyleenoliorbrgetcttkainrsscdrbolrndcrdoil
+gtktfirmerrsngaboatersaiaoysredleueaosrvnsdemandssdurqsonrtcdvnmnrlvrreuxbyssboeptaettsuwmsuhsfpnbiw
+nxlithrnlfjerifestseivmpcnleenohpomohwaolsycgvelveteenuewnatnaoepctsmokelesswkdbippbriohewseagssieao
+adefglvsdvmlmilchiwliehklibrhrpsgauntamndarlwmnuitnyjsotseipluplttxobgeeksmlandparhuovorjcresiropavl
+mmeehneegsapaoaecsisrircagaryehlzkpjemoerieatidiedrnlncantorseatfussanirastoisbapcurkeavuresmsdeicet
+sbxaedtbokkmfltknbhtcieyernstpeautidvgkralpsajzlieteannicingmysowolvohdgipswgqbozscnehakietwtaetnjek
+eblelnadurearijuamxpvgpnarmfrmcmnloydlkizsopinrettntsfloozieieuwimittuebownkmoraleeosikiceaieeifaabp
+brnuetsotusroaoteeeaiodaziaciermnbirelclztsewerntiardecnatsninnnimaattgrewpsalmiabfesgatykenspnbnqdi
+iwfvhqlrimhtnnsncalalepgakdhdtueanpaiearukedliiielexssbfdlgwtrysuhpturdtounhedrizzleglgeeshkalbheode
+rinicijeerictetucbeerrbtksnilsmrttitfplybasbbwpnegsntddetliseddsxpiuzwidtnemssessaeigiidzfewfeojsnca
+tinchestrafrgodaekmedvsaoismnirsuicnelboscaraicsnhhupsevfsgfpecibeadovrfwrsrekafyhwnaelcehrsdftbticl
+egmpgyncartzntimdikkrigxlcweediirtkeduoocdegpyuuuuppeiiyrgniewhssnrninbalusninepspeamntgepneibbdmvfs
+svzmhdoueuqaipsicsspahserdcrfduoatembbionsgeeohnstglueliorcorcieetsuznamgerisfrizesnernnerqrsooazare
+tjytsapleatsgeesrdpiioipnrlunsqtlermyaneolsnmqnkuayamxaliuudtbrelhcsymgyasrvsersdanidoaeanzurcnxcwgk
+roalreintyasaraielswnnmslqsepmsetfporsmpladeseiovgeyptpoitbaiyceeulesstpyrcneepecdmowbmgniflogoabofn
+auesbcydellepfmnvomicfpdpaitrimpnnrceanqesumdnqircreqasfdnmdfvnepsnrjldettavpodaaugyknlamigratesxxno
+uressuemkgeereatefegoalarfyrloeepooqscarfeddgriactadsniomsgawcvhhidotegdgnjuwwprcamnrfiddlestickschb
+qnsnteohcnhkicnerelhaqymoylanunskcuautopsymsecidobrldtnfiegdameyaaesfnsrgavntlciqbfxitsixeocksocwmkb
+oazpyozdaissotsrirlttmirfgcebianueweakfishxdesrevnoclggmdesotnegnsmhvdesiwnisuirntinusszytorstlaeeqi
+cldkuqlcpruptihpntwtgbnhiigkllusnsdisabbesslrdhrstdaosnigkyosofdttiajyrmacmntwvouebaacidmslrjeiprrge
+qiechoteuabieoirgntenogvldambgetscalvedotdaeesienadrmspimkmdenfqiiceseirarrtrresndsiidoucoamsnspcmts
+dsefaalinpaprnpemeimrlsdemeritsegasrpnlsetpvsehewdtgsewamuctoshmncapetrmhreeeenpxnerlbhtqctadgzeseut
+imginwradstmlshtqcrotlolssevereprisalsmtteawntcllkoedugesmaqtusoeeanaaftcnhrvdepnycrmleeeoeshacdinst
+eleakedaterviajeotrillionthdsesneunamaoieruwobpedxedbajciieatpuurbetnsibafcrosrenomenafdswlfdmsrlhsa
+tqotjlennnrutgcdacecwcdhkseysjusticerxmpbxpmagadealyzouagvbtvprslvetimhtmrruckalntsteinolipihrawaelt
+elilndrpugaabfoizvaunoadepositoryfgtimzhvhmsgtemsemisdhecarnsoviosyssocuoeapaithgisnleqvlnvnliainset
+daverskeatucestsdfeopkroaiqtdetoragfoyqchaslcjhssfnlstlhsrvetrenbitnilnamputtnecdtuyawnsadueiorgddsl
+erogenousosevfeoaacnyajyresgnidaericedudmtnercaceeyzwloheditvtygnlitanksipaeisssurpatterwnsolnsegzni
+kfferfxsretsoorrrerppbrwewispebyreadooaspreaderdcaaoodenyandzoogitilekudlisdonubenyestetcolretavyatn
+ruoyuiepartistesrtcpalsiesstaelbdemweucdelbbauqscrscushleaseearjimpotentengynbssyllufitnelpthaqobjlg
+yklfrancsejvjgnicnivenuyentuhchtliuqblcezaeardyhaqcereprintedrhovesubmersiblelocalssnfrjxcarosemarya
+abaft
+abashes
+abating
+abbess
+abbreviation
+ablution
+abode
+abridged
+abstracted
+acceptance
+accessed
+acne
+acquainted
+acrider
+actualisation
+actuator
+adamant
+addle
+adduced
+adhesive
+adjourning
+adjustment
+adjutants
+admonishes
+adult
+afar
+affirms
+afford
+agglomerates
+agitators
+alarmists
+aliases
+alluvia
+alms
+amanuenses
+ameer
+amendable
+amigos
+amok
+amorously
+amuse
+anacondas
+analysts
+anemone
+anesthesia
+animals
+annihilators
+antedate
+antedating
+anthologies
+antiquary
+antitoxins
+antlered
+anvils
+apace
+aplomb
+appreciably
+apse
+arbours
+archer
+arcing
+arcs
+argued
+argyles
+arrest
+arrogating
+artefact
+artistes
+assails
+assassinated
+assaults
+assertive
+assessment
+astringency
+atrium
+atriums
+atrophy
+attribute
+augmentation
+auks
+austerely
+autistic
+autopsy
+aver
+baaed
+backpacking
+backslappers
+backslide
+bacon
+bags
+balding
+ballroom
+balsa
+baseboard
+bass
+bathing
+batters
+baud
+beaning
+beaten
+beauty
+bedrock
+bedsteads
+beeper
+beeping
+beeps
+befalling
+befouled
+behead
+belittles
+benumbs
+besiegers
+besot
+betas
+biannually
+bias
+bicep
+bidets
+bigoted
+bilaterally
+bilge
+billfolds
+bins
+biospheres
+bitten
+blabs
+black
+blacker
+blander
+blankly
+bleats
+blintzes
+blither
+bloodmobiles
+bloodshot
+boastfully
+boasts
+boaters
+bodice
+bogeymen
+bogging
+boiled
+boldly
+boleros
+boll
+bombing
+bonged
+bony
+boobed
+boobing
+booby
+borne
+borrowing
+bouncy
+bowed
+bowman
+boyfriend
+brainier
+brats
+braved
+brawny
+breezier
+brig
+briquets
+broadsided
+broil
+brownies
+browning
+brutally
+bunk
+buoyed
+burg
+burgles
+burns
+busbies
+busboy
+bushel
+bushelling
+buzzard
+cads
+cagier
+cakes
+calicoes
+callow
+calls
+calved
+calving
+camber
+camomiles
+cannabises
+canoe
+cantaloups
+cantors
+capes
+capped
+carbonated
+cards
+caregivers
+careless
+carelessly
+caroming
+casino
+catamaran
+catatonic
+catchalls
+catchwords
+catnap
+causally
+cavalryman
+cedilla
+centrefolds
+certificating
+chamber
+champ
+chaperons
+charbroiled
+chastening
+chauvinist
+checked
+chest
+chides
+chigger
+chignons
+chilli
+chime
+chirped
+chirrup
+chlorine
+chords
+chows
+chucking
+chutney
+cilium
+cinders
+circularised
+clasped
+classical
+claustrophobic
+claw
+cleaners
+clears
+clingy
+cloning
+clubfoot
+coarse
+coax
+cockleshell
+coexist
+cohabitation
+coils
+collegiate
+colonels
+colourblind
+commentary
+committal
+compartmentalised
+compatibly
+compatriots
+comptroller
+compulsive
+concession
+condole
+condoning
+confesses
+confetti
+connivance
+conscripted
+consequent
+conspiracy
+contenders
+contriving
+conurbations
+convene
+conversed
+conveys
+conviction
+cooler
+cope
+copter
+corn
+corporeal
+cosiest
+councils
+counterexample
+counterpoints
+countrywoman
+coward
+crass
+creamy
+credited
+creole
+cretin
+crevasse
+crinoline
+crossbows
+crosswalk
+cruder
+cruets
+crumby
+crystalize
+crystalline
+cubs
+cultivators
+cumquats
+cunninger
+curbing
+curtseys
+curved
+cutups
+cyclones
+dabbles
+dados
+daily
+daintiest
+damnably
+dandles
+darns
+daze
+dazzling
+deadlocked
+dealt
+dear
+debtors
+decade
+deck
+declaimed
+decomposing
+deeper
+defied
+defray
+degrades
+delight
+delineating
+delve
+demands
+demerits
+demurest
+depository
+deputies
+despair
+detoxified
+devout
+devoutness
+diacritics
+dialyses
+diamond
+diction
+dieted
+differentiate
+dills
+dims
+dipole
+dirty
+disabuses
+disdainfully
+disembody
+disengagement
+disobliging
+disorders
+disowns
+disparage
+dispatcher
+displayable
+disseminated
+disseminates
+distemper
+distends
+distillates
+dither
+diverts
+divvy
+doggonedest
+doldrums
+doleful
+donor
+doodad
+door
+doses
+dotted
+doubly
+downwind
+doyen
+draughtsmanship
+drawer
+dreary
+drizzle
+drooped
+dryad
+ductility
+dude
+duke
+dumbest
+duns
+duodenums
+dwellers
+earmarking
+earning
+ease
+ebbing
+eccentricities
+economic
+edits
+effete
+effigies
+eggbeater
+ejects
+elbows
+elders
+elective
+elephantine
+embellishing
+embezzled
+empanels
+empirical
+employing
+enamored
+enchiladas
+encrypts
+endurance
+enterprises
+enthusiastic
+enured
+enures
+epistle
+equal
+equinox
+erogenous
+essayed
+evacuate
+evincing
+evoke
+exalted
+exemplar
+exhumed
+existent
+expectation
+expediting
+expostulation
+expropriates
+extant
+extremism
+facially
+factitious
+faint
+faker
+fakers
+fakir
+fascists
+fasted
+fatherly
+faulting
+feared
+fencers
+fern
+ferried
+ferrules
+fertilisation
+fertilised
+fiat
+fictionalised
+fiddlesticks
+fidelity
+fiend
+fierier
+file
+filtered
+filters
+finagled
+finales
+fiord
+firebreaks
+firebug
+firefighters
+firetraps
+firmer
+fishers
+fishnets
+fission
+fizzed
+flagged
+flatted
+flayed
+fling
+floozie
+flyweight
+fogged
+foldaway
+foment
+foolish
+foraging
+forcibly
+foregrounds
+forested
+forevermore
+forge
+fornicates
+fortnights
+fostered
+founts
+francs
+franking
+freights
+frequently
+frescos
+frets
+fried
+front
+frying
+fungicidal
+funk
+futile
+fuze
+gaits
+gales
+gallantly
+gambols
+gamed
+gamuts
+gangrened
+gannet
+garnering
+garoted
+gauche
+gaunt
+gavel
+gawks
+gayness
+gearing
+geed
+geeks
+gelded
+gender
+genome
+geophysics
+gewgaws
+giant
+gimleted
+glassfuls
+glaucoma
+global
+glottides
+glowered
+glows
+gnarl
+gnashing
+goad
+goalies
+godfather
+golfing
+golfs
+good
+goosed
+goutier
+gowns
+grackle
+grandstanded
+grasses
+grassing
+gremlin
+grenade
+greys
+grilling
+groomed
+grossest
+grovels
+growls
+gulley
+gums
+gunk
+gutturals
+gybed
+gyrates
+hairbrushes
+hairnet
+halfback
+halon
+hands
+hansoms
+harangue
+harem
+harmless
+harmonics
+hastening
+hats
+heap
+heartbreaking
+heater
+heaven
+heiresses
+held
+hellion
+herbs
+hermit
+hiding
+highboys
+holographic
+homesick
+homicides
+homophone
+hones
+honing
+honks
+hoorahs
+hooves
+hops
+horde
+horribly
+housefly
+hove
+howls
+humbleness
+humorists
+hungers
+hungriest
+hurrahs
+huskies
+huskily
+husking
+hydrae
+hypoallergenic
+hypochondria
+iambs
+icing
+idiotically
+illnesses
+illnesses
+illustrates
+illustrations
+imitates
+immobilising
+impenetrability
+impinge
+imploded
+implying
+importations
+impotent
+improperly
+incongruously
+increment
+incubation
+indecisiveness
+induce
+inductee
+indulged
+industrial
+inebriated
+inferior
+infiltrated
+informally
+inhibits
+inseam
+insertions
+insignias
+insoles
+installed
+instanced
+intercessors
+interdict
+interesting
+internists
+interprets
+intimate
+inundates
+invented
+invitingly
+involvements
+iodising
+irks
+irregular
+isms
+issues
+itinerary
+jabbed
+jeremiads
+jigsawed
+jilts
+joke
+jolly
+journalism
+jugular
+juiciest
+juicy
+justice
+juxtapositions
+karat
+kettledrums
+keystone
+keystrokes
+kibitzer
+killer
+kinematics
+kink
+kisser
+kited
+kitties
+kneed
+kneeled
+knobbiest
+knocks
+kosher
+labia
+laconically
+lades
+laggards
+lagoons
+lanced
+landmarks
+lapidaries
+lapsing
+laudably
+laugh
+lays
+leaked
+leased
+leftists
+legatee
+leggin
+legs
+lend
+leniency
+lenses
+lessee
+lessee
+libelled
+licensees
+limb
+limbers
+limbos
+lineage
+linen
+liquefied
+liquefies
+listed
+listed
+listen
+liveliness
+liver
+locals
+lodged
+lofting
+lolled
+lollypops
+longings
+looney
+lording
+lordlier
+lords
+lovebirds
+lowbrow
+lowly
+maces
+mademoiselles
+magazine
+magic
+magnets
+majority
+makeshift
+maladies
+malinger
+maltreats
+mammoth
+manifolds
+mantelpiece
+many
+march
+margarine
+marshes
+martial
+mascaras
+materialist
+matrix
+matts
+mayhem
+mean
+medications
+megaphoned
+melody
+memorises
+memory
+menage
+mendicant
+merman
+mermen
+merry
+metals
+metastasise
+mewl
+mica
+microcomputer
+microwaved
+miffs
+migrates
+milch
+militancy
+miniaturist
+minimising
+ministers
+minuscule
+minutes
+miserable
+mishmash
+misinterpretation
+misinterpreted
+mislead
+misled
+mismatch
+mismatching
+misspent
+mitigates
+mizzens
+mockeries
+modem
+modem
+moderately
+modernists
+moistly
+molds
+monocle
+montages
+monthlies
+moot
+morale
+moralises
+morons
+morticing
+mortised
+mortuaries
+motherland
+motives
+mouse
+mouses
+mousing
+multilingual
+mummers
+mummified
+murks
+muse
+mushing
+musician
+musketry
+muted
+mutters
+myth
+nagged
+nannies
+narrated
+national
+needed
+negligees
+neighboring
+neonatal
+neophyte
+nerves
+nervy
+neurologists
+night
+nipper
+nippy
+nites
+nits
+nitwits
+nobleman
+nobles
+nods
+noises
+nonstandard
+nonsupport
+nosiest
+nostrum
+noticed
+nought
+nouns
+nude
+nugget
+nutria
+nutrient
+nuts
+oaths
+obey
+oblate
+oblige
+obviated
+occupies
+oceangoing
+octets
+offing
+offset
+ogled
+oink
+opened
+operate
+operational
+opines
+opposed
+opprobrious
+oratorio
+orgasm
+orthogonal
+ostracism
+otiose
+outcrops
+outdo
+outlaw
+outpost
+outputs
+outranks
+outsourcing
+overhearing
+overrate
+oversee
+overshooting
+overstayed
+overviews
+overwriting
+overwrought
+owner
+oxbow
+oxygenate
+pacifying
+packet
+paddocking
+padlocks
+paging
+pails
+pale
+palmist
+palsies
+panda
+papayas
+paraffin
+parameciums
+parenthesises
+parenthetic
+parkas
+parliaments
+parlor
+parqueted
+parred
+parries
+parted
+patinas
+patriot
+patronise
+patronised
+patsy
+patter
+pealing
+peddles
+peel
+peeper
+peeps
+pelicans
+pendulums
+peninsula
+pentathlons
+perfections
+perish
+perpetrating
+perspiring
+pewees
+philosopher
+phonying
+physicked
+picker
+piebald
+piggyback
+piles
+pilling
+pimple
+pipes
+pitfalls
+pittance
+placid
+plagiarises
+platooning
+played
+playing
+pleasingly
+pleats
+plectra
+plentifully
+plexus
+pliant
+plod
+ploughs
+plowmen
+plunder
+plus
+pluses
+polemics
+police
+poor
+portion
+poser
+posh
+potboilers
+pottiest
+powdery
+powwowed
+poxes
+prancing
+prefixing
+premise
+preoccupations
+prepositions
+preppie
+preppy
+presidential
+pretends
+previewers
+pride
+privier
+proclaimed
+proclaims
+profiles
+prognosticating
+programmables
+prohibits
+projectors
+promiscuity
+propelling
+prototypes
+provide
+provisions
+prudent
+psalm
+puddling
+pulpiest
+pupa
+purling
+purloins
+pussycats
+quaint
+quarantined
+quarantining
+quarts
+queerly
+quilt
+quince
+quintessences
+quizzes
+quotation
+raced
+radiates
+radios
+raggedest
+railings
+raincoat
+rajahs
+rambles
+rambunctiousness
+ransom
+rating
+rationed
+rattles
+raucous
+ravine
+ravishment
+rawboned
+razing
+razzes
+reached
+reacted
+reacting
+readings
+readmits
+reamer
+rebinds
+reclassifies
+reconciled
+recur
+redheaded
+redheads
+redskins
+reek
+reeled
+refer
+refinanced
+regicide
+regrettable
+reissued
+reject
+related
+relegates
+relented
+relics
+relive
+remorseless
+removable
+renal
+rending
+renegotiated
+renovates
+reposes
+repress
+reprinted
+reprisals
+republics
+reputably
+requisites
+resembled
+residential
+resides
+restauranteur
+resting
+retouch
+retreading
+retrospectives
+revering
+reverse
+revocation
+revs
+rheumy
+riced
+rifest
+riffed
+riling
+rioter
+ripper
+rival
+riven
+robbers
+roosters
+root
+rosemary
+route
+rowed
+royalty
+rubes
+rubs
+rued
+rues
+rumbaing
+rumbles
+rumpus
+runes
+saboteurs
+sages
+saki
+sandal
+sandbagged
+sandbagging
+sarcophagus
+sardine
+scant
+scarfed
+scat
+scats
+scenario
+scenes
+scheming
+schlepps
+schlocky
+scintillation
+scoff
+scotchs
+screw
+scuds
+scumming
+sealskin
+seamanship
+secured
+sedentary
+seduction
+seeks
+seethe
+selvages
+semi
+sensibilities
+serapes
+serenade
+serest
+severe
+sewer
+sexton
+shabbily
+shad
+shaken
+shamefully
+shamrock
+shawls
+sheathe
+shoed
+shoptalk
+shortstop
+shred
+shunned
+sickliest
+sidelined
+sideshow
+sifted
+silent
+silhouettes
+silted
+sirs
+sirup
+site
+sixties
+sizeable
+skate
+skedaddled
+skiers
+skinning
+skip
+skippers
+skullcap
+slacks
+slaking
+slammers
+slaughterers
+sleazy
+sleds
+sleeks
+slicer
+slogans
+slots
+smaller
+smashes
+smashing
+smell
+smelters
+smitten
+smokeless
+smokes
+smokiness
+smut
+snaked
+snorkelled
+snowdrop
+snubs
+snuff
+soak
+soaped
+soapsuds
+socks
+soft
+softwoods
+solids
+soliloquising
+sopped
+sores
+sorrel
+sorriest
+sorrows
+sorted
+sorters
+sorts
+sourest
+sows
+spacemen
+spadework
+sparingly
+spewing
+spiced
+spigot
+spindly
+spinoffs
+spire
+spoilage
+spokesmen
+spouted
+spreader
+springs
+spumoni
+squabbled
+squarer
+squatted
+squirm
+stabilised
+stabs
+stacking
+stalactite
+stallion
+stamped
+standpoints
+starve
+stash
+state
+staying
+steamiest
+steeped
+stemming
+stench
+stepchild
+stepladders
+stereos
+stewarded
+stigma
+stigmatising
+stints
+stoked
+stolen
+stonewalled
+stoppage
+straightens
+strews
+strident
+stubble
+stubs
+styling
+stylising
+subleasing
+submerged
+submersible
+subtler
+subtly
+suburbanites
+sultry
+summered
+sunbonnet
+supervene
+supplements
+surveyor
+swam
+swans
+sward
+swashed
+sway
+swinger
+switch
+sword
+syllable
+syllogism
+syrups
+tabby
+tabus
+tacitness
+tanks
+tarots
+tattle
+tattling
+teaspoonfuls
+technologies
+telexing
+temperament
+tempests
+tendentious
+tension
+terabytes
+terraria
+terror
+theocracy
+these
+thirsts
+tidied
+tied
+tigresses
+tilts
+timed
+tinging
+tinkering
+tins
+tinsmith
+tips
+tissue
+toaster
+tobaccos
+toenail
+toes
+toil
+token
+tolls
+tonnes
+tonsils
+towns
+toys
+trademarking
+tramples
+trams
+transfixing
+transplantation
+transporters
+transshipment
+trawl
+treasures
+treats
+trendier
+trials
+tribesman
+tribunes
+trifler
+trigonometry
+trillionth
+trimarans
+trivets
+tromping
+trophies
+tropics
+truest
+trumped
+tsarinas
+tugs
+tumbrel
+turfs
+tussle
+tweeds
+twelves
+tycoons
+ubiquitous
+ugly
+ulnae
+unaware
+unbeknownst
+unblushing
+unbroken
+unburden
+unclean
+unclothing
+unconquerable
+undefined
+underact
+underground
+unfriendlier
+unimaginable
+uninterrupted
+unit
+unjustly
+unluckier
+unluckily
+unmaking
+unmatched
+unmistakably
+unmodified
+unnatural
+unnerving
+unopposed
+unpreventable
+unsteady
+untruth
+unusable
+unveil
+upbraids
+upload
+uppercutting
+urges
+valets
+valved
+vaporise
+vatted
+vegans
+vehicle
+velocities
+velveteen
+veneers
+venerates
+verb
+veritable
+verminous
+vernal
+vilified
+vintage
+viragos
+vital
+vitiated
+volume
+voracious
+vortexes
+wager
+waggles
+waits
+wangles
+wapiti
+warrantying
+warty
+wattles
+wavy
+weakfish
+weasel
+weaselled
+weeded
+weekdays
+weighty
+welds
+wheeling
+whipped
+whist
+wife
+wight
+wigs
+windbreakers
+wink
+wintering
+winterise
+winterising
+wintery
+wisp
+wispy
+wittily
+woodbine
+woofer
+worse
+writers
+wryer
+xerography
+yank
+yawed
+yawns
+your
+zeniths
+zoom
\ No newline at end of file
diff --git a/04-word-search/huge-wordsearch.txt b/04-word-search/huge-wordsearch.txt
new file mode 100644 (file)
index 0000000..f5a13ab
--- /dev/null
@@ -0,0 +1,2101 @@
+100x100
+smuiclacphysicsihcnebrevilingdroskcabllupcsowygnitnacsipblustedpesnipilafeldrigclenquireddetnawnufly
+eqdbmnutmegsvtzdtelbanimretanmelptseikwagewoodpeckerstirwaszbdrrdypicksnzikylhsiroobsuspectingsexevd
+cgnittacdliwffisuoniallivsegasplraftstyevcsgcdemrofsnartrmlaydzescpopxehsfannysdiscriminationdoeypen
+nnytimavwharfrepjstswashbucklerswklqimkeosulxnopratpsitaoorsrtrjtthnsmxrelabelesrssstribiscutsddvbrs
+eidgkdesivedaiajshegdtgrgniyugyshohaabrmedgpantedsobeysodgmraoozdteosaboundgfjsmbttpygjujedorhdvboeh
+tverediwtczdtlwdeiaryehacrierhsrmccosiantnnbestridikysreepegarotedadrpslaropausesubepnrdissoteiailld
+narddypasjitligihpesubsrwewfgciuuhfsntizsgingivitislublefotkcuhschrmsensitisedeugnveleygbutsiyjcflud
+eernefunuaiindrsilnsethiokutttaeiapgodsteknerdhlngemldlrslhtrhobnobsizsvdlocdtrszbnjnbpieoizwillkarf
+shiensetnhaepslnnaietundowigvidtrptsrsayiewreogudoecniebbyofugamwhmtntwsufaulcdsmlptbeondrancoeersak
+onhpnnktstsdovgsdicvevqeypblohdoaseomtcdrbaatgnrgdnaiaejspdtscrsoratzdntmrgenqnomiroixqgslltmsbfduee
+lasxiiasehcnerdjomoidodedsoayvebrawnufhcrtrtsgiaxgdekmkrtfodkinoirfekkaagvsermuroalabsreraehsuxxnoet
+grderahepeeweeusiutdirnohmaccsmardrztienunpdeehbomeyxruyralgeskucnoveltiesseirfdpyebuttocksntqlaodne
+nrrsglsmxdupsdwrgoielalgmccuikisexoaaltwfniaidcbtgednzcpoeoatsqoszdgratefullytisportingsweepersaapys
+iawlbpsleeyhgorhulnnstulleemntlgtnmttpssostidstienstcbfnnhggcstegsugaringinsighthrsniftersmmfwicdeoi
+ntabemghsstenongideckefombnlrarlxynieuplplsznnendirswunfgsiehsuensdelbafetkzinterposexldsurtimreelhu
+oegleoaeiusdrixklisecdiaiprovesoatllsdsayebsawrasieeterrlaesihztixsllihygrellapractisedatcneeavgggpr
+sdebzczioferrsexdiadatergthrivelpdagearetrfhststsavrbyriymsrecharupocketbooktrotxextuvznwkunlkaqggtb
+ayrewatmerseespumonebatlnoisemorhcdrnadaubistpoeehiouxcpogaesnsuuyratchetswishereatjingsepnfepckaose
+eosafgcffsrrhsawretpadaspitgewuheaiggiivrllcaamkvgntrodtbsidtutpjnrgretemarapecnarussaugaylcfrpantet
+rretarcurneicwgnpellagraupmsixcdswniodknelgnaaetinusmlomsgibehfedtslabprowldenimnushiedrkaqndltillss
+ntoimlleatgbtlrcsxsehsesitengamedinkafgnonnxtladtabmvkifuentblwaaroeegniyartropieseitoobsnolemedtpuu
+ubqfilentigrigafassevissimagingslgiryuoriitoarnsahaseigodniiyelwblmupwthguorbkobmilkiaxhfeedingspptr
+nanyydnerxaewaryrriaemackintoshwftrsbnasnhsukntrksragasketrpcsraarliptereinterpretingieycoudeggiwtnp
+msrgnylmnkraslitloeettosplinesobtihfgnlgtktmrxealwassetpiykusurbvgijzeejgpkxclrtssfdnrtonnaccordshoa
+aihikersaebkawarrtssraodcrgckrpyekbruesuorhnpennaobwgmoversabidgriwcsketchesuesartetsicgswollefdebcs
+zleticilliozaenkfuftsrnvzylogeldilsrrrcrinoautnitrlbroeidribuiwaeireakrstmioieiadxesnnlrolocsidazdms
+srsyamajsmedlkssrdloyeagevapwanespcemorhucilkxamhroouevilamsidvarcemgtqggezgfdeaerosyygnideerbnquoit
+reprobatesdiyruovasbsidboddubehksoehnssseevklieepuoaetlairetsigamtorocevinneedmspwtnpfincisesuhctulc
+smvrnttsdldfysbcontrollablelfsraleaveseuslvpsavsgbtrshalvesylsuougibmaesesimcpgopavhshortensrszzazip
+vebaeioliedpmsuesilangisgynainhcazingsyymqoqueryingdoreopenedhsendlessasolbbsqlrlsnikskcubetbrknifed
+jiklruonsflefilbsnwodwohsnittupnitfstdretsenohlcrcvsmphngnimirgnidaetsemohgbbaamongstljykwucustomers
+doionfghfaalsotejhlrgmewhiieelbbgniretnuasuqsuiouoazeggqrhrisnoituloswselppitueaowymrioutrrbfruitspa
+veydjogonywisiutvosplithsejlhpesseieinveighingqymnlerlbukfpineappleeunkagfieensrealiseadelaarjeevell
+rkertuiegvgcbodleoievtwhtiiyiomravrsetransducersafelaatemptspbjhkrudenifiudktdscalesfratreaopinionql
+tddyoveterinaryoenrnedaebapgowjuiniepsalmistyxadtinnlenvdnakiebrashereatmneirdsnaecomfaeiidedpskfzii
+kfpbgdtacoseizlfsrfgimrblebehopnrideraemsnfhropatdcdriuieyjnilvmschkhkweentaoutsmartedwlooaefiekydmb
+fewestegwhcpuviacpfrenisreesbtgcktshueckfttuzbemteecaswlpggdaypipmrniakrqeasedoberofmrrqltnhphqdefpn
+dyesightingateonspalfngsdqfbxcellistottrnscchhdesshlhefleindegaasmeatewnulcsekytmrgyoaoecoiilanlatao
+hddrafobjectkatrsaehgdeertiprrzyalndegmreioascontrritspanloieinwiumlzwaoaiissziicnetuimidictatorialo
+renemidmuiretcabgsnwrnhegnoigimletslrywdenreftmdiectrsygdmgrssvsealplyrobcllugxxibegusnmqebycrpsguap
+npstekcolsopyhbnsthtschngpsteppeseesoadwcaibraesvsrhiireediprikvrcrlpydniapisenbibanaoicarlyagrflsss
+epksewpfsbkymacinimincislpsvsvyifxrpaotoirdfzmtoreoomharntseseltiuazaeeslrxarebiajdahvalaslprnoarbez
+soeykbongothistlektasssiidsregsleaiarlreogaiweevilggwznttagrwniaiddroasiioemsoinsaepnnavtrnadidllucs
+illoloverwhelmednilnicneegeetcndjasdmduvrchpnnrfzlurdloarnasenilesabemtdtulestkxuiepctesaerrigdekiup
+rpriyewmjoqxltmivbalqnrigdnglcniinfdamavaoitsgrskseaeyipikliserpcrtheoryysabushnolreerilpedknniesohw
+oproponentsmetliekacotroinaoltrenlinnsidutbgrelrucqpgetgemdklciportosipuaegamitgeplpyautgefegoniarcu
+ecaudalyokelrsttynoiifilipiklstsrrtftaenvoyeuristichnludtaqbgsewinngnirabrergentuleaugsnofgdfrgdlibd
+hahconfigurationontntzghhtomrbtoteorfsgyguostsefninyoranpsaqtllumsaqodnbecrbdysseoluetatzxpdwhesieee
+tpalsygrarcdeobivcsrscinapbtmanirsfmeuliuqnartodayebracpnneowyuaplncaninevnegxeduynrargueuieatllgngp
+ixfleshyukesedteemeueruptingtahmlhirugmvrccontrastedhbehugniblpsueiayamsidadinrealahrenyyrrntcwantoy
+fefmyoginsnnearnisieripenessjedsmethelnaabsromalgtentrrxnilrkgmjlemigfieryedopiwvttanwiafhnisrsseeth
+nonhumanvcknnsnteayuemsncupolargiitapthigreideewosireipieirnooaespoanrcbqygkemwlfieefhdwsppehwmubdkw
+bywordswjtosiohmetlestnemegagnedlnstcontyanlaprimessnbmshockerhleydesseheotossealraodauaascpraardpga
+outlastedtaocsbbcrxmgjeenilefileeavgotsiulrfordssgtrsettautnessbdebbadieilppfurvpopwylleemnsiuoelksg
+ddetsyrtemntalngnpwesuccocddyplqppdeisifmrlpimplyntzecggndsuitcaseskarksnflomdtnekrahecsuetsawfpnpcn
+iawaitssbskoedamenelphzijeuhauwpieudrvzvennerraytudtcpasbsencactlocnrcaltifsretaehccsrnempollenagtii
+essertsimdaehrsciagdrphststrcocrnvstesidiayejswheosedmerqhhltviuakacooksussocondoretsaocnofktptdnnls
+ssrettabiesarptgciideyhitaeidodohbvcynenmsncoesiqyvgvrcuaxauclbcearhgiyhladhniblebiluncraakussenioli
+retsimdtluweoolrssfaajxsendnszehoqaxoeesgdtpmoppetsgueeuamoseyumcyganhtlaibeodetoormoisterpejltolial
+sbtrsyhbbdtprleinmtddesrtaetjhpilusrlrtdssoqderunettceirlteslhcsneofisxaenssregnifrettubudnodgasbtha
+sfeergalebiamfsnouieiobattlaebebeicbdweejrruostolgpozsorslslvleiodefdrietvdniqtadjectivesswdrfgeaapr
+widrisitultscrbdccninelelipahgnimeqeisldpjierweqianeubcetoiwsbikcusenerqniiceslaysxrpbmcedunupagnrnt
+fcclimocleiasoaegsgignduearteudtutolkjugambolbnsrvyibvoxrerniipmupfdetezmysaatrcmpeatoaarfetmftaeuqn
+okideokoslbcewnrxnrsospsnsszreeifelatrinemsnxnaeieeetbcsiurvgiesolqsrtcjyrlinaujstelsneqcpatceeyypte
+owdmmeldeargisiraeipeatsenyecsnvfriilatticeworkndlrfesgnihsalpslagfosuunsprlvarnucjotkptardslassgpcc
+tryltdndlgeehysamtuhtlcsoitmpscelcascadinghlsiceasiyrseovexeditsnghfshpaslpuadicsoasislliiumtocsguie
+wynifnpseydscetdsofacyyiledfiqelihslanifbstslewrevevrycvygetxrhipnestsetoahdstaupsetxneascaearjmisvd
+euamraessliuraeicccecnttmstneroynlstodopolansonsadetieeoinoeoeouwiegarrubqyaitovtdeposittdaatnarwael
+apmeitrrussrarrazqaaraiosgypgbgagsgieunuteworpwartrnmcbrfdcoddsihrpnbearlusddlltpoesyrrtjsyljalwtghe
+rpisasmtoutgidqlsuilctnlgnabiopsyngnbilacwsiibgepeiogstutfnheescseiimptaweiecoaegesdeuyuyfeynominees
+aictrsiarorerromgdiipoirfiwgnilratsnibuohortcgnisaefzedrtslrreylcknlooelahckasrvregisdraeslatheriwhr
+yekopuspalirtuneenfmresmonbslartueneiloqebeakoihstlhirruqapaptaaonilculirskrsqtnnsntaarttdetcartsbao
+bsenobsrclcyamnmeiphrpleenufdeniapeptllnsvkvslkyamymceufsrmawussraneonasdaiutdylsasetmaeacanoesroefm
+ruoejoioeatwptmrtkcaarqtgestappinggprodosicahfnmolimiydflecugtudihgvocieiunlerugpshietetniksgipdntmn
+flierrooicsrliacagunfirejpwhimsdphaatngrreucasueufnrmnilisihiduinnlibetdnqgerfoceaodidsdewotwokrgals
+latconnmtfoessepaimedcsatdeducesddshsvvaunfxnsrnvgszkugiettgdldtgrqnhqykgdnawnekrnilseisnoopingisgil
+obmibsssylasirralfpameeviecerggeesemrbegecuebvtstoadspynveaelmhdiresonantgtanaugseitiiruolevtizfreao
+uppgdarnsspegnicieersylbatonarpgfhrsodomychaiserelbmuhvgrtnsstseebedliwmoqlarpobncmpryenrapturetertv
+tvawrdzsponccwtfsrnclennutrcainoaapnbhodepbfrolicsaktziuogrosseforpqfdbrazzesbolaopaneseifidocselgee
+vesjeegvojmooeoeslsthukexwudrarnwanxlkestjacvhscgliatesrohcqsdellennekgiqnslueafsalbtkncttclawsrigrn
+ozpbdbycrenekrsindekyasascetredsdodislbrejlrstgocnobscuredhhabsecurerechaliconsfnciacesixcoupledoanl
+tlmeicsihqmaximaltedynnwsdstssldoemtiebeedmdnbnngvgnippohcaeetsmespodtfmesosdnesjaloperpetuatingbosi
+eegggclassroomssniiralitlpsspsewbidtlelpduyedoicsgumgwfswdnmgfotopaetnrtvlsmovrnsfhfsmpilingcppuiafe
+dahhjnprnhwepecnarpeetixyeeredsrtezeredeldmdepkrnmnpqfgsiucsunneaegsueotisaiecreisueyirknittingsbdbr
+rtyeenickinglfygenlxrdigwsievneetfcevthaeeolnaceoiwispsenmedeielgrwblmncertrntdxsibdpsaostokenismdad
+aeedlafgiuigoarnccgezonchnnlktihttfiasllggalwqitcpcencrpttmteldnnutixisbkiilhgeamyseprzkmrhnmldneild
+tvwkibpeatnhwlozifgiigdugtwoafglrtrwizsnwpaiauleaencrorpoaaekiueoissoaihdszanryognhkaaeccceuyegcehad
+ifaitnmsephymsvstaxfstrqhlowziiirdendhiornplpesyecbeboigarxcrldhtslpgrnahswasitsraiortdemysvtjaindne
+berlyinacaepaeateliyortuetlclofnsirrdrooerleystfdcvlvuytireypiiaidamcyrlessdnoluvyzpcsggsidaimraoect
+unloijrerrrcnssacsetuoaaccbpdymciuakfdpreuegatsopasetznlapsnirnmfkzsztynctrgratoeectsoainarepnrmrbet
+tgibpsridceottensigittnrntnalaesfsnnseysworddcgtlrdedoygstrlrnggisimxaoinoscvrcharsapcngmesiamnmkkdu
+tnkyeuejuuselpscatelhdaaarlegabnaeimriohkinderouaydplerylksleegheueevtteleaeezzaipddpismnmntfgfowcsp
+eietdrimpqankffhpyaietgntwtyrbusesgallivantsdyicelxuydpunerjuyttdysinadlcrovejtloeeitsludgeuijnrcipt
+rbredgyperimusoejsrbayetimikesplkdebrutrepnumnbrklwmbanpserahfosmtdimieiscovsrdrvtyraomissluafioisiu
+nbisluelornaaorsteoastrireitliugselttitndxadgsweiufpreiiadmsbnemilqgcrtrnsiepeclrrapteswovasidfvcgro
+uupceraowdyedtgtstulteoneucertsicitnamoraincoatkubfearedkhayyeutycacyclhwlgrcjoeematrvilvendedaeisin
+trxrmgmsinimefestaniridihueiokfkdedutingamsnoynacqndecayswceagdoarakagcelniesvsndwomagpinupjyrlfdntd
+sgeosdrenblurbscaldahomnnoncncimonoxatkineticrseqorhnarksokurlsqplrreteaiheeeerepwrylykpdtubesuerogi
+qmsaesuohdraugzuiecvemsgigtycnangiopatawdrieroawjsonscallopedsesiwpratstclfddoiastelfaelihbumblersru
+itekrandomisessvrraayrgripestsivitcellocsbawsshapeliestmjgnitontoofhylluftsaobwsocilacidlocatedlrsee
+aberrant
+aberrant
+aboriginals
+abound
+absently
+abstracted
+accidents
+accountability
+accreditation
+achieve
+acidly
+acrostic
+actionable
+activist
+acute
+adapter
+addle
+adjective
+adjourned
+adjudges
+adjurations
+adjuring
+adorns
+adulterating
+aerial
+aerodynamics
+aesthetics
+aflame
+afternoons
+agates
+aggregate
+aggrieving
+agings
+agrarians
+aimed
+airlines
+airmailed
+alderman
+align
+alive
+allergy
+allusive
+along
+aloof
+alternate
+alumni
+amalgamate
+ambiguously
+ambition
+ambles
+amends
+amity
+amongst
+amorously
+ampule
+analgesia
+angular
+anions
+antennae
+antimatter
+antipastos
+antiperspirants
+antiseptic
+antitoxins
+aplenty
+applications
+appropriated
+approximate
+arcade
+archdeacon
+argosy
+aristocrat
+armed
+armful
+around
+ascetic
+aspiring
+asset
+assumed
+assurance
+atelier
+atheist
+atrophies
+attenuation
+attire
+auction
+audacious
+augustest
+automates
+availability
+avenger
+avidly
+awaits
+awarding
+awkwardest
+babbles
+babies
+backhand
+backslide
+backtracked
+bacterium
+bagel
+balanced
+baldest
+balling
+balmy
+balsa
+banister
+banjoes
+banks
+barbed
+barbeques
+bards
+bareback
+barge
+baring
+barley
+barrister
+baselines
+baseness
+basil
+basting
+bathe
+batter
+baulk
+bawling
+beatify
+bedfellows
+beetles
+befogs
+begot
+belches
+belief
+belladonna
+bells
+bemoaned
+bench
+benchmarks
+benefitted
+bereavements
+bereft
+bestrid
+bestride
+betaken
+bethinks
+bewitches
+biased
+biassing
+bicycles
+biennials
+bight
+billowing
+bimbo
+binging
+biopsy
+biotechnology
+birdie
+birthright
+bisexual
+bitingly
+blackguards
+blanched
+blankest
+blasphemes
+bleeder
+blithely
+bloods
+blown
+blundering
+blurb
+blurt
+boards
+boastfully
+boatswain
+bodies
+bodkins
+boilers
+bombardment
+bongo
+bookkeeper
+boorishly
+booties
+bordered
+bossy
+botches
+bothers
+bottles
+bottomless
+boughs
+bowels
+braggers
+brasher
+bravery
+break
+breaststrokes
+breathy
+breech
+breeding
+brier
+brigands
+brink
+brisket
+broncho
+brooms
+brought
+brownest
+bruise
+bucket
+buckskins
+bucolic
+budging
+buggers
+bulks
+bulldozer
+bully
+bumblers
+bunglers
+bungles
+burrows
+bursitis
+busily
+busybodies
+butterfingers
+butternuts
+buttocks
+bywords
+cabals
+cactus
+cadavers
+cadge
+caftan
+caged
+caked
+calcium
+calicos
+callously
+calms
+cameraman
+cancelled
+candidacy
+canine
+canister
+cannot
+canoes
+canyons
+capitalise
+caramel
+caressed
+cargoes
+carousel
+carouser
+cascading
+caster
+castigate
+castigator
+catalogued
+catapult
+catcall
+caudal
+cellist
+certifications
+chaffed
+chainsaws
+chairwomen
+chaise
+chance
+chancels
+chanty
+chapped
+chaps
+charge
+chars
+chastisements
+chauvinism
+cheaper
+cheaters
+cheers
+cheques
+chiefs
+chiffon
+chimaera
+chime
+chirp
+choir
+chopping
+chores
+christen
+chromes
+chronometer
+cistern
+citadels
+civet
+civilises
+clacks
+clamours
+clapped
+clarified
+classier
+classrooms
+claws
+cleanse
+clearinghouse
+clicked
+climaxing
+clincher
+clinging
+clocking
+clocks
+clung
+clutch
+coalesced
+coaster
+coccus
+codding
+codifies
+coevals
+coexisted
+coldest
+collar
+collectivists
+colonialist
+colors
+comatose
+combats
+commandeered
+commas
+commend
+commentator
+complains
+completing
+complimenting
+compromise
+conceal
+concertinaed
+conciliated
+concluding
+concordant
+concourse
+concrete
+condemns
+condor
+confide
+configuration
+confining
+confront
+congaed
+congesting
+congregates
+conjunctive
+connection
+conniver
+conscience
+consortia
+constellation
+constructing
+contaminate
+contested
+contrasted
+controllable
+contumacious
+contuses
+conversions
+convicts
+convinces
+cooper
+copulate
+copyrighted
+cords
+corked
+corms
+corpse
+costars
+costliest
+cotyledon
+coupled
+coupon
+courtships
+coves
+covets
+cowbirds
+crafty
+cranial
+crated
+crater
+crayfishes
+crazy
+credenza
+creeks
+cremate
+crewed
+crier
+crispier
+croak
+croupy
+cruet
+cubic
+culling
+cupola
+curdles
+curdling
+curfews
+curiosity
+curler
+custard
+customers
+cutesiest
+cutoffs
+cycled
+dabbed
+daguerreotype
+daiquiri
+daisy
+dallying
+damming
+damps
+dandies
+dandled
+dangling
+dapperest
+darns
+dazed
+deacon
+deadpanning
+dears
+deathblow
+deaths
+debarks
+debauches
+decamping
+decay
+decentralising
+decoded
+decree
+deduces
+deductibles
+deeming
+defecation
+defender
+deformity
+delayed
+delis
+deludes
+demagnetises
+denotes
+dentures
+denying
+dependence
+dependent
+deploys
+deposit
+deposition
+deputy
+desecrate
+desensitised
+deserted
+despot
+detect
+detox
+deviated
+devised
+devolved
+devotees
+devour
+devours
+dictated
+dictatorial
+differently
+diffusing
+dimensional
+diminuendo
+dinned
+direst
+dirtying
+disable
+disassociating
+disavows
+discolor
+disconnecting
+discontentedly
+discontents
+discrimination
+discursive
+discusses
+disgruntled
+dishonor
+disillusioning
+disinherit
+dismal
+dismay
+disowns
+disparages
+disparaging
+displays
+displease
+disported
+dispossessed
+disprove
+disrobing
+dissimulates
+distrusts
+divesting
+divulged
+divvied
+dogged
+dogies
+dogtrot
+dogwoods
+dominant
+dosed
+dosing
+doted
+douche
+downstage
+dowsed
+draft
+drape
+drawn
+drenches
+driblet
+drifter
+drivel
+drollery
+dross
+drowsy
+duding
+dulls
+dusts
+dynamic
+dynamism
+eager
+eardrum
+earnings
+eastern
+echelons
+editorial
+educates
+effusion
+egalitarians
+egotist
+eighteenths
+electrifies
+electrify
+electrolyte
+elevated
+elides
+elsewhere
+elucidated
+embarrassingly
+embed
+embezzle
+emery
+empty
+enabled
+enabling
+encrusts
+endless
+endow
+enemy
+enervating
+engagement
+engineers
+engorged
+enjoyable
+enlists
+enquired
+enrapture
+entertains
+entreat
+entreaties
+epaulette
+epiglottises
+epitaphs
+epoxies
+equability
+equivocated
+eradicating
+erupting
+escape
+estranged
+evacuates
+evades
+evict
+evidenced
+examiners
+excavations
+exceptionable
+excruciatingly
+excursion
+executing
+executives
+exertions
+exited
+expectorant
+expectorates
+expend
+expense
+expire
+explicated
+exploitative
+expostulates
+expressive
+extemporised
+extincted
+extort
+extraction
+extraditions
+eyetooth
+fabled
+fabricates
+facades
+facet
+facilitate
+facts
+faeces
+fagots
+fainted
+fairies
+faithless
+falsest
+falsifying
+falsity
+fanny
+fasten
+faulted
+faunas
+favored
+fazes
+fealty
+feared
+feedings
+feinting
+feminism
+fettle
+feverishly
+fewest
+fiery
+fiestas
+finals
+finch
+finis
+finked
+firewalls
+firsthand
+fitted
+fixers
+flaps
+flashed
+flashers
+flattery
+fleeced
+fleshy
+flier
+flinching
+flings
+flippest
+floating
+florae
+flour
+fluidly
+fluke
+flummox
+fluxing
+foams
+foamy
+fogeys
+folds
+foolishness
+footnoting
+footwear
+foppish
+forbearing
+fords
+forebodes
+forefront
+foreordained
+fores
+forge
+forgetful
+fouler
+fountainheads
+fractures
+frankfurter
+fraternises
+fraud
+freaky
+freeman
+freestyles
+freighter
+friar
+fried
+friends
+friendship
+fries
+frigid
+frillier
+frills
+frippery
+frolics
+frosty
+frowsy
+frugality
+fruiting
+fruits
+fryer
+fucker
+fuddled
+fulminated
+fumbled
+funnel
+funner
+funniness
+furious
+furriest
+fused
+gabardines
+gadabout
+gages
+galleons
+gallivants
+gambol
+gamete
+gamines
+gaping
+gardens
+garnet
+garoted
+garret
+gashing
+gasket
+gawkiest
+gawkily
+gecko
+genome
+genre
+gentle
+gentled
+geographers
+getup
+gewgaw
+gibber
+gifting
+gimlets
+gimme
+gingersnap
+gingivitis
+girdle
+girds
+gladdened
+glade
+glades
+glamors
+glances
+glider
+glitches
+glues
+glyph
+goals
+goblets
+golfs
+gonna
+gopher
+grace
+graded
+gratefully
+gravestone
+great
+greenish
+greenness
+greyish
+griming
+grimy
+grinder
+grinned
+gripes
+grovels
+growling
+growls
+grubbing
+gruesomer
+grumpier
+guardhouse
+guess
+guild
+guiltier
+gummy
+gunfire
+guying
+gybes
+haggle
+hairdo
+hairstylists
+halfpence
+haloed
+halves
+handbooks
+handcar
+handiest
+handmaiden
+handspring
+hankering
+happen
+harem
+harken
+harming
+hasps
+hatch
+havoc
+headhunter
+headmistress
+headway
+heady
+heaps
+hearsay
+hearses
+heaving
+height
+heliotropes
+hellhole
+helmets
+hereabout
+heroins
+hideouts
+hikers
+hills
+hinterland
+hisses
+hitch
+hitches
+hoarseness
+hobnobs
+hokiest
+holiday
+homegrown
+homesteading
+honester
+honking
+hooks
+hopscotches
+horns
+horseshoeing
+horsetail
+hospital
+hugest
+hugged
+humanity
+humbleness
+humbler
+hunch
+hydroponics
+hying
+hymens
+hyped
+hypersensitivities
+hypertext
+hypos
+iambs
+icing
+identified
+idlers
+ikons
+illicit
+immediacy
+immerses
+immobile
+impalas
+implementing
+imprecations
+impregnable
+impresarios
+impresarios
+impulse
+incises
+incubus
+indigents
+industrialised
+inertia
+infests
+infinitesimally
+informational
+infractions
+infringements
+infusion
+inhere
+inheritance
+inimitable
+input
+inseam
+insight
+insists
+instalment
+institution
+insufficiency
+insulation
+insulted
+intent
+intercede
+intercepts
+interconnect
+interference
+interfering
+interlinking
+intermarries
+interpolated
+interpose
+intones
+inveighing
+invent
+inventors
+inverses
+irons
+irradiates
+irreparably
+irrevocable
+isotropic
+itched
+jabbed
+jaguar
+japans
+jeeps
+jellying
+jewelry
+jibbing
+jibed
+jinnis
+jiving
+jobbing
+jokes
+jolted
+jovially
+joyrode
+junket
+juntas
+juvenile
+keepsakes
+kennelled
+keynotes
+khaki
+khakis
+kilobytes
+kinder
+kindles
+kinetic
+kitty
+kneel
+knifed
+knits
+knitting
+knuckles
+koshered
+kowtowed
+krone
+laborious
+laced
+ladling
+laity
+landmark
+lapidaries
+lather
+latrine
+latticework
+laughingstock
+laughter
+lavisher
+lawfulness
+laymen
+lazes
+lazied
+lazies
+leaflets
+leaves
+lessors
+letter
+levee
+libel
+liefest
+lifeline
+likes
+limbo
+limed
+limestone
+limit
+limping
+liner
+lithography
+liveries
+llanos
+loath
+lobby
+located
+lockets
+loftiest
+lollipops
+longish
+loony
+lotto
+loveliness
+loves
+lurked
+lusted
+lyrical
+mackintosh
+magisterial
+magnitude
+magnolias
+mails
+mainlined
+makeups
+malarial
+mammas
+mandrill
+manifestoes
+marchers
+mares
+markedly
+martinis
+martins
+masques
+masterpieces
+matchbox
+maternally
+mathematically
+matrons
+mausoleum
+maximal
+mayhem
+meadowlark
+mealy
+medias
+mediator
+medicated
+meekly
+mellowest
+melodically
+melon
+mental
+mentioned
+meringues
+merinos
+messiahs
+metacarpus
+metastasis
+meteorological
+methodologies
+metres
+midriffs
+miked
+mikes
+miller
+mills
+mined
+minicam
+minuends
+mirror
+mirth
+misadventure
+mischief
+misgivings
+misinforms
+misread
+missile
+missives
+mister
+mistime
+mitre
+mitten
+mixer
+mocks
+modal
+moiety
+moister
+moisturising
+molasses
+moleskin
+molested
+monarchic
+monetarily
+monopolised
+monthlies
+mooning
+mooted
+moppets
+morbid
+mornings
+morsel
+mortgage
+motels
+mothballing
+motherboard
+motionless
+motorcars
+moused
+mouths
+movable
+movers
+muffling
+mullahs
+multiplexers
+multiplexes
+mummers
+muralists
+musicians
+musings
+mussel
+mussiest
+mutate
+myopia
+nagged
+naively
+nakedly
+nanny
+napalming
+narks
+narrated
+nasal
+nationalising
+naturalised
+nearby
+neglect
+nerds
+nestle
+neutrals
+newsletters
+nicking
+nicotine
+niece
+nightmare
+noddy
+noisily
+nominees
+nonhuman
+nonplused
+nosegays
+notably
+notified
+noughts
+novelties
+nuncio
+nurse
+nurture
+nutmegs
+oasis
+obeyed
+obeys
+object
+obliges
+obscured
+obscures
+obsequiousness
+obsequy
+occupation
+oceans
+octal
+oddest
+okayed
+onomatopoeia
+onsets
+opaques
+operation
+opinion
+oppressor
+orals
+orated
+orations
+oriented
+ornery
+osteopaths
+ostracism
+ouster
+outcomes
+outdistances
+outlasted
+outlaws
+outputted
+outrageously
+outsmarted
+outvoted
+overcrowded
+overlain
+overland
+overnights
+overrules
+overtakes
+overturns
+overwhelmed
+owned
+oxbows
+oxygenates
+oyster
+padded
+paging
+pained
+paled
+pales
+palliate
+palsy
+panic
+panier
+pantaloons
+panted
+parallels
+parameter
+parental
+parked
+parsley
+partner
+passions
+pasting
+patina
+patriarchies
+pauses
+pawned
+pawpaw
+paymasters
+peacock
+pearlier
+peccary
+pecked
+peculiarities
+peddle
+pediments
+pedometer
+peewee
+pelagic
+pellagra
+pencil
+penning
+peppery
+percussionist
+permissions
+perpetuating
+perspiration
+perusals
+petiole
+phallic
+philander
+phoneying
+physicking
+physics
+pianos
+piazza
+piazze
+picks
+piece
+pigskin
+pilaf
+piling
+piloting
+pimply
+pineapple
+pinhole
+pining
+pinned
+pinup
+piton
+pizazz
+placarding
+placket
+plane
+planked
+plaque
+plateful
+players
+plexuses
+plighted
+ploddings
+plopped
+plowman
+plummeting
+plunge
+plusher
+pocketbook
+poesy
+poetical
+poignancy
+point
+poised
+poked
+pokey
+pollen
+poltergeists
+poltroons
+polyp
+poplin
+popularising
+popularity
+pornographers
+portico
+portraying
+postage
+postcard
+potion
+potter
+pounce
+pounding
+practices
+practised
+pragmatic
+prance
+prancer
+prawning
+prearrange
+precautionary
+preceding
+preceptor
+precipice
+preps
+presage
+price
+priests
+primes
+prodding
+professor
+profitably
+prohibitionists
+prohibitively
+promulgating
+pronged
+propane
+propellers
+proper
+properties
+proponents
+proposals
+propulsion
+protestors
+protrusion
+proves
+prowl
+prudery
+psalmist
+pukes
+puking
+pullbacks
+pumice
+pumped
+punchiest
+purebreds
+purulence
+puzzles
+qualifier
+quarantining
+quartette
+quash
+querying
+quieter
+quiets
+quirkier
+quoit
+rabbinate
+raceway
+racism
+radial
+radiant
+rafts
+ragamuffin
+raged
+raiment
+raincoat
+rajahs
+raked
+rambunctiousness
+ramming
+randomises
+rapids
+raptures
+rasps
+ratchet
+ratified
+ravel
+raves
+ravings
+rawer
+razed
+razzes
+reads
+realise
+realising
+rebut
+receive
+recliner
+recompenses
+reconnected
+reconnoiters
+recreation
+rectifications
+recuperate
+redirected
+redistricts
+redoing
+redundant
+reedy
+reefs
+reforests
+refuels
+regale
+regally
+regularly
+rehabbed
+rehearsed
+reigns
+reimbursed
+reindeers
+reinterpreting
+reinvents
+reissues
+reiterates
+relabel
+relates
+remake
+remunerated
+renal
+rending
+rends
+rents
+reoccur
+reopened
+repackage
+repatriate
+repeal
+repealed
+reprobates
+reproduce
+reproducing
+rereads
+resells
+resemble
+resistance
+resolved
+resonant
+retail
+retardants
+retards
+retching
+retreading
+retrieved
+retrievers
+return
+revalues
+revaluing
+reviling
+revised
+reward
+rewires
+rewrote
+rhapsodised
+ricing
+ricksha
+ridiculousness
+rightful
+ripeness
+riskiest
+rivalled
+robbers
+robotics
+rogue
+rolls
+romanticist
+rooted
+rosebuds
+rotting
+roundups
+rouses
+routs
+roving
+royal
+ruffling
+rugby
+rummaging
+runner
+rusks
+rusted
+rustlers
+sabbatical
+saboteurs
+sacerdotal
+sachets
+sacrificed
+sages
+sandhog
+sandiest
+sashes
+satellited
+sauna
+sauntering
+savager
+savories
+savory
+savouries
+savoury
+sawed
+sayings
+scabbiest
+scald
+scale
+scalloped
+scalpel
+scandalised
+scanting
+scants
+scarabs
+scenic
+schlock
+scholar
+scholarship
+scofflaw
+scoops
+scored
+scoring
+scoured
+scowled
+scrappy
+screechy
+scribes
+scrolling
+scuffles
+scull
+scums
+sealant
+seaplane
+seasick
+seaway
+securer
+sedans
+sedately
+sedatest
+seeded
+seers
+selfishness
+selflessness
+semen
+seminars
+sensitised
+sentences
+sentient
+septette
+serest
+serum
+setter
+settling
+severing
+sexed
+shabby
+shacks
+shadier
+shakeup
+shameless
+shanghaiing
+shapeliest
+shark
+sheaf
+shearers
+sheepish
+sheikhs
+shepherd
+shied
+shillelagh
+shirred
+shittiest
+shocker
+shockingly
+shocks
+shoos
+shortens
+shorting
+shovelling
+showdowns
+showiest
+shrew
+shriller
+shuck
+shutters
+sibyl
+sickbed
+sidelights
+sierra
+sighted
+sighting
+signalise
+sillier
+silted
+simmering
+simplification
+singsonged
+sisterhoods
+sketches
+sketchiest
+skews
+skylight
+slashed
+slavish
+slays
+sleepless
+sleepy
+slicking
+sliders
+slink
+slovenlier
+sluttish
+smeared
+smelly
+smirk
+smoked
+smoldered
+smudgier
+snacks
+snaky
+snappiest
+snifters
+snippet
+snivelling
+snobbish
+snooping
+snuff
+soakings
+soaped
+sobbing
+sodomy
+softly
+softness
+sogginess
+solar
+solemnises
+solicitors
+solidifies
+solutions
+songs
+sophists
+sophomoric
+sounded
+southeast
+spacy
+spanning
+speckle
+spines
+spirit
+spitted
+splashing
+splices
+splines
+split
+splits
+splotched
+spoonbill
+sporting
+spotlighted
+sprats
+spreading
+spumone
+squared
+squashed
+squashiest
+squeeze
+squirms
+squirmy
+stabling
+stair
+stalks
+stanchest
+stand
+stank
+starling
+starter
+starved
+stationing
+staunchly
+steeds
+stencilled
+steppes
+stepson
+sterilised
+stiffed
+stiffening
+stigmatising
+stilettos
+stilled
+stoic
+stoniest
+stores
+stout
+straightaway
+straw
+streetcar
+strikeout
+striped
+stripteases
+striving
+stroll
+strongly
+structural
+strumpet
+studies
+studiously
+styes
+styles
+stymie
+subbing
+subcontractors
+subjoining
+sublime
+suborns
+subscribers
+subway
+sudden
+sugaring
+suitcase
+sulfurous
+sumps
+sunnier
+supercharger
+superficial
+suppuration
+surfaced
+surgery
+surgical
+surpass
+surplused
+suspecting
+swabs
+swanked
+swarms
+swashbucklers
+swathes
+sweeper
+sweet
+swirly
+swisher
+switchback
+switcher
+swoon
+swordsmen
+synching
+syringed
+table
+tabled
+tacos
+talkative
+tamales
+tames
+tanager
+tango
+tapping
+taprooms
+tarpon
+tarry
+tarts
+tasted
+taupe
+tautness
+tawdrier
+taxonomic
+taxying
+teapot
+tearoom
+techs
+tedious
+tedium
+teeming
+teepees
+telegraphing
+telephonic
+telexed
+tempest
+tempts
+tenderfeet
+tenured
+terminable
+terrapins
+terrarium
+territorials
+terrorists
+thaws
+theirs
+theorise
+theory
+thickset
+thirsted
+thirsts
+thistle
+thoughtfulness
+thoughtlessness
+threatened
+threshes
+thrive
+thronged
+thronging
+throttles
+throwback
+thrust
+thundered
+thunders
+thymuses
+tiebreaker
+tiled
+tinges
+tinsmiths
+tipplers
+tipples
+tipsiest
+tipsily
+tittles
+toads
+today
+togae
+toggle
+tokenism
+tolling
+toolbar
+topside
+torpedoing
+torso
+tortes
+tortoiseshell
+torus
+totally
+toupees
+towel
+track
+traducing
+tragicomedies
+trample
+tranquil
+tranquilest
+transducers
+transformed
+transited
+transposes
+treadle
+treasonous
+tribe
+trimming
+trivialises
+troika
+trots
+trunking
+trustworthier
+trysted
+trysts
+tubeless
+tubes
+tulip
+tulle
+tumbler
+tuneful
+tunnel
+turbojets
+turnkey
+turtledove
+tusked
+tweak
+tweeted
+twerp
+twigged
+twiggier
+twiggy
+twilight
+twill
+twittered
+tykes
+typed
+typewriter
+tyrannises
+tyrannosaurus
+ukuleles
+unable
+unclasping
+uncles
+uncut
+undaunted
+undemocratic
+undergrowth
+undresses
+unearths
+unfurnished
+universe
+unperturbed
+unplumbed
+unproved
+unreasoning
+unrolling
+unscramble
+unstressed
+unsupervised
+unthinkingly
+unwanted
+uplifts
+uppermost
+uprisings
+upset
+upside
+urbanising
+ushers
+utensils
+uvulas
+vacationer
+valence
+valid
+valise
+valueless
+veils
+velour
+vended
+verbalises
+veterinary
+vexed
+vexes
+vibes
+vibrated
+viburnum
+villager
+villainous
+villas
+virgins
+visas
+visitations
+vitiation
+vogue
+voiced
+volunteers
+voyeuristic
+waddling
+wagers
+wails
+wainscotting
+waistband
+waive
+walkways
+wallpaper
+wanner
+warding
+warlike
+warlocks
+warrantied
+warrants
+washbowls
+waste
+watched
+waterbed
+watering
+waylay
+waywardness
+weaken
+weaker
+wedged
+weedier
+weedy
+weepies
+weevil
+westward
+whaler
+wharf
+whims
+whinnied
+whorehouses
+whose
+wider
+wight
+wildcatting
+wildebeests
+wiling
+windstorms
+wines
+wingtips
+wired
+wises
+wispiest
+wisps
+woman
+wonderfully
+wonderment
+woodpeckers
+woodsy
+woofs
+wordiness
+worldly
+worsening
+worthiest
+wraith
+wrapped
+wrapper
+wrathful
+wreckers
+writs
+wryly
+wryness
+xenon
+yakked
+yogins
+yokel
+youngest
+yuckiest
+yummy
+yuppies
+zebra
+zigzagged
+zings
+zippering
+zither
+zithers
+zoology
+zygotes
\ No newline at end of file
index 5259725cf255bb5f24b620c8e193f345f7461dc4..52cbbdcd082588912156d2fc10432f92ed6e6f64 100644 (file)
@@ -2,8 +2,10 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {},
+   "execution_count": 206,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "import string\n",
@@ -11,6 +13,9 @@
     "import random\n",
     "import collections\n",
     "import copy\n",
+    "import os\n",
+    "\n",
+    "from IPython.display import clear_output\n",
     "\n",
     "from enum import Enum\n",
     "Direction = Enum('Direction', 'left right up down upleft upright downleft downright')\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
-   "metadata": {},
+   "execution_count": 180,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "# all_words = [w.strip() for w in open('/usr/share/dict/british-english').readlines()\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
-   "metadata": {},
+   "execution_count": 181,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "# ws_words = [w.strip() for w in open('wordsearch-words').readlines()\n",
@@ -51,7 +60,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 182,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 183,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "62183"
+      ]
+     },
+     "execution_count": 183,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len([w for w in ws_words if len(w) >= 4])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 184,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 185,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 186,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 187,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 188,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 10,
+   "execution_count": 189,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 11,
+   "execution_count": 190,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 12,
+   "execution_count": 191,
    "metadata": {},
    "outputs": [
     {
        "'..e.....'"
       ]
      },
-     "execution_count": 12,
+     "execution_count": 191,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 192,
    "metadata": {},
    "outputs": [
     {
        "<_sre.SRE_Match object; span=(0, 4), match='keen'>"
       ]
      },
-     "execution_count": 13,
+     "execution_count": 192,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": 193,
    "metadata": {},
    "outputs": [
     {
        "<_sre.SRE_Match object; span=(0, 3), match='kee'>"
       ]
      },
-     "execution_count": 14,
+     "execution_count": 193,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 15,
-   "metadata": {},
+   "execution_count": 194,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "re.fullmatch(cat(gslice(grid, 3, 2, 3, Direction.right)), 'keen')"
   },
   {
    "cell_type": "code",
-   "execution_count": 16,
+   "execution_count": 195,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 196,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 197,
    "metadata": {},
    "outputs": [
     {
        "<_sre.SRE_Match object; span=(0, 4), match='keen'>"
       ]
      },
-     "execution_count": 18,
+     "execution_count": 197,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
-   "metadata": {},
+   "execution_count": 198,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "could_add(grid, 3, 2, Direction.right, 'kine')"
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 199,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "<Direction.right: 2>"
+       "<Direction.up: 3>"
       ]
      },
-     "execution_count": 20,
+     "execution_count": 199,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 58,
+   "execution_count": 207,
    "metadata": {
     "collapsed": true
    },
    "outputs": [],
    "source": [
-    "def fill_grid(grid, words, word_count, max_attempts=10000):\n",
+    "def fill_grid(grid, words, word_count, max_attempts=10000, min_word_len=4):\n",
     "    attempts = 0\n",
     "    added_words = []\n",
     "    w = len(grid[0])\n",
     "    h = len(grid)\n",
     "    while len(added_words) < word_count and attempts < max_attempts:\n",
+    "        clear_output(wait=True)\n",
+    "        print(\"Added\", len(added_words), '; attempt', attempts)\n",
     "        attempts += 1\n",
     "        r = random.randrange(w)\n",
     "        c = random.randrange(h)\n",
     "        word = random.choice(words)\n",
     "        d = random.choice(list(Direction))\n",
-    "        if len(word) >=4 and not any(word in w2 for w2 in added_words) and could_add(grid, r, c, d, word):\n",
-    "            set_grid(grid, r, c, d, word)\n",
-    "            added_words += [word]\n",
-    "            attempts = 0\n",
+    "#         print(word, r, c, d, \n",
+    "#               len(word) >= min_word_len, \n",
+    "#               not any(word in w2 for w2 in added_words), \n",
+    "#               could_add(grid, r, c, d, word), \n",
+    "#               not present(grid, word)[0]\n",
+    "#              )\n",
+    "        if (len(word) >= min_word_len\n",
+    "              and not any(word in w2 for w2 in added_words) \n",
+    "              and could_add(grid, r, c, d, word)\n",
+    "              and not present(grid, word)[0]):\n",
+    "            grid2 = copy.deepcopy(grid)\n",
+    "            set_grid(grid2, r, c, d, word)\n",
+    "#             print(present_many(grid2, [word]))\n",
+    "            if collections.Counter(p[0] for p in \n",
+    "                                   present_many(grid2, added_words + [word])).most_common(1)[0][1] == 1:\n",
+    "                set_grid(grid, r, c, d, word)\n",
+    "                added_words += [word]\n",
+    "                attempts = 0\n",
     "    return grid, added_words"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 201,
    "metadata": {},
    "outputs": [
     {
-     "data": {
-      "text/plain": [
-       "40"
-      ]
-     },
-     "execution_count": 22,
-     "metadata": {},
-     "output_type": "execute_result"
+     "ename": "KeyboardInterrupt",
+     "evalue": "",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-201-6ab66457c812>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mempty_grid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m20\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m20\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mws\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfill_grid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mws_words\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m40\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mws\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-200-42497f37ad7f>\u001b[0m in \u001b[0;36mfill_grid\u001b[0;34m(grid, words, word_count, max_attempts, min_word_len)\u001b[0m\n\u001b[1;32m     24\u001b[0m \u001b[0;31m#             print(present_many(grid2, [word]))\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     25\u001b[0m             if collections.Counter(p[0] for p in \n\u001b[0;32m---> 26\u001b[0;31m                                    present_many(grid2, added_words + [word])).most_common(1)[0][1] == 1:\n\u001b[0m\u001b[1;32m     27\u001b[0m                 \u001b[0mset_grid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mword\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     28\u001b[0m                 \u001b[0madded_words\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mword\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-123-ff8574b12cf0>\u001b[0m in \u001b[0;36mpresent_many\u001b[0;34m(grid, words)\u001b[0m\n\u001b[1;32m      8\u001b[0m             \u001b[0;32mfor\u001b[0m \u001b[0md\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mDirection\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      9\u001b[0m                 \u001b[0;32mfor\u001b[0m \u001b[0mwordlen\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mwordlens\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m                     \u001b[0mword\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgslice\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwordlen\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     11\u001b[0m                     \u001b[0;32mif\u001b[0m \u001b[0mword\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mwords\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     12\u001b[0m                         \u001b[0mpresences\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mword\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-188-a5adda74be28>\u001b[0m in \u001b[0;36mgslice\u001b[0;34m(grid, r, c, l, d)\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mgslice\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ml\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m     \u001b[0;32mreturn\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mindices\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ml\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[0;32m<ipython-input-187-e0e67252b972>\u001b[0m in \u001b[0;36mindices\u001b[0;34m(grid, r, c, l, d)\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mdef\u001b[0m \u001b[0mindices\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ml\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m     \u001b[0mdr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdelta\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m     \u001b[0mw\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m     \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrid\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[0minds\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mr\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mdr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mdc\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ml\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
+     ]
     }
    ],
    "source": [
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "..pouchexecrate.....\n",
-      ".hazardous....t.wive\n",
-      "...sniradnam.aselcnu\n",
-      "s.weeklies.rnb......\n",
-      "e..lamenessse.o.....\n",
-      "i.tsallab..s.a.i....\n",
-      "tslim.......f.c.l...\n",
-      "iwheelbase...f.tges.\n",
-      "ed....llabhgihinirr.\n",
-      "dw.limbs..nj.bitev.s\n",
-      "te.wiltediu.ructs.e.\n",
-      "elsombretv.oqes..a..\n",
-      "ll..e..te.iela....m.\n",
-      "ie.a..un.lheleiretoc\n",
-      "ord..bi.scsp...kiths\n",
-      "ts.malcentilitren...\n",
-      "..i.e.sexetrov.stolb\n",
-      ".r.s...ruof....htrof\n",
-      "bgnihsirevopmi.....c\n",
-      "....graciousness....\n",
-      "40 words added\n",
-      "lameness impoverishing plasters wilted toilet forth coterie hazardous abutting chequing weeklies sombre execrate mastiffs boilers uncles centilitre mandarins wheelbase graciousness vortexes dwellers ballast limbs four tans highball wive broils beads mils reactive select deities shtik juveniles blots pouch brim coon\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "print(show_grid(g))\n",
     "print(len(ws), 'words added')\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def present_many(grid, words):\n",
+    "    w = len(grid[0])\n",
+    "    h = len(grid)\n",
+    "    wordlens = set(len(w) for w in words)\n",
+    "    presences = []\n",
+    "    for r in range(h):\n",
+    "        for c in range(w):\n",
+    "            for d in Direction:\n",
+    "                for wordlen in wordlens:\n",
+    "                    word = cat(gslice(grid, r, c, wordlen, d))\n",
+    "                    if word in words:\n",
+    "                        presences += [(word, r, c, d)]\n",
+    "    return set(presences)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "lameness (True, 4, 3, <Direction.right: 2>)\n",
-      "impoverishing (True, 18, 13, <Direction.left: 1>)\n",
-      "plasters (True, 14, 11, <Direction.upright: 6>)\n",
-      "wilted (True, 10, 3, <Direction.right: 2>)\n",
-      "toilet (True, 15, 0, <Direction.up: 3>)\n",
-      "forth (True, 17, 19, <Direction.left: 1>)\n",
-      "coterie (True, 13, 19, <Direction.left: 1>)\n",
-      "hazardous (True, 1, 1, <Direction.right: 2>)\n",
-      "abutting (True, 15, 4, <Direction.upright: 6>)\n",
-      "chequing (True, 14, 9, <Direction.upright: 6>)\n",
-      "weeklies (True, 3, 2, <Direction.right: 2>)\n",
-      "sombre (True, 11, 2, <Direction.right: 2>)\n",
-      "execrate (True, 0, 7, <Direction.right: 2>)\n",
-      "mastiffs (True, 12, 18, <Direction.upleft: 5>)\n",
-      "boilers (True, 3, 13, <Direction.downright: 8>)\n",
-      "uncles (True, 2, 19, <Direction.left: 1>)\n",
-      "centilitre (True, 15, 6, <Direction.right: 2>)\n",
-      "mandarins (True, 2, 11, <Direction.left: 1>)\n",
-      "wheelbase (True, 7, 1, <Direction.right: 2>)\n",
-      "graciousness (True, 19, 4, <Direction.right: 2>)\n",
-      "vortexes (True, 16, 13, <Direction.left: 1>)\n",
-      "dwellers (True, 8, 1, <Direction.down: 4>)\n",
-      "ballast (True, 5, 8, <Direction.left: 1>)\n",
-      "limbs (True, 9, 3, <Direction.right: 2>)\n",
-      "four (True, 17, 10, <Direction.left: 1>)\n",
-      "tans (True, 1, 14, <Direction.downleft: 7>)\n",
-      "highball (True, 8, 13, <Direction.left: 1>)\n",
-      "wive (True, 1, 16, <Direction.right: 2>)\n",
-      "broils (True, 9, 13, <Direction.downleft: 7>)\n",
-      "beads (True, 11, 5, <Direction.downleft: 7>)\n",
-      "mils (True, 6, 4, <Direction.left: 1>)\n",
-      "reactive (True, 3, 11, <Direction.downright: 8>)\n",
-      "select (True, 14, 10, <Direction.upright: 6>)\n",
-      "deities (True, 9, 0, <Direction.up: 3>)\n",
-      "shtik (True, 14, 19, <Direction.left: 1>)\n",
-      "juveniles (True, 9, 11, <Direction.downleft: 7>)\n",
-      "blots (True, 16, 19, <Direction.left: 1>)\n",
-      "pouch (True, 0, 2, <Direction.right: 2>)\n",
-      "brim (True, 18, 0, <Direction.upright: 6>)\n",
-      "coon (True, 18, 19, <Direction.upleft: 5>)\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "for w in ws:\n",
     "    print(w, present(g, w))"
   },
   {
    "cell_type": "code",
-   "execution_count": 47,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 48,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "True"
-      ]
-     },
-     "execution_count": 48,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "interesting(g, ws)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 51,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
    "outputs": [],
    "source": [
-    "def interesting_grid(width=20, height=20, words_limit=40, direction_slack=1):\n",
+    "def interesting_grid(width=20, height=20, words_limit=40, max_words=80, direction_slack=1):\n",
     "    boring = True\n",
     "    while boring:\n",
     "        grid = empty_grid(width, height)\n",
-    "        grid, words = fill_grid(grid, ws_words, 80)\n",
+    "        grid, words = fill_grid(grid, ws_words, max_words)\n",
     "        boring = not interesting(grid, words, words_limit=words_limit, direction_slack=direction_slack)\n",
     "    return grid, words"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 52,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "dexawwt....ybossm..t\n",
-      "snaprhlukulele..o.er\n",
-      "...erioteb.hrevordla\n",
-      "..sivc..pr.tdekcahkp\n",
-      "atve..h.oiselapcy.cd\n",
-      "nesrehpargohtill.pue\n",
-      "n.leaveyis.smuguhhrt\n",
-      "eyhsifnt.r...aeesetc\n",
-      "xverbseebasedlritl.a\n",
-      ".r..k.wie..mdonaiaeg\n",
-      "..ac.nsof.admeeulsoo\n",
-      "g.opo.cmanaotpqiinmp\n",
-      "nc.us.a.lpnteaerdkiu\n",
-      "ionjoys.leirinioicns\n",
-      "wnkcent.skeracllkase\n",
-      "oab..erusopxeao.antt\n",
-      "dureifidimuhed.nskea\n",
-      "aga...capitols..scrl\n",
-      "h.v.sandblaster..i.i\n",
-      "s.e..sdratoelhitsn.d\n",
-      "61 words added;  8 directions\n",
-      "newscast kittenish cocks lithographers truckle leotards they exposure dehumidifier sandblaster alien paddle shadowing gondola wrest joys minster pales chairs fishy capitols based gums pheromones saki moiety waxed guano thriven dilate moray icons adman ukulele hacked rope rise clue acted nicknack spar verbs boss annex neck repeater befalls drover leave pans brave brigs opus live noun tail riot care hits quilt part\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "g, ws = interesting_grid()\n",
     "print(show_grid(g))\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 30,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 31,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 32,
-   "metadata": {},
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "english_counts = collections.Counter(dict(datafile('count_1l.txt')))\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 33,
-   "metadata": {},
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "wordsearch_counts = collections.Counter(cat(ws_words))\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 34,
-   "metadata": {},
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "normalised_wordsearch_counts = normalise(collections.Counter(normalised_wordsearch_counts) + collections.Counter({l: 0.05 for l in string.ascii_lowercase}))"
   },
   {
    "cell_type": "code",
-   "execution_count": 35,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 36,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'aaaaaabbccddeeeeeeeeeeeffggghhhhhhiiiiiiiiillllmmnnnnnnnooooooooooppppqrrrrrrrssstttttttttuuwyyyyyyz'"
-      ]
-     },
-     "execution_count": 36,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "cat(sorted(random_english_letter() for i in range(100)))"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 37,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'aaaaaaaabbbccccddeeeeeeeeggghhhiiiiiiiijjkkllllnnnnoooooooooopppqqrrrrrssssssttttttuuuuvvwxxxxxyzzzz'"
-      ]
-     },
-     "execution_count": 37,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "cat(sorted(random_wordsearch_letter() for i in range(100)))"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 38,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'x'"
-      ]
-     },
-     "execution_count": 38,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "random_wordsearch_letter()"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 39,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 53,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "dexawwtmxepybossmezt\n",
-      "snaprhlukulelefaoder\n",
-      "ijreriotebahrevordla\n",
-      "jrsivcciprstdekcahkp\n",
-      "atvecshkoiselapcydcd\n",
-      "nesrehpargohtilljpue\n",
-      "nuleaveyisasmuguhhrt\n",
-      "eyhsifntzrmnsaeesetc\n",
-      "xverbseebasedlritlla\n",
-      "prcckzwiefamdonaiaeg\n",
-      "osacqnsofgadmeeulsoo\n",
-      "gdoporcmanaotpqiinmp\n",
-      "ncmusbaslpnteaerdkiu\n",
-      "ionjoyswleirinioicns\n",
-      "wnkcentcskeracllkase\n",
-      "oabsuerusopxeaodantt\n",
-      "dureifidimuhedgnskea\n",
-      "agagvccapitolsgyscrl\n",
-      "hkvgsandblasterdhihi\n",
-      "syenesdratoelhitsnod\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "padded = pad_grid(g)\n",
     "print(show_grid(padded))"
   },
   {
    "cell_type": "code",
-   "execution_count": 54,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "dexawwt....ybossm..t\n",
-      "snaprhlukulele..o.er\n",
-      "...erioteb.hrevordla\n",
-      "..sivc..pr.tdekcahkp\n",
-      "atve..h.oiselapcy.cd\n",
-      "nesrehpargohtill.pue\n",
-      "n.leaveyis.smuguhhrt\n",
-      "eyhsifnt.r...aeesetc\n",
-      "xverbseebasedlritl.a\n",
-      ".r..k.wie..mdonaiaeg\n",
-      "..ac.nsof.admeeulsoo\n",
-      "g.opo.cmanaotpqiinmp\n",
-      "nc.us.a.lpnteaerdkiu\n",
-      "ionjoys.leirinioicns\n",
-      "wnkcent.skeracllkase\n",
-      "oab..erusopxeao.antt\n",
-      "dureifidimuhed.nskea\n",
-      "aga...capitols..scrl\n",
-      "h.v.sandblaster..i.i\n",
-      "s.e..sdratoelhitsn.d\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "print(show_grid(g))"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 55,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "newscast (True, 7, 6, <Direction.down: 4>)\n",
-      "kittenish (True, 14, 9, <Direction.upright: 6>)\n",
-      "cocks (True, 12, 1, <Direction.upright: 6>)\n",
-      "lithographers (True, 5, 14, <Direction.left: 1>)\n",
-      "truckle (True, 7, 18, <Direction.up: 3>)\n",
-      "leotards (True, 19, 12, <Direction.left: 1>)\n",
-      "they (True, 3, 11, <Direction.up: 3>)\n",
-      "exposure (True, 15, 12, <Direction.left: 1>)\n",
-      "dehumidifier (True, 16, 13, <Direction.left: 1>)\n",
-      "sandblaster (True, 18, 4, <Direction.right: 2>)\n",
-      "alien (True, 9, 17, <Direction.downleft: 7>)\n",
-      "paddle (True, 12, 9, <Direction.upright: 6>)\n",
-      "shadowing (True, 19, 0, <Direction.up: 3>)\n",
-      "gondola (True, 9, 19, <Direction.downleft: 7>)\n",
-      "wrest (True, 0, 5, <Direction.downleft: 7>)\n",
-      "joys (True, 13, 3, <Direction.right: 2>)\n",
-      "minster (True, 11, 18, <Direction.down: 4>)\n",
-      "pales (True, 4, 14, <Direction.left: 1>)\n",
-      "chairs (True, 3, 5, <Direction.downright: 8>)\n",
-      "fishy (True, 7, 5, <Direction.left: 1>)\n",
-      "capitols (True, 17, 6, <Direction.right: 2>)\n",
-      "based (True, 8, 8, <Direction.right: 2>)\n",
-      "gums (True, 6, 14, <Direction.left: 1>)\n",
-      "pheromones (True, 5, 17, <Direction.downleft: 7>)\n",
-      "saki (True, 16, 16, <Direction.up: 3>)\n",
-      "moiety (True, 11, 7, <Direction.up: 3>)\n",
-      "waxed (True, 0, 4, <Direction.left: 1>)\n",
-      "guano (True, 17, 1, <Direction.up: 3>)\n",
-      "thriven (True, 0, 6, <Direction.downleft: 7>)\n",
-      "dilate (True, 19, 19, <Direction.up: 3>)\n",
-      "moray (True, 0, 16, <Direction.down: 4>)\n",
-      "icons (True, 13, 12, <Direction.downright: 8>)\n",
-      "adman (True, 7, 13, <Direction.downleft: 7>)\n",
-      "ukulele (True, 1, 7, <Direction.right: 2>)\n",
-      "hacked (True, 3, 17, <Direction.left: 1>)\n",
-      "rope (True, 5, 8, <Direction.up: 3>)\n",
-      "rise (True, 12, 15, <Direction.upright: 6>)\n",
-      "clue (True, 4, 15, <Direction.down: 4>)\n",
-      "acted (True, 8, 19, <Direction.up: 3>)\n",
-      "nicknack (True, 19, 17, <Direction.up: 3>)\n",
-      "spar (True, 12, 4, <Direction.upleft: 5>)\n",
-      "verbs (True, 8, 1, <Direction.right: 2>)\n",
-      "boss (True, 0, 12, <Direction.right: 2>)\n",
-      "annex (True, 4, 0, <Direction.down: 4>)\n",
-      "neck (True, 14, 5, <Direction.left: 1>)\n",
-      "repeater (True, 13, 11, <Direction.upright: 6>)\n",
-      "befalls (True, 8, 8, <Direction.down: 4>)\n",
-      "drover (True, 2, 17, <Direction.left: 1>)\n",
-      "leave (True, 6, 2, <Direction.right: 2>)\n",
-      "pans (True, 1, 3, <Direction.left: 1>)\n",
-      "brave (True, 15, 2, <Direction.down: 4>)\n",
-      "brigs (True, 2, 9, <Direction.down: 4>)\n",
-      "opus (True, 10, 19, <Direction.down: 4>)\n",
-      "live (True, 1, 6, <Direction.downleft: 7>)\n",
-      "noun (True, 10, 5, <Direction.downleft: 7>)\n",
-      "tail (True, 11, 12, <Direction.downright: 8>)\n",
-      "riot (True, 2, 4, <Direction.right: 2>)\n",
-      "care (True, 14, 13, <Direction.left: 1>)\n",
-      "hits (True, 19, 13, <Direction.right: 2>)\n",
-      "quilt (True, 11, 14, <Direction.upright: 6>)\n",
-      "part (True, 3, 19, <Direction.up: 3>)\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "for w in ws:\n",
     "    print(w, present(padded, w))"
   },
   {
    "cell_type": "code",
-   "execution_count": 43,
-   "metadata": {},
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "def decoys(grid, words, all_words, limit=100):\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 44,
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def decoys(grid, words, all_words, limit=100, min_word_len=4):\n",
+    "    decoy_words = []\n",
+    "#     dlen_limit = max(len(w) for w in words)\n",
+    "    while len(words) + len(decoy_words) < limit:\n",
+    "        d = random.choice(all_words)\n",
+    "        if d not in words and len(d) >= min_word_len and not present(grid, d)[0]:\n",
+    "            decoy_words += [d]\n",
+    "    return decoy_words"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['friendship',\n",
-       " 'stepping',\n",
-       " 'featheriest',\n",
-       " 'thriftily',\n",
-       " 'mutilation',\n",
-       " 'nook',\n",
-       " 'clewing',\n",
-       " 'meditated',\n",
-       " 'gooier',\n",
-       " 'cripples',\n",
-       " 'ponderously',\n",
-       " 'roundelay',\n",
-       " 'curtailed',\n",
-       " 'redeemed',\n",
-       " 'perimeters',\n",
-       " 'harelips',\n",
-       " 'overcompensating',\n",
-       " 'rejoicings',\n",
-       " 'adobe',\n",
-       " 'decreasing',\n",
-       " 'interstices',\n",
-       " 'curd',\n",
-       " 'orientate',\n",
-       " 'blueberries',\n",
-       " 'juniors',\n",
-       " 'broadloom',\n",
-       " 'debarring',\n",
-       " 'chandeliers',\n",
-       " 'segues',\n",
-       " 'army',\n",
-       " 'snuck',\n",
-       " 'pugilistic',\n",
-       " 'snugs',\n",
-       " 'dexterity',\n",
-       " 'dallies',\n",
-       " 'curving',\n",
-       " 'newsletter',\n",
-       " 'torn',\n",
-       " 'beaching',\n",
-       " 'limit',\n",
-       " 'blackguards',\n",
-       " 'breezier',\n",
-       " 'reoccur',\n",
-       " 'cabins']"
-      ]
-     },
-     "execution_count": 44,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "ds = decoys(padded, ws, ws_words)\n",
     "ds"
   },
   {
    "cell_type": "code",
-   "execution_count": 45,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "opted (True, 5, 7, <Direction.downright: 8>)\n",
-      "haywire (True, 8, 9, <Direction.downleft: 7>)\n",
-      "busting (True, 4, 17, <Direction.left: 1>)\n",
-      "succinct (True, 7, 17, <Direction.down: 4>)\n",
-      "institute (True, 16, 18, <Direction.up: 3>)\n",
-      "illicit (True, 13, 14, <Direction.left: 1>)\n",
-      "hypersensitivity (True, 16, 15, <Direction.left: 1>)\n",
-      "placement (True, 3, 11, <Direction.left: 1>)\n",
-      "bathrobe (True, 0, 5, <Direction.right: 2>)\n",
-      "inured (True, 4, 0, <Direction.right: 2>)\n",
-      "caveats (True, 3, 8, <Direction.downleft: 7>)\n",
-      "revisiting (True, 2, 11, <Direction.left: 1>)\n",
-      "pulp (True, 15, 11, <Direction.right: 2>)\n",
-      "teacup (True, 7, 16, <Direction.downleft: 7>)\n",
-      "threading (True, 18, 6, <Direction.right: 2>)\n",
-      "queered (True, 5, 13, <Direction.right: 2>)\n",
-      "parking (True, 6, 9, <Direction.right: 2>)\n",
-      "advent (True, 1, 11, <Direction.left: 1>)\n",
-      "chasuble (True, 19, 19, <Direction.left: 1>)\n",
-      "mosey (True, 7, 5, <Direction.downleft: 7>)\n",
-      "highboys (True, 19, 4, <Direction.right: 2>)\n",
-      "recharging (True, 18, 19, <Direction.up: 3>)\n",
-      "flue (True, 12, 2, <Direction.upright: 6>)\n",
-      "plywood (True, 3, 18, <Direction.left: 1>)\n",
-      "gluing (True, 12, 12, <Direction.upleft: 5>)\n",
-      "worrier (True, 1, 12, <Direction.right: 2>)\n",
-      "karma (True, 17, 9, <Direction.left: 1>)\n",
-      "peepers (True, 8, 7, <Direction.downleft: 7>)\n",
-      "vulnerable (True, 17, 10, <Direction.right: 2>)\n",
-      "boycott (True, 15, 1, <Direction.right: 2>)\n",
-      "rummy (True, 5, 4, <Direction.left: 1>)\n",
-      "tonic (True, 8, 13, <Direction.downleft: 7>)\n",
-      "children (True, 15, 0, <Direction.up: 3>)\n",
-      "reales (True, 6, 1, <Direction.right: 2>)\n",
-      "rectal (True, 7, 15, <Direction.down: 4>)\n",
-      "sledded (True, 14, 16, <Direction.up: 3>)\n",
-      "collocates (True, 14, 5, <Direction.right: 2>)\n",
-      "edict (True, 17, 4, <Direction.left: 1>)\n",
-      "captor (True, 14, 5, <Direction.upright: 6>)\n",
-      "amulet (True, 9, 4, <Direction.upright: 6>)\n",
-      "slipper (True, 2, 13, <Direction.right: 2>)\n",
-      "foot (True, 0, 0, <Direction.right: 2>)\n",
-      "chef (True, 14, 4, <Direction.upright: 6>)\n",
-      "goods (True, 6, 15, <Direction.right: 2>)\n",
-      "salter (True, 1, 5, <Direction.left: 1>)\n",
-      "crows (True, 18, 0, <Direction.right: 2>)\n",
-      "paeans (True, 12, 14, <Direction.up: 3>)\n",
-      "fences (True, 0, 18, <Direction.left: 1>)\n",
-      "iron (True, 5, 9, <Direction.right: 2>)\n",
-      "liras (True, 0, 19, <Direction.down: 4>)\n",
-      "stages (True, 19, 16, <Direction.up: 3>)\n",
-      "defer (True, 14, 2, <Direction.upright: 6>)\n",
-      "racy (True, 5, 4, <Direction.downleft: 7>)\n",
-      "gaps (True, 7, 11, <Direction.right: 2>)\n",
-      "aspen (True, 12, 10, <Direction.upleft: 5>)\n",
-      "rams (True, 6, 0, <Direction.downright: 8>)\n",
-      "friendship (False, 0, 0, <Direction.left: 1>)\n",
-      "stepping (False, 0, 0, <Direction.left: 1>)\n",
-      "featheriest (False, 0, 0, <Direction.left: 1>)\n",
-      "thriftily (False, 0, 0, <Direction.left: 1>)\n",
-      "mutilation (False, 0, 0, <Direction.left: 1>)\n",
-      "nook (False, 0, 0, <Direction.left: 1>)\n",
-      "clewing (False, 0, 0, <Direction.left: 1>)\n",
-      "meditated (False, 0, 0, <Direction.left: 1>)\n",
-      "gooier (False, 0, 0, <Direction.left: 1>)\n",
-      "cripples (False, 0, 0, <Direction.left: 1>)\n",
-      "ponderously (False, 0, 0, <Direction.left: 1>)\n",
-      "roundelay (False, 0, 0, <Direction.left: 1>)\n",
-      "curtailed (False, 0, 0, <Direction.left: 1>)\n",
-      "redeemed (False, 0, 0, <Direction.left: 1>)\n",
-      "perimeters (False, 0, 0, <Direction.left: 1>)\n",
-      "harelips (False, 0, 0, <Direction.left: 1>)\n",
-      "overcompensating (False, 0, 0, <Direction.left: 1>)\n",
-      "rejoicings (False, 0, 0, <Direction.left: 1>)\n",
-      "adobe (False, 0, 0, <Direction.left: 1>)\n",
-      "decreasing (False, 0, 0, <Direction.left: 1>)\n",
-      "interstices (False, 0, 0, <Direction.left: 1>)\n",
-      "curd (False, 0, 0, <Direction.left: 1>)\n",
-      "orientate (False, 0, 0, <Direction.left: 1>)\n",
-      "blueberries (False, 0, 0, <Direction.left: 1>)\n",
-      "juniors (False, 0, 0, <Direction.left: 1>)\n",
-      "broadloom (False, 0, 0, <Direction.left: 1>)\n",
-      "debarring (False, 0, 0, <Direction.left: 1>)\n",
-      "chandeliers (False, 0, 0, <Direction.left: 1>)\n",
-      "segues (False, 0, 0, <Direction.left: 1>)\n",
-      "army (False, 0, 0, <Direction.left: 1>)\n",
-      "snuck (False, 0, 0, <Direction.left: 1>)\n",
-      "pugilistic (False, 0, 0, <Direction.left: 1>)\n",
-      "snugs (False, 0, 0, <Direction.left: 1>)\n",
-      "dexterity (False, 0, 0, <Direction.left: 1>)\n",
-      "dallies (False, 0, 0, <Direction.left: 1>)\n",
-      "curving (False, 0, 0, <Direction.left: 1>)\n",
-      "newsletter (False, 0, 0, <Direction.left: 1>)\n",
-      "torn (False, 0, 0, <Direction.left: 1>)\n",
-      "beaching (False, 0, 0, <Direction.left: 1>)\n",
-      "limit (False, 0, 0, <Direction.left: 1>)\n",
-      "blackguards (False, 0, 0, <Direction.left: 1>)\n",
-      "breezier (False, 0, 0, <Direction.left: 1>)\n",
-      "reoccur (False, 0, 0, <Direction.left: 1>)\n",
-      "cabins (False, 0, 0, <Direction.left: 1>)\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "for w in ws + ds:\n",
     "    print(w, present(padded, w))"
   },
   {
    "cell_type": "code",
-   "execution_count": 46,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "s.esevresed...dwhims\n",
-      "e.tbk..vapourse.bn.d\n",
-      "h.ificembracesnslo.e\n",
-      "ctr.egukiwic..ddui.r\n",
-      "inor.dwh.rips.rrftsa\n",
-      "reue.eeisrar.tiefiyl\n",
-      "mmli.mgrg.muarth.slc\n",
-      "ieft.un.a.bnbuemdole\n",
-      "nn.nesimrliertseepad\n",
-      "ei.imeloeccdeh.epob.\n",
-      "dfsaprlrio.saf.smri.\n",
-      "cnpdt.ofrn.usu..ap.h\n",
-      "oom.ispeccgntlpew.sa\n",
-      "tcu.e.l.lu.eda.vsgin\n",
-      "e.bdsb.oarrmneloplsg\n",
-      "r.olaetrleromrkr.isa\n",
-      "ibatnhd.nlpoaeic.bir\n",
-      "eesiee.i.luepno.o.e.\n",
-      "snt.d.o.y.pcte.p.mr.\n",
-      "u....jtoquesylduol..\n",
-      "sfesevresedpzcdwhims\n",
-      "eotbkvgvapoursehbnyd\n",
-      "hiificembracesnslone\n",
-      "ctrnegukiwicurdduivr\n",
-      "inorydwhrripscrrftsa\n",
-      "reueleeisrarvtiefiyl\n",
-      "mmlinmgrgzmuarthgslc\n",
-      "ieftuunyanbnbuemdole\n",
-      "nncnesimrliertseepad\n",
-      "eirimeloeccdehzepobm\n",
-      "dfsaprlrioisafesmriq\n",
-      "cnpdtsofrnausuodapxh\n",
-      "oomlispeccgntlpewasa\n",
-      "tcuaehlzluledakvsgin\n",
-      "eibdsbeoarrmneloplsg\n",
-      "rbolaetrleromrkrnisa\n",
-      "ibatnhdtnlpoaeicibir\n",
-      "eesieerimluepnoholey\n",
-      "sntadvoaycpctespsmro\n",
-      "uamapjtoquesylduoldp\n",
-      "56 words added;  8 directions\n",
-      "Present: abreast bigwig bluff bodes bumps clothe concur confinement coteries crier cull daintier declared dendrites denim deserves embraces empties federal fluorite from glib guarded hangar herds iambic joiner kiwi loudly menus mocked panoply pearl poem polling prints proposition pruned resume rices riches rips roped rove seal seem shucks sissier swamped syllabi tine toque truthful unstabler vapours whims\n",
-      "Decoys: abrasions adapters aimlessness alkali awakens blowing burnouses burped cattily coal commences confusion contrivance crudest curies depravity distribute diva emigrate emulsion giveaway hangman house lifeboats maze middy mines mystified obtain organic parsons postulate prefixes pretenders razors scone sloes spuds straight subtleties systematise turncoats unpacked waivers\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "g, ws = interesting_grid()\n",
     "p = pad_grid(g)\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 63,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "...p.mown.\n",
-      ".sdse..ee.\n",
-      ".e.elad.cr\n",
-      "pi.dtir.ah\n",
-      "rzsiwovspu\n",
-      "oawh.kieab\n",
-      "brow.c.rda\n",
-      "ecnotops.r\n",
-      "d.kc.d...b\n",
-      ".staple...\n",
-      "\n",
-      "fhjpamownq\n",
-      "wsdseuqeev\n",
-      "ieaeladhcr\n",
-      "piedtiriah\n",
-      "rzsiwovspu\n",
-      "oawhakieab\n",
-      "browpcfrda\n",
-      "ecnotopssr\n",
-      "dikchdnpnb\n",
-      "bstapleokr\n",
-      "14 words added;  6 directions\n",
-      "Present: apace cowhides crazies dock knows lived mown pears probed rhubarb rioted staple tops wide\n",
-      "Decoys: adapting bombing boor brick cackles carnal casino chaplets chump coaster coccyxes coddle collies creels crumbled cunt curds curled curlier deepen demeanor dicier dowses ensuing faddish fest fickler foaming gambol garoting gliding gristle grunts guts ibex impugns instants kielbasy lanyard loamier lugs market meanly minuend misprint mitts molested moonshot mucking oaks olives orgasmic pastrami perfect proceed puckered quashed refined regards retraces revel ridges ringlet scoff shinier siren solaria sprain sunder sunup tamped tapes thirds throw tiller times trains tranquil transfix typesets uric wariness welts whimsy winced winced\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "g, ws = interesting_grid(width=10, height=10, words_limit=5, direction_slack=6)\n",
     "p = pad_grid(g)\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 98,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['fickler',\n",
-       " 'adapting',\n",
-       " 'chump',\n",
-       " 'foaming',\n",
-       " 'molested',\n",
-       " 'carnal',\n",
-       " 'crumbled',\n",
-       " 'guts',\n",
-       " 'minuend',\n",
-       " 'bombing',\n",
-       " 'winced',\n",
-       " 'coccyxes',\n",
-       " 'solaria',\n",
-       " 'shinier',\n",
-       " 'cackles']"
-      ]
-     },
-     "execution_count": 98,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "ds_original = ['regards', 'perfect', 'instants', 'refined', 'coddle', 'fickler', 'gambol', 'misprint', 'tapes', 'impugns', 'moonshot', 'chump', 'brick', 'siren', 'faddish', 'winced', 'kielbasy', 'market', 'puckered', 'trains', 'welts', 'cackles', 'foaming', 'proceed', 'gliding', 'guts', 'uric', 'oaks', 'molested', 'curled', 'boor', 'solaria', 'gristle', 'bombing', 'loamier', 'ensuing', 'cunt', 'sunder', 'revel', 'coaster', 'grunts', 'mucking', 'typesets', 'carnal', 'whimsy', 'scoff', 'coccyxes', 'meanly', 'sprain', 'minuend', 'ringlet', 'fest', 'winced', 'shinier', 'dicier', 'thirds', 'olives', 'garoting', 'pastrami', 'tranquil', 'tamped', 'sunup', 'crumbled', 'throw', 'ridges', 'chaplets', 'curlier', 'lugs', 'collies', 'adapting', 'demeanor', 'deepen', 'lanyard', 'tiller', 'transfix', 'wariness', 'times', 'mitts', 'dowses', 'creels', 'curds', 'quashed', 'orgasmic', 'ibex', 'retraces', 'casino']\n",
     "ds = random.sample(ds_original, 15)\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 89,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['regards',\n",
-       " 'perfect',\n",
-       " 'instants',\n",
-       " 'refined',\n",
-       " 'coddle',\n",
-       " 'fickler',\n",
-       " 'gambol',\n",
-       " 'misprint',\n",
-       " 'tapes',\n",
-       " 'impugns',\n",
-       " 'moonshot',\n",
-       " 'chump',\n",
-       " 'brick',\n",
-       " 'siren',\n",
-       " 'faddish',\n",
-       " 'winced',\n",
-       " 'kielbasy',\n",
-       " 'market',\n",
-       " 'puckered',\n",
-       " 'trains',\n",
-       " 'welts',\n",
-       " 'cackles',\n",
-       " 'foaming',\n",
-       " 'proceed',\n",
-       " 'gliding',\n",
-       " 'guts',\n",
-       " 'uric',\n",
-       " 'oaks',\n",
-       " 'molested',\n",
-       " 'curled',\n",
-       " 'boor',\n",
-       " 'solaria',\n",
-       " 'gristle',\n",
-       " 'bombing',\n",
-       " 'loamier',\n",
-       " 'ensuing',\n",
-       " 'cunt',\n",
-       " 'sunder',\n",
-       " 'revel',\n",
-       " 'coaster',\n",
-       " 'grunts',\n",
-       " 'mucking',\n",
-       " 'typesets',\n",
-       " 'carnal',\n",
-       " 'whimsy',\n",
-       " 'scoff',\n",
-       " 'coccyxes',\n",
-       " 'meanly',\n",
-       " 'sprain',\n",
-       " 'minuend',\n",
-       " 'ringlet',\n",
-       " 'fest',\n",
-       " 'winced',\n",
-       " 'shinier',\n",
-       " 'dicier',\n",
-       " 'thirds',\n",
-       " 'olives',\n",
-       " 'garoting',\n",
-       " 'pastrami',\n",
-       " 'tranquil',\n",
-       " 'tamped',\n",
-       " 'sunup',\n",
-       " 'crumbled',\n",
-       " 'throw',\n",
-       " 'ridges',\n",
-       " 'chaplets',\n",
-       " 'curlier',\n",
-       " 'lugs',\n",
-       " 'collies',\n",
-       " 'adapting',\n",
-       " 'demeanor',\n",
-       " 'deepen',\n",
-       " 'lanyard',\n",
-       " 'tiller',\n",
-       " 'transfix',\n",
-       " 'wariness',\n",
-       " 'times',\n",
-       " 'mitts',\n",
-       " 'dowses',\n",
-       " 'creels',\n",
-       " 'curds',\n",
-       " 'quashed',\n",
-       " 'orgasmic',\n",
-       " 'ibex',\n",
-       " 'retraces',\n",
-       " 'casino']"
-      ]
-     },
-     "execution_count": 89,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "ds_original"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 99,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "grid =  [['.', '.', '.', 'p', '.', 'm', 'o', 'w', 'n', '.'], ['.', 's', 'd', 's', 'e', '.', '.', 'e', 'e', '.'], ['.', 'e', '.', 'e', 'l', 'a', 'd', '.', 'c', 'r'], ['p', 'i', '.', 'd', 't', 'i', 'r', '.', 'a', 'h'], ['r', 'z', 's', 'i', 'w', 'o', 'v', 's', 'p', 'u'], ['o', 'a', 'w', 'h', '.', 'k', 'i', 'e', 'a', 'b'], ['b', 'r', 'o', 'w', '.', 'c', '.', 'r', 'd', 'a'], ['e', 'c', 'n', 'o', 't', 'o', 'p', 's', '.', 'r'], ['d', '.', 'k', 'c', '.', 'd', '.', '.', '.', 'b'], ['.', 's', 't', 'a', 'p', 'l', 'e', '.', '.', '.']]\n",
-      "padded_grid =  [['f', 'h', 'j', 'p', 'a', 'm', 'o', 'w', 'n', 'q'], ['w', 's', 'd', 's', 'e', 'u', 'q', 'e', 'e', 'v'], ['i', 'e', 'a', 'e', 'l', 'a', 'd', 'h', 'c', 'r'], ['p', 'i', 'e', 'd', 't', 'i', 'r', 'i', 'a', 'h'], ['r', 'z', 's', 'i', 'w', 'o', 'v', 's', 'p', 'u'], ['o', 'a', 'w', 'h', 'a', 'k', 'i', 'e', 'a', 'b'], ['b', 'r', 'o', 'w', 'p', 'c', 'f', 'r', 'd', 'a'], ['e', 'c', 'n', 'o', 't', 'o', 'p', 's', 's', 'r'], ['d', 'i', 'k', 'c', 'h', 'd', 'n', 'p', 'n', 'b'], ['b', 's', 't', 'a', 'p', 'l', 'e', 'o', 'k', 'r']]\n",
-      "present_words =  ['probed', 'staple', 'rioted', 'cowhides', 'tops', 'knows', 'lived', 'rhubarb', 'crazies', 'dock', 'apace', 'mown', 'pears', 'wide']\n",
-      "decoy_words =  ['fickler', 'adapting', 'chump', 'foaming', 'molested', 'carnal', 'crumbled', 'guts', 'minuend', 'bombing', 'winced', 'coccyxes', 'solaria', 'shinier', 'cackles']\n",
-      "Directions:  [('probed', '`(True, 3, 0, <Direction.down: 4>)`'), ('staple', '`(True, 9, 1, <Direction.right: 2>)`'), ('rioted', '`(True, 6, 7, <Direction.upleft: 5>)`'), ('cowhides', '`(True, 8, 3, <Direction.up: 3>)`'), ('tops', '`(True, 7, 4, <Direction.right: 2>)`'), ('knows', '`(True, 8, 2, <Direction.up: 3>)`'), ('lived', '`(True, 2, 4, <Direction.downright: 8>)`'), ('rhubarb', '`(True, 2, 9, <Direction.down: 4>)`'), ('crazies', '`(True, 7, 1, <Direction.up: 3>)`'), ('dock', '`(True, 8, 5, <Direction.up: 3>)`'), ('apace', '`(True, 5, 8, <Direction.up: 3>)`'), ('mown', '`(True, 0, 5, <Direction.right: 2>)`'), ('pears', '`(True, 0, 3, <Direction.downright: 8>)`'), ('wide', '`(True, 4, 4, <Direction.upright: 6>)`')]\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "print('grid = ', g)\n",
     "print('padded_grid = ', p)\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 100,
+   "execution_count": null,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 77,
+   "execution_count": null,
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "probed 3 0 6 Direction.down [(3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0)]\n",
-      "staple 9 1 6 Direction.right [(9, 1), (9, 2), (9, 3), (9, 4), (9, 5), (9, 6)]\n",
-      "rioted 6 7 6 Direction.upleft [(6, 7), (5, 6), (4, 5), (3, 4), (2, 3), (1, 2)]\n",
-      "cowhides 8 3 8 Direction.up [(8, 3), (7, 3), (6, 3), (5, 3), (4, 3), (3, 3), (2, 3), (1, 3)]\n",
-      "tops 7 4 4 Direction.right [(7, 4), (7, 5), (7, 6), (7, 7)]\n",
-      "knows 8 2 5 Direction.up [(8, 2), (7, 2), (6, 2), (5, 2), (4, 2)]\n",
-      "lived 2 4 5 Direction.downright [(2, 4), (3, 5), (4, 6), (5, 7), (6, 8)]\n",
-      "rhubarb 2 9 7 Direction.down [(2, 9), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9)]\n",
-      "crazies 7 1 7 Direction.up [(7, 1), (6, 1), (5, 1), (4, 1), (3, 1), (2, 1), (1, 1)]\n",
-      "dock 8 5 4 Direction.up [(8, 5), (7, 5), (6, 5), (5, 5)]\n",
-      "apace 5 8 5 Direction.up [(5, 8), (4, 8), (3, 8), (2, 8), (1, 8)]\n",
-      "mown 0 5 4 Direction.right [(0, 5), (0, 6), (0, 7), (0, 8)]\n",
-      "pears 0 3 5 Direction.downright [(0, 3), (1, 4), (2, 5), (3, 6), (4, 7)]\n",
-      "wide 4 4 4 Direction.upright [(4, 4), (3, 5), (2, 6), (1, 7)]\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "[(7, 5), (2, 3), (3, 5)]"
-      ]
-     },
-     "execution_count": 77,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
     "cts = collections.Counter()\n",
     "for w in ws:\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 143,
+   "execution_count": null,
    "metadata": {
+    "collapsed": true,
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "0\n",
-      "1\n",
-      "2\n",
-      "3\n",
-      "4\n",
-      "5\n",
-      "6\n",
-      "7\n",
-      "8\n",
-      "9\n",
-      "10\n",
-      "11\n",
-      "12\n",
-      "13\n",
-      "14\n",
-      "15\n",
-      "16\n",
-      "17\n",
-      "18\n",
-      "19\n",
-      "20\n",
-      "21\n",
-      "22\n",
-      "23\n",
-      "24\n",
-      "25\n",
-      "26\n",
-      "27\n",
-      "28\n",
-      "29\n",
-      "30\n",
-      "31\n",
-      "32\n",
-      "33\n",
-      "34\n",
-      "35\n",
-      "36\n",
-      "37\n",
-      "38\n",
-      "39\n",
-      "40\n",
-      "41\n",
-      "42\n",
-      "43\n",
-      "44\n",
-      "45\n",
-      "46\n",
-      "47\n",
-      "48\n",
-      "49\n",
-      "50\n",
-      "51\n",
-      "52\n",
-      "53\n",
-      "54\n",
-      "55\n",
-      "56\n",
-      "57\n",
-      "58\n",
-      "59\n",
-      "60\n",
-      "61\n",
-      "62\n",
-      "63\n",
-      "64\n",
-      "65\n",
-      "66\n",
-      "67\n",
-      "68\n",
-      "69\n",
-      "70\n",
-      "71\n",
-      "72\n",
-      "73\n",
-      "74\n",
-      "75\n",
-      "76\n",
-      "77\n",
-      "78\n",
-      "79\n",
-      "80\n",
-      "81\n",
-      "82\n",
-      "83\n",
-      "84\n",
-      "85\n",
-      "86\n",
-      "87\n",
-      "88\n",
-      "89\n",
-      "90\n",
-      "91\n",
-      "92\n",
-      "93\n",
-      "94\n",
-      "95\n",
-      "96\n",
-      "97\n",
-      "98\n",
-      "99\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "# for i in range(100):\n",
     "#     print(i)\n",
     "#         f.write(lcat(sorted(ds)))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "g, ws = interesting_grid(width=100, height=100, words_limit=1, max_words=2000, direction_slack=1)\n",
+    "p = pad_grid(g)\n",
+    "ds = decoys(p, ws, ws_words, limit=2500)\n",
+    "# print(show_grid(g))\n",
+    "# print()\n",
+    "# print(show_grid(p))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "print(len(ws), 'words added; ', len(set(present(g, w)[3] for w in ws)), 'directions')\n",
+    "# print('Present:', wcat(sorted(ws)))\n",
+    "# print('Decoys:', wcat(sorted(ds)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true,
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "with open('huge-wordsearch.txt', 'w') as f:\n",
+    "        f.write('{}x{}\\n'.format(len(g[0]), len(g)))\n",
+    "        f.write(show_grid(p))\n",
+    "        f.write('\\n')\n",
+    "        f.write(lcat(sorted(ws + ds)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def read_wordsearch(fn):\n",
+    "    lines = [l.strip() for l in open(fn).readlines()]\n",
+    "    w, h = [int(s) for s in lines[0].split('x')]\n",
+    "    grid = lines[1:h+1]\n",
+    "    words = lines[h+1:]\n",
+    "    return w, h, grid, words"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def do_wordsearch_tasks(fn, show_anyway=False):\n",
+    "    width, height, grid, words = read_wordsearch(fn)\n",
+    "    used_words = [w for w in words if present(grid, w)[0]]\n",
+    "    unused_words = [w for w in words if not present(grid, w)[0]]\n",
+    "    lwp = sorted([w for w in words if present(grid, w)[0]], key=len)[-1]\n",
+    "    lwps = [w for w in used_words if len(w) == len(lwp)]\n",
+    "    lwa = sorted(unused_words, key=len)[-1]\n",
+    "    lwas = [w for w in unused_words if len(w) == len(lwa)]\n",
+    "    g0 = empty_grid(width, height)\n",
+    "    for w in words:\n",
+    "        p, r, c, d = present(grid, w)\n",
+    "        if p:\n",
+    "            set_grid(g0, r, c, d, w) \n",
+    "    unused_letters = [l for l, u in zip((c for c in cat(cat(l) for l in grid)), (c for c in cat(cat(l) for l in g0)))\n",
+    "                  if u == '.']\n",
+    "    unused_letter_count = collections.Counter(unused_letters)\n",
+    "    makeable_words = []\n",
+    "    for w in unused_words:\n",
+    "        unused_word_count = collections.Counter(w)\n",
+    "        if all(unused_word_count[l] <= unused_letter_count[l] for l in unused_word_count):\n",
+    "            makeable_words += [w]\n",
+    "    lwm = sorted(makeable_words, key=len)[-1]\n",
+    "    lwms = [w for w in makeable_words if len(w) == len(lwm)]\n",
+    "    if show_anyway or len(set((len(lwp),len(lwa),len(lwm)))) == 3:\n",
+    "        print('\\n{}'.format(fn))\n",
+    "        print('{} words present'.format(len(words) - len(unused_words)))\n",
+    "        print('Longest word present: {}, {} letters ({})'.format(lwp, len(lwp), lwps))\n",
+    "        print('Longest word absent: {}, {} letters ({})'.format(lwa, len(lwa), lwas))\n",
+    "        print('{} unused letters'.format(len([c for c in cat(cat(l) for l in g0) if c == '.'])))\n",
+    "        print('Longest makeable word: {}, {} ({})'.format(lwm, len(lwm), lwms))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "[w for w in ws_words if len(w) == 16]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# all_lines = []\n",
+    "# for fn in sorted(os.listdir()):\n",
+    "#     if re.match('wordsearch\\d\\d\\.txt', fn):\n",
+    "#         all_lines += open(fn).readlines()\n",
+    "#         all_lines += ['\\n'] * 2\n",
+    "\n",
+    "# open('all-wordsearches.txt', 'w').writelines(all_lines)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 209,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Added 6 ; attempt 19\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "6"
+      ]
+     },
+     "execution_count": 209,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "g = empty_grid(10, 10)\n",
+    "g, ws = fill_grid(g, ws_words, 200, min_word_len=4, max_attempts=20)\n",
+    "len(ws)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 210,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Added 1149 ; attempt 9427\n"
+     ]
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "IOPub message rate exceeded.\n",
+      "The notebook server will temporarily stop sending output\n",
+      "to the client in order to avoid crashing it.\n",
+      "To change this limit, set the config variable\n",
+      "`--NotebookApp.iopub_msg_rate_limit`.\n"
+     ]
+    }
+   ],
+   "source": [
+    "g = empty_grid(100, 100)\n",
+    "g, ws = fill_grid(g, ws_words, 2000, min_word_len=5)\n",
+    "len(ws)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 216,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(1149, 1149, [('scofflaw', 1)])"
+      ]
+     },
+     "execution_count": 216,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pm = present_many(g, ws)\n",
+    "pold = [w for w in ws if present(g, w)[0]]\n",
+    "len(pm), len(pold), collections.Counter(p[0] for p in pm).most_common(1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 219,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "\n",
+    "with open('huge-unpadded-wordsearch.txt', 'w') as f:\n",
+    "        f.write('{}x{}\\n'.format(len(g[0]), len(g)))\n",
+    "        f.write(show_grid(g))\n",
+    "        f.write('\\n')\n",
+    "        f.write(lcat(sorted(ws)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 218,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "smuiclacphysics.hcnebrevilingd..skcabllup.s...gnitnacs..blusted.....pilafeldrig..enquireddetnawnu...\n",
+      "e....nutmegs.t..telbanimret...e..tseikwagewoodpeckerstirwas.b.r...picksn...ylhsiroobsuspectingsexevd\n",
+      "cgnittacdliw..isuoniallivsegas.lrafts.y.vcs..demrofsnart.mla...e.c....e..fannysdiscrimination.oe..e.\n",
+      "nnytima.wharfrep.stswashbucklersw....m.eos...noprat....ao.rs....t.h..m.relabele..sss...b.sc.ts..vb.s\n",
+      "eid..desivedaia.shegdtg.gniyugys.o..a.rme.gpantedsobeysodgm.a....t.osabound...s.bttp...uje.orhd.boe.\n",
+      "tverediw...dtlw.eiar.ehacrierhsrmccosiant.nbestridi..sreepegarotedadr.slaropauses..e..rdis.oteia.lld\n",
+      "nardd.p...itli.i.pesu.srwe...ciuuhfsnti.sgingivitislubl.fotkcuhs..rmsensitisedeu...eleygbutsiyjcf.u.\n",
+      "eerne.u..aiin.r.i.nset.ioku..taeia.gods.e.n..dh.n.emld.r.lht.hobnobsi.s..l.c.trs...jnb.ieoizw.llka.f\n",
+      "shiense.nhae.s.n.aietun.owig.idtrp.srsayi.w..ogu.oecnie..yo.u...whmt.t..u.a.lcds...tb.ondran.oeersa.\n",
+      ".nhpnnktsts...g.d.cve.qe.pblohdoaseomtc.r.a.tgnrgdnaiae.spd.sc.sora...nt.r.en.no..ro...g.l..msbfdue.\n",
+      ".asxiiasehcnerdj.moido.edsoayvebr.w.ufh.rtr.sgiaxgdekm.rtfo.k.noir.....ag.se..ur.al..sreraehsu.xnoet\n",
+      "gr.erah.peeweeu.i.tdir..h.acc.mard..tie.u.pdeehbo.eyx.u.ralge.kucnoveltiesseirfdp..buttocksn..laodne\n",
+      "nr.sgls..d..sdwrg.iela...c.uikise.o.altwf.i.idcbtged...poeoatsqo...gratefully..sportingsweepersaa..s\n",
+      "iaw.bp...e.hgor.ulnnstullee.ntl.t.mttps.os..d.tienstc...nhggcst.gsugaringinsight..snifters.....cde.i\n",
+      "nta..m..ssteno..i.eckef..b...ar..y.ieu.lpls.n.endirswu..gsiehs..n.delbaf....interpose..dsurt..r.el.u\n",
+      "oeg..oae.usdr..kl..ecd.aiproveso..llsdsayeb.a.ra.iee.er.l.esih.ti.sllihygrellapractisedatcneea..gg.r\n",
+      "sdeb.cziofe.r.e.d..da..rgthrive.p.agearetr.hs.stsavr..riy.srec.ar.pocketbooktrotxe.....nw.unlk..gg.b\n",
+      "a.re.a.m.rs.espumoneb.t..o.semorhc.rnadau.istp.eehio..cpoga.sn.uuyratchetswisher.....n.se..fepc.aos.\n",
+      "e.saf...fsrrh.a.retpada...t.....e.iggiiv.llcaam.vgnt.o.t.sidtu.pj.r.retemarapecnarussau.a.l.frpante.\n",
+      "rretarcurne.c.g.pellagra...s...d.wni.dk.elgnaae.inusm..msgibehfedtsl..prowldenimn.shiedrka...l.il.ss\n",
+      "n..i..leatgbt.rc..s..sesitengamedinkafgnonn.tladta.m....uentbl.aa.oeegniyartrop.eseitoobsnoleme.tpuu\n",
+      "ub.f.lent.gri.afassevissimagingslgiryuoriit...nsahaseigodniiyelwb..upwthguorb.obmil....hfeedings..tr\n",
+      ".a.yydne..aew.ryrri.emackintoshw.trsbnasnh.u..trksr.gasketrpc.raar..ptereinterpretingie....deggiwtnp\n",
+      ".s..nyl...raslitloeett.splinesobtih.gnlgtkt.r.ealwasset....usu.bvgi..eej......rtss.dnrtonnaccords.oa\n",
+      ".ihikers..bkawa.rtssrao...gc.r.yek..ues..rhn.ennaob.gmovers.bid.riwcsketches.esar.etsi.gswollefdebcs\n",
+      ".leticilli.zaen..uftsrnv..log..dils.rrc..noau.nitrlbr.eidrib.iwa.irea..st...ieiadxe.n.lrolocsid....s\n",
+      "sr...m....edl.s...loyeage.ap...e.pc....h..ilk.am.roouevilamsidv.r.e.gt..ge.gfdeaer.s.ygnideerbnquoit\n",
+      "reprobatesdiyruovasbs.d.oddu..hks..h.s..e..kliee.uoae.lairetsigamt.r..e..nneedmsp.t.p.incisesuhctulc\n",
+      "s.vr.t.sdld..s.controllablel.s.aleavese..l..s..s.btrshalvesylsuougibma.s.sim.pgo.avhshortensr.zzazip\n",
+      ".ebae.oliedpmsuesilangisg..a..hc.zingsyy..oqueryingdoreopened..endless...l.bs.lrlsnikskcub.t..knifed\n",
+      "jiklruons.lefilbsnwodwohsn.ttupnit..tdretsenohl..cvsm...gnimirgnidaetsemoh..baamongst..y.wucustomers\n",
+      "doionfgh.a.lsotej.....e.h.iee...gniretnuas..s..o.oa.e.g.r...snoitulos.selppitue..w...io.trrbfruits..\n",
+      ".eydj.g.n..i.iutvosplithsejlhp.s.eieinveighing..mnl.rlbu..pineapple....a.f.e.nsrealiseadel.ar.eevell\n",
+      "r.ertu.e..gc..dleoi....htiiyi.m.avr..transducers.fe.aatempts.b.....d.n.f.ud.t.scales.r.tr.aopinion.l\n",
+      ".d.yoveterinaryoenrn..a.bapg.wjuin..psalmist.x...innlenvd...iebrashereat.ne...snaeco..aeiide.ps...ii\n",
+      "..pb.dtacosei.l.sr.gim.b.eb.ho.nrideraems....opa.dcdri.ie..n.lv.sc.k.kweent.outsmartedwl.oaef.ek..mb\n",
+      "feweste....p.v.a.p..enisreesbtg..t.h.e.k.tt..bem.eecas.lpggday.ipmrn.akrqeasedoberofmrr.l.nhp..de.pn\n",
+      "dy.sighting...o.spalfngsd..b.cellistott.nscc.hdesshlhe.leinde.aas.ea.ewnulcsekytmrg.oa..co..la...tao\n",
+      ".ddr..object...r.aehg.ee..ipr......degmreioascontrrits.an.oieinw.umlzwaoa.iss..i.netu.midictatorialo\n",
+      ".e.em..muiretcab.sn.rnh.gnoigimletslry.denreftmdie.trsygdm.rssvsealplyrobcll.gx.i.egusnm..b.c.ps..ap\n",
+      ".pstekcolsopyh..s...schngpsteppes.esoadwcaib.aesvsrhiiree.iprikvrc.l.ydniapisenb.banaoicar.yagr...ss\n",
+      "ep.sew......macinimin.islp..s....xrpaotoirdf.mto.eoomharntse.elti.a.a.eslrxarebiajdahvalaslprnoarbez\n",
+      "so.ykbongothistlektass.iidsreg..e.ia.lreogaiweevilgg..n.tagrw.ia.d.r..s.ioemsoinsa.pnnavtr.adidllucs\n",
+      "il.oloverwhelmednilni.neegee.cnd.as.mduvrch.n.r..lurd.oarnasenilesab..t.tul.stkxuie.ctesae.rigd.....\n",
+      "rp..y.......l..ivbal.nrigdn.l.ni.n.damava..t.g...seaeyi.ik..se...rtheoryysab.shnolreeril.edknniesohw\n",
+      "oproponents.etli.kacotr.in.o.t.en.innsidu...relruc.pgetge.d.lciportosi...ega.itgeplpyautge.egon.ar..\n",
+      "ecaudalyokelrst.ynoiif.l.piklstsrrtf.aenvoyeuristichnludta.b.se.i.ngnirabrer.entuleaugsno.gd.rgdlibd\n",
+      "h..configurationontnt.g...omr.toteo.fsg.g..stsefni.yora.psa.t.l.msa.....e.rbd.sseol.e.at.x.dwhesieee\n",
+      "tpalsy.r..c.e..ivcsrscinap.tma.irsfm.uliuqnartoday..racp.neo..u.plncaninev.eg.eduynr.rg.e.ieat.lgngp\n",
+      "..fleshyuk.s.dteeme.eruptingtah.lhir.gm.r.contrastedhbe.ugni..p.uei.yamsidad.nreal..r.ny.rrntc.antoy\n",
+      "....yogins..earnis..ripeness.edsmethe.na.bsromalgte.trr.ni..k.m.lemigfieryed..iwvtta.wia.hnis.ss.eth\n",
+      "nonhuman..knnsnte...e...cupolargiitapt.igreideew.s.re.pie....oaespo.nrcb.y.ke.wlfiee.hdws.p...mu.d..\n",
+      "bywords...osiohme..estnemegagnedlnstcon.ya...primessn.mshockerhleyd..sehe.t.ssealra.daua.s....ar....\n",
+      "outlastedt.ocsb.c.x....enilefileeavgotsi.lrfordssgt..ettautnessbdebbadieil.p.ur.po.w.lle......oe.k.g\n",
+      "ddetsyrte.n..l.gnp.esuccocddypl.ppdeisi..rlpimplyn..ecg..dsuitcases.a.ksnfl.mdtnekrahecs.etsawfpn.cn\n",
+      "iawaitss.s..e.a.e..lp....euhauwpi.udrv.ve..er.a..udt..as.se...ctlocn.c.ltifsretaehcc.rnempollenag.ii\n",
+      "essertsimdaehrsci.gdr...tstrcocrn.stesidi..ejs...o.e..erq..lt.i.akaco.ksussocondoretsaocno....tdnnls\n",
+      "s.rettab.es.rptgc.ide..itaeidodohb.cynen.sn.o....y..vrcua..uclb.earhgiyhla.hn..lebil..c..ak..senioli\n",
+      "retsim.tlu.eoo.rssfaa.xsendns.ehoqa.oeesgdtpmoppets.ueeu.moseyu.cygan.tlaib..detoormoisterpe.l.olial\n",
+      "......hbbdtpr..inmt.desrtaetjhpilu.rlrtdsso.derunettceirltesl.csneofis.aenssregnifrettub...od.asbtha\n",
+      "sfeergalebia.f.noui.iobattlae.ebei.bdwe..r..os...gpoz.orslsl.le.odefdr..tvdn...adjectivess.dr.geaapr\n",
+      "....isitultscrbdccn.n.lelipa.gnime..is.dp....we..ane.b..toi..bikc.sener..ii.eslays.rp..c.du..pagnr.t\n",
+      "f..limocleiasoaegsgignduear..udtut.l...gambol.nsrv.ib.o.re.ni..mupfdete..ysa.t....ea.oa..fetm.taeu.n\n",
+      "o.ideokoslb.ewnr.nrso.psnss.reeifelatrinems....ei..etb.s..rvg...ol..rtc.y.lin.u..t.lsne.cp.tceeyypte\n",
+      "owd.mel.ear.isir.eipeatsenye.snvfr..latticeworkndlrfesgnihsalpslagf.suunsprlv...u..otk.tardslassgpcc\n",
+      "t.yltd.dl.e.hysam.uhtl.so.tm.scelcascadinghl..c.asiyrse.vexed.tsng.fshpaslpua..c.oasislliiumtocsguie\n",
+      "wynifnpseydscetdso.acyyi.e..i.elihslanifbstsle.r.vevrycv.....rhi.ne.tsetoahdstaupset..eascae.rj.isvd\n",
+      "euamrae.sliuraeicccecnttmstner.yn.st....olansonsade.ieeoi...oeo..i.ga.rubqyaito..deposittdaat.a.wael\n",
+      "apmeitr.ussrarra..aaraiosgy...g.g.gie...tewor.wart.n.cbrfd.odds.hrpnb.ar.usddlltpoesyrr.js.l...wt.he\n",
+      "rpisasmtoutgid.l..ilctnl.nabiopsy.gnbi..cwsii.gepei.g..u.fn.ee.cseiimptaweiecoae..s.euyu...ynominees\n",
+      ".ictrsiarorerr..gdiipoi.fiwgnilratsnibu.hortcgn.saef.e.rtslrre.lcknlooelahcka.rvre.isdraeslather...r\n",
+      "yekopuspalirtu.eenf.re.m.nbslartueneiloqebeakoihstlhi.ru...ap.aaonilculirskrs..nnsntaarttdetcartsbao\n",
+      ".s.n.bsrclcyamnmei.h.pl..nu.deniapeptllns.kvslky.mymce.fs.mawussrane.nasdaiut.ylsasetmae.canoes.oe.m\n",
+      "...e.oio.at.ptmrt.c..r...estappinggp.odos.cahfnm..imi.dfl.c.gtudihgv.cieiunlerugpshietetniksgipdnt..\n",
+      "flierroo.cs.liac.gunfire.pwhimsd..aa..grr.ucasue...rmn.lis.hidu.n..i.etdnqgerfoceaodidsdewotwokrgals\n",
+      "latconnm.f.e..epaimedc...deducesddshs..aunfx..rn....kugie.tgdl..g..n..y.g.nawn.krnilse.snoopingisgil\n",
+      "obmibsss..asir..l..a.eeviecerggee.em....ecue..tstoadspynveael....resonantgtan.ugseiti.ruolev...freao\n",
+      "u..gdarnsspegniciee.sylbatonarpgfhrsodomychaiserelbmuh.grtnsstseebedliw.o.la.p..ncmpr.enrapturetertv\n",
+      "t...rd...oncc.t.srnclennut.cainoaap...od..bfrolics.k....o.rosseforp...brazzesb.laopa.eseifidoc.elgee\n",
+      "v...ee..o..ooe.eslsth.ke...drarnwan.l.es..a...sc.liatesrohc.sdellennekgi..s.u.af.albtkn...clawsrigrn\n",
+      "o..bdbyc....krsindekyasa..etredsdodi.l.re.l..tgo.nobscuredhh..securere..al.c.nsfn.iace.i.coupledoanl\n",
+      "t.mei.si..maximaltedynn.sdstss.doem.iebe.dm.n.nng.gnippohca....m....dt..eso.dnes.a.operpetuatingbo.i\n",
+      "eegggclassroomss...ral.t.pssp.ewbidtlelpd.yedoic.g.....s.dnm..otopaetn.t.lsmov..sfh.s.piling....i..e\n",
+      "dahh.n...h..pecnarpeeti.yeeredsrte.ere.e..mdepkrn.np....iucsun..ae...eotisaie..eis.ey.rknittings..br\n",
+      "rt.eenickinglfy...l.rdig..ie.neet.cev.ha.eo.naceo.wispsenme.eie.gr..lmncertrntdxs.bdpsao.tokenismda.\n",
+      "...dla.g..i.oar.cc.e.onchnn.ktihttfi.s.lgg.lwqitcp.en.rpttmt.ldnn.ti.i.bkii.hgeamyseprzk.r..mld.e.l.\n",
+      ".vwkibp.a.n.wlo.ifg..g.ugtw.afglrtr.i..nwpa.auleae.crorpoaaek.ueo.ssoai.ds.a.ryognhkaaec..euye.ce.ad\n",
+      "..ai.nmseph.msvsta..st.qh.ow.iiirden..iornp.pes.ec.eboigarxcrld.tslp.r.ahsw.sitsra.ortde..svt.a.ndne\n",
+      "b.rl.inacae.aeatel.yortuetl.l.fn.irr.rooe..e.s..dcv.vuytireypii.i.a.c.rlessdnoluvy.pcsggsidaim.aoect\n",
+      "u.loi.rerrr.nssacs.tuoaac.bp.y..iuakfdpr..egatsopasetznlapsni.nmf.zs.tynctrgrato..c.so.in.repnr.rbet\n",
+      "tgibps.idceott.nsi.ittnrntnalaesfsnnseysword.c..lrdedoygst.lrnggisi.xaoinoscvrcharsa.cngmesiamn.kkdu\n",
+      "tnkye.e.uusel..cat.lh.aaa.legabnaei.r...kinderou.y.pler.lksleeg.e.eevtteleaeezzaipddpis.nmntfgfo.csp\n",
+      "eietd..mpqankffh.yaie.gnt.....use.gallivants..ic.l.uydpuner.uyttdysinadlcrove....ee.tslu.geuijnrcipt\n",
+      "rbred..peri.usoe.srbayetimikespl.debrutrepnu.n.rkl.mb.npsera.fosm.dimieiscovsrd.vtyr.om...l..fioisiu\n",
+      "nbisl.e.or.a..rs.eoastrireitliugselttit.....g..e.u.pr..iadmsbnemil.gcrt..siepeclrrapteswovasidfvcgro\n",
+      "uupcer.o..y.d.gtstulte.ne...rtsicitnamoraincoatk.bfearedkhayyeutycacyc.hwlgrc.oeematr...vended.ei.i.\n",
+      "trxrm.msinimefe.tani.i.ih..i.....edutingamsnoynac..decay..ceagd.ara.a.celnie.vsndwo...pinup...l.dntd\n",
+      "sgeosdrenblurbscalda.o.nn.n..cimonoxatkinetic..e....narks.k.rl..pl.r.teaihe.eer.pwryly...tubes.e..g.\n",
+      "..saesuohdraug..ie.v.m.gig.ycnangiop.tawdrier..w....scallopedsesiwp.atstcl.ddo.astelfael..bumblers..\n",
+      ".t.krandomises..rr.a..gripestsivitcellocsbawsshapeliest..gnitontoofhylluftsaobwsocilac..located..s..\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(show_grid(g))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 221,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Attempt 249 ; most common is [('scofflaw', 1)]\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "(True, [('scofflaw', 1)])"
+      ]
+     },
+     "execution_count": 221,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "padded = False\n",
+    "padding_attempts = 0\n",
+    "while not padded and padding_attempts < 10**6:\n",
+    "    clear_output(wait=True)\n",
+    "    padding_attempts += 1\n",
+    "    pg = pad_grid(g)\n",
+    "    pm = present_many(pg, ws)\n",
+    "    print('Attempt', padding_attempts, '; most common is', collections.Counter(p[0] for p in pm).most_common(1))\n",
+    "    if collections.Counter(p[0] for p in pm).most_common(1)[0][1] == 1:\n",
+    "        padded = True\n",
+    "        \n",
+    "padded, collections.Counter(p[0] for p in pm).most_common(1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 222,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "249"
+      ]
+     },
+     "execution_count": 222,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "padding_attempts"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 230,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "851"
+      ]
+     },
+     "execution_count": 230,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "dws = decoys(pg, ws, ws_words, limit=2000, min_word_len=5)\n",
+    "len(dws)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 231,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "smuiclacphysicsihcnebrevilingdroskcabllupcsowygnitnacsipblustedpesnipilafeldrigclenquireddetnawnufly\n",
+      "eqdbmnutmegsvtzdtelbanimretanmelptseikwagewoodpeckerstirwaszbdrrdypicksnzikylhsiroobsuspectingsexevd\n",
+      "cgnittacdliwffisuoniallivsegasplraftstyevcsgcdemrofsnartrmlaydzescpopxehsfannysdiscriminationdoeypen\n",
+      "nnytimavwharfrepjstswashbucklerswklqimkeosulxnopratpsitaoorsrtrjtthnsmxrelabelesrssstribiscutsddvbrs\n",
+      "eidgkdesivedaiajshegdtgrgniyugyshohaabrmedgpantedsobeysodgmraoozdteosaboundgfjsmbttpygjujedorhdvboeh\n",
+      "tverediwtczdtlwdeiaryehacrierhsrmccosiantnnbestridikysreepegarotedadrpslaropausesubepnrdissoteiailld\n",
+      "narddypasjitligihpesubsrwewfgciuuhfsntizsgingivitislublefotkcuhschrmsensitisedeugnveleygbutsiyjcflud\n",
+      "eernefunuaiindrsilnsethiokutttaeiapgodsteknerdhlngemldlrslhtrhobnobsizsvdlocdtrszbnjnbpieoizwillkarf\n",
+      "shiensetnhaepslnnaietundowigvidtrptsrsayiewreogudoecniebbyofugamwhmtntwsufaulcdsmlptbeondrancoeersak\n",
+      "onhpnnktstsdovgsdicvevqeypblohdoaseomtcdrbaatgnrgdnaiaejspdtscrsoratzdntmrgenqnomiroixqgslltmsbfduee\n",
+      "lasxiiasehcnerdjomoidodedsoayvebrawnufhcrtrtsgiaxgdekmkrtfodkinoirfekkaagvsermuroalabsreraehsuxxnoet\n",
+      "grderahepeeweeusiutdirnohmaccsmardrztienunpdeehbomeyxruyralgeskucnoveltiesseirfdpyebuttocksntqlaodne\n",
+      "nrrsglsmxdupsdwrgoielalgmccuikisexoaaltwfniaidcbtgednzcpoeoatsqoszdgratefullytisportingsweepersaapys\n",
+      "iawlbpsleeyhgorhulnnstulleemntlgtnmttpssostidstienstcbfnnhggcstegsugaringinsighthrsniftersmmfwicdeoi\n",
+      "ntabemghsstenongideckefombnlrarlxynieuplplsznnendirswunfgsiehsuensdelbafetkzinterposexldsurtimreelhu\n",
+      "oegleoaeiusdrixklisecdiaiprovesoatllsdsayebsawrasieeterrlaesihztixsllihygrellapractisedatcneeavgggpr\n",
+      "sdebzczioferrsexdiadatergthrivelpdagearetrfhststsavrbyriymsrecharupocketbooktrotxextuvznwkunlkaqggtb\n",
+      "ayrewatmerseespumonebatlnoisemorhcdrnadaubistpoeehiouxcpogaesnsuuyratchetswishereatjingsepnfepckaose\n",
+      "eosafgcffsrrhsawretpadaspitgewuheaiggiivrllcaamkvgntrodtbsidtutpjnrgretemarapecnarussaugaylcfrpantet\n",
+      "rretarcurneicwgnpellagraupmsixcdswniodknelgnaaetinusmlomsgibehfedtslabprowldenimnushiedrkaqndltillss\n",
+      "ntoimlleatgbtlrcsxsehsesitengamedinkafgnonnxtladtabmvkifuentblwaaroeegniyartropieseitoobsnolemedtpuu\n",
+      "ubqfilentigrigafassevissimagingslgiryuoriitoarnsahaseigodniiyelwblmupwthguorbkobmilkiaxhfeedingspptr\n",
+      "nanyydnerxaewaryrriaemackintoshwftrsbnasnhsukntrksragasketrpcsraarliptereinterpretingieycoudeggiwtnp\n",
+      "msrgnylmnkraslitloeettosplinesobtihfgnlgtktmrxealwassetpiykusurbvgijzeejgpkxclrtssfdnrtonnaccordshoa\n",
+      "aihikersaebkawarrtssraodcrgckrpyekbruesuorhnpennaobwgmoversabidgriwcsketchesuesartetsicgswollefdebcs\n",
+      "zleticilliozaenkfuftsrnvzylogeldilsrrrcrinoautnitrlbroeidribuiwaeireakrstmioieiadxesnnlrolocsidazdms\n",
+      "srsyamajsmedlkssrdloyeagevapwanespcemorhucilkxamhroouevilamsidvarcemgtqggezgfdeaerosyygnideerbnquoit\n",
+      "reprobatesdiyruovasbsidboddubehksoehnssseevklieepuoaetlairetsigamtorocevinneedmspwtnpfincisesuhctulc\n",
+      "smvrnttsdldfysbcontrollablelfsraleaveseuslvpsavsgbtrshalvesylsuougibmaesesimcpgopavhshortensrszzazip\n",
+      "vebaeioliedpmsuesilangisgynainhcazingsyymqoqueryingdoreopenedhsendlessasolbbsqlrlsnikskcubetbrknifed\n",
+      "jiklruonsflefilbsnwodwohsnittupnitfstdretsenohlcrcvsmphngnimirgnidaetsemohgbbaamongstljykwucustomers\n",
+      "doionfghfaalsotejhlrgmewhiieelbbgniretnuasuqsuiouoazeggqrhrisnoituloswselppitueaowymrioutrrbfruitspa\n",
+      "veydjogonywisiutvosplithsejlhpesseieinveighingqymnlerlbukfpineappleeunkagfieensrealiseadelaarjeevell\n",
+      "rkertuiegvgcbodleoievtwhtiiyiomravrsetransducersafelaatemptspbjhkrudenifiudktdscalesfratreaopinionql\n",
+      "tddyoveterinaryoenrnedaebapgowjuiniepsalmistyxadtinnlenvdnakiebrashereatmneirdsnaecomfaeiidedpskfzii\n",
+      "kfpbgdtacoseizlfsrfgimrblebehopnrideraemsnfhropatdcdriuieyjnilvmschkhkweentaoutsmartedwlooaefiekydmb\n",
+      "fewestegwhcpuviacpfrenisreesbtgcktshueckfttuzbemteecaswlpggdaypipmrniakrqeasedoberofmrrqltnhphqdefpn\n",
+      "dyesightingateonspalfngsdqfbxcellistottrnscchhdesshlhefleindegaasmeatewnulcsekytmrgyoaoecoiilanlatao\n",
+      "hddrafobjectkatrsaehgdeertiprrzyalndegmreioascontrritspanloieinwiumlzwaoaiissziicnetuimidictatorialo\n",
+      "renemidmuiretcabgsnwrnhegnoigimletslrywdenreftmdiectrsygdmgrssvsealplyrobcllugxxibegusnmqebycrpsguap\n",
+      "npstekcolsopyhbnsthtschngpsteppeseesoadwcaibraesvsrhiireediprikvrcrlpydniapisenbibanaoicarlyagrflsss\n",
+      "epksewpfsbkymacinimincislpsvsvyifxrpaotoirdfzmtoreoomharntseseltiuazaeeslrxarebiajdahvalaslprnoarbez\n",
+      "soeykbongothistlektasssiidsregsleaiarlreogaiweevilggwznttagrwniaiddroasiioemsoinsaepnnavtrnadidllucs\n",
+      "illoloverwhelmednilnicneegeetcndjasdmduvrchpnnrfzlurdloarnasenilesabemtdtulestkxuiepctesaerrigdekiup\n",
+      "rpriyewmjoqxltmivbalqnrigdnglcniinfdamavaoitsgrskseaeyipikliserpcrtheoryysabushnolreerilpedknniesohw\n",
+      "oproponentsmetliekacotroinaoltrenlinnsidutbgrelrucqpgetgemdklciportosipuaegamitgeplpyautgefegoniarcu\n",
+      "ecaudalyokelrsttynoiifilipiklstsrrtftaenvoyeuristichnludtaqbgsewinngnirabrergentuleaugsnofgdfrgdlibd\n",
+      "hahconfigurationontntzghhtomrbtoteorfsgyguostsefninyoranpsaqtllumsaqodnbecrbdysseoluetatzxpdwhesieee\n",
+      "tpalsygrarcdeobivcsrscinapbtmanirsfmeuliuqnartodayebracpnneowyuaplncaninevnegxeduynrargueuieatllgngp\n",
+      "ixfleshyukesedteemeueruptingtahmlhirugmvrccontrastedhbehugniblpsueiayamsidadinrealahrenyyrrntcwantoy\n",
+      "fefmyoginsnnearnisieripenessjedsmethelnaabsromalgtentrrxnilrkgmjlemigfieryedopiwvttanwiafhnisrsseeth\n",
+      "nonhumanvcknnsnteayuemsncupolargiitapthigreideewosireipieirnooaespoanrcbqygkemwlfieefhdwsppehwmubdkw\n",
+      "bywordswjtosiohmetlestnemegagnedlnstcontyanlaprimessnbmshockerhleydesseheotossealraodauaascpraardpga\n",
+      "outlastedtaocsbbcrxmgjeenilefileeavgotsiulrfordssgtrsettautnessbdebbadieilppfurvpopwylleemnsiuoelksg\n",
+      "ddetsyrtemntalngnpwesuccocddyplqppdeisifmrlpimplyntzecggndsuitcaseskarksnflomdtnekrahecsuetsawfpnpcn\n",
+      "iawaitssbskoedamenelphzijeuhauwpieudrvzvennerraytudtcpasbsencactlocnrcaltifsretaehccsrnempollenagtii\n",
+      "essertsimdaehrsciagdrphststrcocrnvstesidiayejswheosedmerqhhltviuakacooksussocondoretsaocnofktptdnnls\n",
+      "ssrettabiesarptgciideyhitaeidodohbvcynenmsncoesiqyvgvrcuaxauclbcearhgiyhladhniblebiluncraakussenioli\n",
+      "retsimdtluweoolrssfaajxsendnszehoqaxoeesgdtpmoppetsgueeuamoseyumcyganhtlaibeodetoormoisterpejltolial\n",
+      "sbtrsyhbbdtprleinmtddesrtaetjhpilusrlrtdssoqderunettceirlteslhcsneofisxaenssregnifrettubudnodgasbtha\n",
+      "sfeergalebiamfsnouieiobattlaebebeicbdweejrruostolgpozsorslslvleiodefdrietvdniqtadjectivesswdrfgeaapr\n",
+      "widrisitultscrbdccninelelipahgnimeqeisldpjierweqianeubcetoiwsbikcusenerqniiceslaysxrpbmcedunupagnrnt\n",
+      "fcclimocleiasoaegsgignduearteudtutolkjugambolbnsrvyibvoxrerniipmupfdetezmysaatrcmpeatoaarfetmftaeuqn\n",
+      "okideokoslbcewnrxnrsospsnsszreeifelatrinemsnxnaeieeetbcsiurvgiesolqsrtcjyrlinaujstelsneqcpatceeyypte\n",
+      "owdmmeldeargisiraeipeatsenyecsnvfriilatticeworkndlrfesgnihsalpslagfosuunsprlvarnucjotkptardslassgpcc\n",
+      "tryltdndlgeehysamtuhtlcsoitmpscelcascadinghlsiceasiyrseovexeditsnghfshpaslpuadicsoasislliiumtocsguie\n",
+      "wynifnpseydscetdsofacyyiledfiqelihslanifbstslewrevevrycvygetxrhipnestsetoahdstaupsetxneascaearjmisvd\n",
+      "euamraessliuraeicccecnttmstneroynlstodopolansonsadetieeoinoeoeouwiegarrubqyaitovtdeposittdaatnarwael\n",
+      "apmeitrrussrarrazqaaraiosgypgbgagsgieunuteworpwartrnmcbrfdcoddsihrpnbearlusddlltpoesyrrtjsyljalwtghe\n",
+      "rpisasmtoutgidqlsuilctnlgnabiopsyngnbilacwsiibgepeiogstutfnheescseiimptaweiecoaegesdeuyuyfeynominees\n",
+      "aictrsiarorerromgdiipoirfiwgnilratsnibuohortcgnisaefzedrtslrreylcknlooelahckasrvregisdraeslatheriwhr\n",
+      "yekopuspalirtuneenfmresmonbslartueneiloqebeakoihstlhirruqapaptaaonilculirskrsqtnnsntaarttdetcartsbao\n",
+      "bsenobsrclcyamnmeiphrpleenufdeniapeptllnsvkvslkyamymceufsrmawussraneonasdaiutdylsasetmaeacanoesroefm\n",
+      "ruoejoioeatwptmrtkcaarqtgestappinggprodosicahfnmolimiydflecugtudihgvocieiunlerugpshietetniksgipdntmn\n",
+      "flierrooicsrliacagunfirejpwhimsdphaatngrreucasueufnrmnilisihiduinnlibetdnqgerfoceaodidsdewotwokrgals\n",
+      "latconnmtfoessepaimedcsatdeducesddshsvvaunfxnsrnvgszkugiettgdldtgrqnhqykgdnawnekrnilseisnoopingisgil\n",
+      "obmibsssylasirralfpameeviecerggeesemrbegecuebvtstoadspynveaelmhdiresonantgtanaugseitiiruolevtizfreao\n",
+      "uppgdarnsspegnicieersylbatonarpgfhrsodomychaiserelbmuhvgrtnsstseebedliwmoqlarpobncmpryenrapturetertv\n",
+      "tvawrdzsponccwtfsrnclennutrcainoaapnbhodepbfrolicsaktziuogrosseforpqfdbrazzesbolaopaneseifidocselgee\n",
+      "vesjeegvojmooeoeslsthukexwudrarnwanxlkestjacvhscgliatesrohcqsdellennekgiqnslueafsalbtkncttclawsrigrn\n",
+      "ozpbdbycrenekrsindekyasascetredsdodislbrejlrstgocnobscuredhhabsecurerechaliconsfnciacesixcoupledoanl\n",
+      "tlmeicsihqmaximaltedynnwsdstssldoemtiebeedmdnbnngvgnippohcaeetsmespodtfmesosdnesjaloperpetuatingbosi\n",
+      "eegggclassroomssniiralitlpsspsewbidtlelpduyedoicsgumgwfswdnmgfotopaetnrtvlsmovrnsfhfsmpilingcppuiafe\n",
+      "dahhjnprnhwepecnarpeetixyeeredsrtezeredeldmdepkrnmnpqfgsiucsunneaegsueotisaiecreisueyirknittingsbdbr\n",
+      "rtyeenickinglfygenlxrdigwsievneetfcevthaeeolnaceoiwispsenmedeielgrwblmncertrntdxsibdpsaostokenismdad\n",
+      "aeedlafgiuigoarnccgezonchnnlktihttfiasllggalwqitcpcencrpttmteldnnutixisbkiilhgeamyseprzkmrhnmldneild\n",
+      "tvwkibpeatnhwlozifgiigdugtwoafglrtrwizsnwpaiauleaencrorpoaaekiueoissoaihdszanryognhkaaeccceuyegcehad\n",
+      "ifaitnmsephymsvstaxfstrqhlowziiirdendhiornplpesyecbeboigarxcrldhtslpgrnahswasitsraiortdemysvtjaindne\n",
+      "berlyinacaepaeateliyortuetlclofnsirrdrooerleystfdcvlvuytireypiiaidamcyrlessdnoluvyzpcsggsidaimraoect\n",
+      "unloijrerrrcnssacsetuoaaccbpdymciuakfdpreuegatsopasetznlapsnirnmfkzsztynctrgratoeectsoainarepnrmrbet\n",
+      "tgibpsridceottensigittnrntnalaesfsnnseysworddcgtlrdedoygstrlrnggisimxaoinoscvrcharsapcngmesiamnmkkdu\n",
+      "tnkyeuejuuselpscatelhdaaarlegabnaeimriohkinderouaydplerylksleegheueevtteleaeezzaipddpismnmntfgfowcsp\n",
+      "eietdrimpqankffhpyaietgntwtyrbusesgallivantsdyicelxuydpunerjuyttdysinadlcrovejtloeeitsludgeuijnrcipt\n",
+      "rbredgyperimusoejsrbayetimikesplkdebrutrepnumnbrklwmbanpserahfosmtdimieiscovsrdrvtyraomissluafioisiu\n",
+      "nbisluelornaaorsteoastrireitliugselttitndxadgsweiufpreiiadmsbnemilqgcrtrnsiepeclrrapteswovasidfvcgro\n",
+      "uupceraowdyedtgtstulteoneucertsicitnamoraincoatkubfearedkhayyeutycacyclhwlgrcjoeematrvilvendedaeisin\n",
+      "trxrmgmsinimefestaniridihueiokfkdedutingamsnoynacqndecayswceagdoarakagcelniesvsndwomagpinupjyrlfdntd\n",
+      "sgeosdrenblurbscaldahomnnoncncimonoxatkineticrseqorhnarksokurlsqplrreteaiheeeerepwrylykpdtubesuerogi\n",
+      "qmsaesuohdraugzuiecvemsgigtycnangiopatawdrieroawjsonscallopedsesiwpratstclfddoiastelfaelihbumblersru\n",
+      "itekrandomisessvrraayrgripestsivitcellocsbawsshapeliestmjgnitontoofhylluftsaobwsocilacidlocatedlrsee\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(show_grid(pg))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 232,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "2000"
+      ]
+     },
+     "execution_count": 232,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(dws) + len(ws)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 233,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "with open('huge-wordsearch.txt', 'w') as f:\n",
+    "        f.write('{}x{}\\n'.format(len(pg[0]), len(pg)))\n",
+    "        f.write(show_grid(pg))\n",
+    "        f.write('\\n')\n",
+    "        f.write(lcat(sorted(ws + dws)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 234,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(1149, 1149)"
+      ]
+     },
+     "execution_count": 234,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pm = present_many(g, ws)\n",
+    "pold = [w for w in ws if present(g, w)[0]]\n",
+    "len(pm), len(pold)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 235,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(1149, 1149)"
+      ]
+     },
+     "execution_count": 235,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ppm = present_many(pg, ws)\n",
+    "ppold = [w for w in ws if present(pg, w)[0]]\n",
+    "len(ppm), len(ppold)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 236,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "smuiclacphysics.hcnebrevilingd..skcabllup.s...gnitnacs..blusted.....pilafeldrig..enquireddetnawnu...\n",
+      "e....nutmegs.t..telbanimret...e..tseikwagewoodpeckerstirwas.b.r...picksn...ylhsiroobsuspectingsexevd\n",
+      "cgnittacdliw..isuoniallivsegas.lrafts.y.vcs..demrofsnart.mla...e.c....e..fannysdiscrimination.oe..e.\n",
+      "nnytima.wharfrep.stswashbucklersw....m.eos...noprat....ao.rs....t.h..m.relabele..sss...b.sc.ts..vb.s\n",
+      "eid..desivedaia.shegdtg.gniyugys.o..a.rme.gpantedsobeysodgm.a....t.osabound...s.bttp...uje.orhd.boe.\n",
+      "tverediw...dtlw.eiar.ehacrierhsrmccosiant.nbestridi..sreepegarotedadr.slaropauses..e..rdis.oteia.lld\n",
+      "nardd.p...itli.i.pesu.srwe...ciuuhfsnti.sgingivitislubl.fotkcuhs..rmsensitisedeu...eleygbutsiyjcf.u.\n",
+      "eerne.u..aiin.r.i.nset.ioku..taeia.gods.e.n..dh.n.emld.r.lht.hobnobsi.s..l.c.trs...jnb.ieoizw.llka.f\n",
+      "shiense.nhae.s.n.aietun.owig.idtrp.srsayi.w..ogu.oecnie..yo.u...whmt.t..u.a.lcds...tb.ondran.oeersa.\n",
+      ".nhpnnktsts...g.d.cve.qe.pblohdoaseomtc.r.a.tgnrgdnaiae.spd.sc.sora...nt.r.en.no..ro...g.l..msbfdue.\n",
+      ".asxiiasehcnerdj.moido.edsoayvebr.w.ufh.rtr.sgiaxgdekm.rtfo.k.noir.....ag.se..ur.al..sreraehsu.xnoet\n",
+      "gr.erah.peeweeu.i.tdir..h.acc.mard..tie.u.pdeehbo.eyx.u.ralge.kucnoveltiesseirfdp..buttocksn..laodne\n",
+      "nr.sgls..d..sdwrg.iela...c.uikise.o.altwf.i.idcbtged...poeoatsqo...gratefully..sportingsweepersaa..s\n",
+      "iaw.bp...e.hgor.ulnnstullee.ntl.t.mttps.os..d.tienstc...nhggcst.gsugaringinsight..snifters.....cde.i\n",
+      "nta..m..ssteno..i.eckef..b...ar..y.ieu.lpls.n.endirswu..gsiehs..n.delbaf....interpose..dsurt..r.el.u\n",
+      "oeg..oae.usdr..kl..ecd.aiproveso..llsdsayeb.a.ra.iee.er.l.esih.ti.sllihygrellapractisedatcneea..gg.r\n",
+      "sdeb.cziofe.r.e.d..da..rgthrive.p.agearetr.hs.stsavr..riy.srec.ar.pocketbooktrotxe.....nw.unlk..gg.b\n",
+      "a.re.a.m.rs.espumoneb.t..o.semorhc.rnadau.istp.eehio..cpoga.sn.uuyratchetswisher.....n.se..fepc.aos.\n",
+      "e.saf...fsrrh.a.retpada...t.....e.iggiiv.llcaam.vgnt.o.t.sidtu.pj.r.retemarapecnarussau.a.l.frpante.\n",
+      "rretarcurne.c.g.pellagra...s...d.wni.dk.elgnaae.inusm..msgibehfedtsl..prowldenimn.shiedrka...l.il.ss\n",
+      "n..i..leatgbt.rc..s..sesitengamedinkafgnonn.tladta.m....uentbl.aa.oeegniyartrop.eseitoobsnoleme.tpuu\n",
+      "ub.f.lent.gri.afassevissimagingslgiryuoriit...nsahaseigodniiyelwb..upwthguorb.obmil....hfeedings..tr\n",
+      ".a.yydne..aew.ryrri.emackintoshw.trsbnasnh.u..trksr.gasketrpc.raar..ptereinterpretingie....deggiwtnp\n",
+      ".s..nyl...raslitloeett.splinesobtih.gnlgtkt.r.ealwasset....usu.bvgi..eej......rtss.dnrtonnaccords.oa\n",
+      ".ihikers..bkawa.rtssrao...gc.r.yek..ues..rhn.ennaob.gmovers.bid.riwcsketches.esar.etsi.gswollefdebcs\n",
+      ".leticilli.zaen..uftsrnv..log..dils.rrc..noau.nitrlbr.eidrib.iwa.irea..st...ieiadxe.n.lrolocsid....s\n",
+      "sr...m....edl.s...loyeage.ap...e.pc....h..ilk.am.roouevilamsidv.r.e.gt..ge.gfdeaer.s.ygnideerbnquoit\n",
+      "reprobatesdiyruovasbs.d.oddu..hks..h.s..e..kliee.uoae.lairetsigamt.r..e..nneedmsp.t.p.incisesuhctulc\n",
+      "s.vr.t.sdld..s.controllablel.s.aleavese..l..s..s.btrshalvesylsuougibma.s.sim.pgo.avhshortensr.zzazip\n",
+      ".ebae.oliedpmsuesilangisg..a..hc.zingsyy..oqueryingdoreopened..endless...l.bs.lrlsnikskcub.t..knifed\n",
+      "jiklruons.lefilbsnwodwohsn.ttupnit..tdretsenohl..cvsm...gnimirgnidaetsemoh..baamongst..y.wucustomers\n",
+      "doionfgh.a.lsotej.....e.h.iee...gniretnuas..s..o.oa.e.g.r...snoitulos.selppitue..w...io.trrbfruits..\n",
+      ".eydj.g.n..i.iutvosplithsejlhp.s.eieinveighing..mnl.rlbu..pineapple....a.f.e.nsrealiseadel.ar.eevell\n",
+      "r.ertu.e..gc..dleoi....htiiyi.m.avr..transducers.fe.aatempts.b.....d.n.f.ud.t.scales.r.tr.aopinion.l\n",
+      ".d.yoveterinaryoenrn..a.bapg.wjuin..psalmist.x...innlenvd...iebrashereat.ne...snaeco..aeiide.ps...ii\n",
+      "..pb.dtacosei.l.sr.gim.b.eb.ho.nrideraems....opa.dcdri.ie..n.lv.sc.k.kweent.outsmartedwl.oaef.ek..mb\n",
+      "feweste....p.v.a.p..enisreesbtg..t.h.e.k.tt..bem.eecas.lpggday.ipmrn.akrqeasedoberofmrr.l.nhp..de.pn\n",
+      "dy.sighting...o.spalfngsd..b.cellistott.nscc.hdesshlhe.leinde.aas.ea.ewnulcsekytmrg.oa..co..la...tao\n",
+      ".ddr..object...r.aehg.ee..ipr......degmreioascontrrits.an.oieinw.umlzwaoa.iss..i.netu.midictatorialo\n",
+      ".e.em..muiretcab.sn.rnh.gnoigimletslry.denreftmdie.trsygdm.rssvsealplyrobcll.gx.i.egusnm..b.c.ps..ap\n",
+      ".pstekcolsopyh..s...schngpsteppes.esoadwcaib.aesvsrhiiree.iprikvrc.l.ydniapisenb.banaoicar.yagr...ss\n",
+      "ep.sew......macinimin.islp..s....xrpaotoirdf.mto.eoomharntse.elti.a.a.eslrxarebiajdahvalaslprnoarbez\n",
+      "so.ykbongothistlektass.iidsreg..e.ia.lreogaiweevilgg..n.tagrw.ia.d.r..s.ioemsoinsa.pnnavtr.adidllucs\n",
+      "il.oloverwhelmednilni.neegee.cnd.as.mduvrch.n.r..lurd.oarnasenilesab..t.tul.stkxuie.ctesae.rigd.....\n",
+      "rp..y.......l..ivbal.nrigdn.l.ni.n.damava..t.g...seaeyi.ik..se...rtheoryysab.shnolreeril.edknniesohw\n",
+      "oproponents.etli.kacotr.in.o.t.en.innsidu...relruc.pgetge.d.lciportosi...ega.itgeplpyautge.egon.ar..\n",
+      "ecaudalyokelrst.ynoiif.l.piklstsrrtf.aenvoyeuristichnludta.b.se.i.ngnirabrer.entuleaugsno.gd.rgdlibd\n",
+      "h..configurationontnt.g...omr.toteo.fsg.g..stsefni.yora.psa.t.l.msa.....e.rbd.sseol.e.at.x.dwhesieee\n",
+      "tpalsy.r..c.e..ivcsrscinap.tma.irsfm.uliuqnartoday..racp.neo..u.plncaninev.eg.eduynr.rg.e.ieat.lgngp\n",
+      "..fleshyuk.s.dteeme.eruptingtah.lhir.gm.r.contrastedhbe.ugni..p.uei.yamsidad.nreal..r.ny.rrntc.antoy\n",
+      "....yogins..earnis..ripeness.edsmethe.na.bsromalgte.trr.ni..k.m.lemigfieryed..iwvtta.wia.hnis.ss.eth\n",
+      "nonhuman..knnsnte...e...cupolargiitapt.igreideew.s.re.pie....oaespo.nrcb.y.ke.wlfiee.hdws.p...mu.d..\n",
+      "bywords...osiohme..estnemegagnedlnstcon.ya...primessn.mshockerhleyd..sehe.t.ssealra.daua.s....ar....\n",
+      "outlastedt.ocsb.c.x....enilefileeavgotsi.lrfordssgt..ettautnessbdebbadieil.p.ur.po.w.lle......oe.k.g\n",
+      "ddetsyrte.n..l.gnp.esuccocddypl.ppdeisi..rlpimplyn..ecg..dsuitcases.a.ksnfl.mdtnekrahecs.etsawfpn.cn\n",
+      "iawaitss.s..e.a.e..lp....euhauwpi.udrv.ve..er.a..udt..as.se...ctlocn.c.ltifsretaehcc.rnempollenag.ii\n",
+      "essertsimdaehrsci.gdr...tstrcocrn.stesidi..ejs...o.e..erq..lt.i.akaco.ksussocondoretsaocno....tdnnls\n",
+      "s.rettab.es.rptgc.ide..itaeidodohb.cynen.sn.o....y..vrcua..uclb.earhgiyhla.hn..lebil..c..ak..senioli\n",
+      "retsim.tlu.eoo.rssfaa.xsendns.ehoqa.oeesgdtpmoppets.ueeu.moseyu.cygan.tlaib..detoormoisterpe.l.olial\n",
+      "......hbbdtpr..inmt.desrtaetjhpilu.rlrtdsso.derunettceirltesl.csneofis.aenssregnifrettub...od.asbtha\n",
+      "sfeergalebia.f.noui.iobattlae.ebei.bdwe..r..os...gpoz.orslsl.le.odefdr..tvdn...adjectivess.dr.geaapr\n",
+      "....isitultscrbdccn.n.lelipa.gnime..is.dp....we..ane.b..toi..bikc.sener..ii.eslays.rp..c.du..pagnr.t\n",
+      "f..limocleiasoaegsgignduear..udtut.l...gambol.nsrv.ib.o.re.ni..mupfdete..ysa.t....ea.oa..fetm.taeu.n\n",
+      "o.ideokoslb.ewnr.nrso.psnss.reeifelatrinems....ei..etb.s..rvg...ol..rtc.y.lin.u..t.lsne.cp.tceeyypte\n",
+      "owd.mel.ear.isir.eipeatsenye.snvfr..latticeworkndlrfesgnihsalpslagf.suunsprlv...u..otk.tardslassgpcc\n",
+      "t.yltd.dl.e.hysam.uhtl.so.tm.scelcascadinghl..c.asiyrse.vexed.tsng.fshpaslpua..c.oasislliiumtocsguie\n",
+      "wynifnpseydscetdso.acyyi.e..i.elihslanifbstsle.r.vevrycv.....rhi.ne.tsetoahdstaupset..eascae.rj.isvd\n",
+      "euamrae.sliuraeicccecnttmstner.yn.st....olansonsade.ieeoi...oeo..i.ga.rubqyaito..deposittdaat.a.wael\n",
+      "apmeitr.ussrarra..aaraiosgy...g.g.gie...tewor.wart.n.cbrfd.odds.hrpnb.ar.usddlltpoesyrr.js.l...wt.he\n",
+      "rpisasmtoutgid.l..ilctnl.nabiopsy.gnbi..cwsii.gepei.g..u.fn.ee.cseiimptaweiecoae..s.euyu...ynominees\n",
+      ".ictrsiarorerr..gdiipoi.fiwgnilratsnibu.hortcgn.saef.e.rtslrre.lcknlooelahcka.rvre.isdraeslather...r\n",
+      "yekopuspalirtu.eenf.re.m.nbslartueneiloqebeakoihstlhi.ru...ap.aaonilculirskrs..nnsntaarttdetcartsbao\n",
+      ".s.n.bsrclcyamnmei.h.pl..nu.deniapeptllns.kvslky.mymce.fs.mawussrane.nasdaiut.ylsasetmae.canoes.oe.m\n",
+      "...e.oio.at.ptmrt.c..r...estappinggp.odos.cahfnm..imi.dfl.c.gtudihgv.cieiunlerugpshietetniksgipdnt..\n",
+      "flierroo.cs.liac.gunfire.pwhimsd..aa..grr.ucasue...rmn.lis.hidu.n..i.etdnqgerfoceaodidsdewotwokrgals\n",
+      "latconnm.f.e..epaimedc...deducesddshs..aunfx..rn....kugie.tgdl..g..n..y.g.nawn.krnilse.snoopingisgil\n",
+      "obmibsss..asir..l..a.eeviecerggee.em....ecue..tstoadspynveael....resonantgtan.ugseiti.ruolev...freao\n",
+      "u..gdarnsspegniciee.sylbatonarpgfhrsodomychaiserelbmuh.grtnsstseebedliw.o.la.p..ncmpr.enrapturetertv\n",
+      "t...rd...oncc.t.srnclennut.cainoaap...od..bfrolics.k....o.rosseforp...brazzesb.laopa.eseifidoc.elgee\n",
+      "v...ee..o..ooe.eslsth.ke...drarnwan.l.es..a...sc.liatesrohc.sdellennekgi..s.u.af.albtkn...clawsrigrn\n",
+      "o..bdbyc....krsindekyasa..etredsdodi.l.re.l..tgo.nobscuredhh..securere..al.c.nsfn.iace.i.coupledoanl\n",
+      "t.mei.si..maximaltedynn.sdstss.doem.iebe.dm.n.nng.gnippohca....m....dt..eso.dnes.a.operpetuatingbo.i\n",
+      "eegggclassroomss...ral.t.pssp.ewbidtlelpd.yedoic.g.....s.dnm..otopaetn.t.lsmov..sfh.s.piling....i..e\n",
+      "dahh.n...h..pecnarpeeti.yeeredsrte.ere.e..mdepkrn.np....iucsun..ae...eotisaie..eis.ey.rknittings..br\n",
+      "rt.eenickinglfy...l.rdig..ie.neet.cev.ha.eo.naceo.wispsenme.eie.gr..lmncertrntdxs.bdpsao.tokenismda.\n",
+      "...dla.g..i.oar.cc.e.onchnn.ktihttfi.s.lgg.lwqitcp.en.rpttmt.ldnn.ti.i.bkii.hgeamyseprzk.r..mld.e.l.\n",
+      ".vwkibp.a.n.wlo.ifg..g.ugtw.afglrtr.i..nwpa.auleae.crorpoaaek.ueo.ssoai.ds.a.ryognhkaaec..euye.ce.ad\n",
+      "..ai.nmseph.msvsta..st.qh.ow.iiirden..iornp.pes.ec.eboigarxcrld.tslp.r.ahsw.sitsra.ortde..svt.a.ndne\n",
+      "b.rl.inacae.aeatel.yortuetl.l.fn.irr.rooe..e.s..dcv.vuytireypii.i.a.c.rlessdnoluvy.pcsggsidaim.aoect\n",
+      "u.loi.rerrr.nssacs.tuoaac.bp.y..iuakfdpr..egatsopasetznlapsni.nmf.zs.tynctrgrato..c.so.in.repnr.rbet\n",
+      "tgibps.idceott.nsi.ittnrntnalaesfsnnseysword.c..lrdedoygst.lrnggisi.xaoinoscvrcharsa.cngmesiamn.kkdu\n",
+      "tnkye.e.uusel..cat.lh.aaa.legabnaei.r...kinderou.y.pler.lksleeg.e.eevtteleaeezzaipddpis.nmntfgfo.csp\n",
+      "eietd..mpqankffh.yaie.gnt.....use.gallivants..ic.l.uydpuner.uyttdysinadlcrove....ee.tslu.geuijnrcipt\n",
+      "rbred..peri.usoe.srbayetimikespl.debrutrepnu.n.rkl.mb.npsera.fosm.dimieiscovsrd.vtyr.om...l..fioisiu\n",
+      "nbisl.e.or.a..rs.eoastrireitliugselttit.....g..e.u.pr..iadmsbnemil.gcrt..siepeclrrapteswovasidfvcgro\n",
+      "uupcer.o..y.d.gtstulte.ne...rtsicitnamoraincoatk.bfearedkhayyeutycacyc.hwlgrc.oeematr...vended.ei.i.\n",
+      "trxrm.msinimefe.tani.i.ih..i.....edutingamsnoynac..decay..ceagd.ara.a.celnie.vsndwo...pinup...l.dntd\n",
+      "sgeosdrenblurbscalda.o.nn.n..cimonoxatkinetic..e....narks.k.rl..pl.r.teaihe.eer.pwryly...tubes.e..g.\n",
+      "..saesuohdraug..ie.v.m.gig.ycnangiop.tawdrier..w....scallopedsesiwp.atstcl.ddo.astelfael..bumblers..\n",
+      ".t.krandomises..rr.a..gripestsivitcellocsbawsshapeliest..gnitontoofhylluftsaobwsocilac..located..s..\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(show_grid(g))"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/04-word-search/wordsearch-exploratory-solving.ipynb b/04-word-search/wordsearch-exploratory-solving.ipynb
new file mode 100644 (file)
index 0000000..2fcc075
--- /dev/null
@@ -0,0 +1,2493 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Wordsearch\n",
+    "Given a text file, consisting of three parts (a grid size, a grid, and a list of words), find:\n",
+    "* the words present in the grid, \n",
+    "* the longest word present in the grid, \n",
+    "* the number of words not present in the grid, \n",
+    "* the longest word not present that can be formed from the leftover letters\n",
+    "\n",
+    "The only words that need be considered are the ones given in the list in the puzzle input.\n",
+    "\n",
+    "The puzzle consists of:\n",
+    "1. A line consisting of _w_`x`_h_, where _w_ and _h_ are integers giving the width and height of the grid.\n",
+    "2. The grid itself, consisting of _h_ lines each of _w_ letters.\n",
+    "3. A list of words, one word per line, of arbitrary length. "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Example\n",
+    "\n",
+    "\n",
+    "`...p.mown.\n",
+    ".sdse..ee.\n",
+    ".e.elad.cr\n",
+    "pi.dtir.ah\n",
+    "rzsiwovspu\n",
+    "oawh.kieab\n",
+    "brow.c.rda\n",
+    "ecnotops.r\n",
+    "d.kc.d...b\n",
+    ".staple...`\n",
+    "\n",
+    "```\n",
+    "fhjpamownq\n",
+    "wsdseuqeev\n",
+    "ieaeladhcr\n",
+    "piedtiriah\n",
+    "rzsiwovspu\n",
+    "oawhakieab\n",
+    "browpcfrda\n",
+    "ecnotopssr\n",
+    "dikchdnpnb\n",
+    "bstapleokr\n",
+    "```\n",
+    "\n",
+    "14 words added;  6 directions\n",
+    "\n",
+    "Present: apace cowhides crazies dock knows lived mown pears probed rhubarb rioted staple tops wide\n",
+    "\n",
+    "Decoys: adapting bombing boor brick cackles carnal casino chaplets chump coaster coccyxes coddle collies creels crumbled cunt curds curled curlier deepen demeanor dicier dowses ensuing faddish fest fickler foaming gambol garoting gliding gristle grunts guts ibex impugns instants kielbasy lanyard loamier lugs market meanly minuend misprint mitts molested moonshot mucking oaks olives orgasmic pastrami perfect proceed puckered quashed refined regards retraces revel ridges ringlet scoff shinier siren solaria sprain sunder sunup tamped tapes thirds throw tiller times trains tranquil transfix typesets uric wariness welts whimsy winced winced\n",
+    "\n",
+    "Decoys: fickler, adapting, chump, foaming, molested, carnal, crumbled, guts, minuend, bombing, winced, coccyxes, solaria, shinier, cackles\n",
+    "\n",
+    "All words: adapting, apace, bombing, cackles, carnal, chump, coccyxes, cowhides, crazies, crumbled, dock, fickler, foaming, guts, knows, lived, minuend, molested, mown, pears, probed, rhubarb, rioted, shinier, solaria, staple, tops, wide, winced\n",
+    "\n",
+    "Directions:  [('probed', '`(True, 3, 0, <Direction.down: 4>)`'), ('staple', '`(True, 9, 1, <Direction.right: 2>)`'), ('rioted', '`(True, 6, 7, <Direction.upleft: 5>)`'), ('cowhides', '`(True, 8, 3, <Direction.up: 3>)`'), ('tops', '`(True, 7, 4, <Direction.right: 2>)`'), ('knows', '`(True, 8, 2, <Direction.up: 3>)`'), ('lived', '`(True, 2, 4, <Direction.downright: 8>)`'), ('rhubarb', '`(True, 2, 9, <Direction.down: 4>)`'), ('crazies', '`(True, 7, 1, <Direction.up: 3>)`'), ('dock', '`(True, 8, 5, <Direction.up: 3>)`'), ('apace', '`(True, 5, 8, <Direction.up: 3>)`'), ('mown', '`(True, 0, 5, <Direction.right: 2>)`'), ('pears', '`(True, 0, 3, <Direction.downright: 8>)`'), ('wide', '`(True, 4, 4, <Direction.upright: 6>)`')]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import string\n",
+    "import re\n",
+    "import collections\n",
+    "import copy\n",
+    "import os\n",
+    "\n",
+    "from enum import Enum\n",
+    "Direction = Enum('Direction', 'left right up down upleft upright downleft downright')\n",
+    "    \n",
+    "delta = {Direction.left: (0, -1),Direction.right: (0, 1), \n",
+    "         Direction.up: (-1, 0), Direction.down: (1, 0), \n",
+    "         Direction.upleft: (-1, -1), Direction.upright: (-1, 1), \n",
+    "         Direction.downleft: (1, -1), Direction.downright: (1, 1)}\n",
+    "\n",
+    "cat = ''.join\n",
+    "wcat = ' '.join\n",
+    "lcat = '\\n'.join"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def empty_grid(w, h):\n",
+    "    return [['.' for c in range(w)] for r in range(h)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def show_grid(grid):\n",
+    "    return lcat(cat(r) for r in grid)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def indices(grid, r, c, l, d):\n",
+    "    dr, dc = delta[d]\n",
+    "    w = len(grid[0])\n",
+    "    h = len(grid)\n",
+    "    inds = [(r + i * dr, c + i * dc) for i in range(l)]\n",
+    "    return [(i, j) for i, j in inds\n",
+    "           if i >= 0\n",
+    "           if j >= 0\n",
+    "           if i < h\n",
+    "           if j < w]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def gslice(grid, r, c, l, d):\n",
+    "    return [grid[i][j] for i, j in indices(grid, r, c, l, d)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def set_grid(grid, r, c, d, word):\n",
+    "    for (i, j), l in zip(indices(grid, r, c, len(word), d), word):\n",
+    "        grid[i][j] = l\n",
+    "    return grid"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def present(grid, word):\n",
+    "    w = len(grid[0])\n",
+    "    h = len(grid)\n",
+    "    for r in range(h):\n",
+    "        for c in range(w):\n",
+    "            for d in Direction:\n",
+    "                if cat(gslice(grid, r, c, len(word), d)) == word:\n",
+    "                    return True, r, c, d\n",
+    "    return False, 0, 0, list(Direction)[0]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 158,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def present_many(grid, words):\n",
+    "    w = len(grid[0])\n",
+    "    h = len(grid)\n",
+    "    wordlens = set(len(w) for w in words)\n",
+    "    presences = []\n",
+    "    for r in range(h):\n",
+    "        for c in range(w):\n",
+    "            for d in Direction:\n",
+    "                for wordlen in wordlens:\n",
+    "                    word = cat(gslice(grid, r, c, wordlen, d))\n",
+    "                    if word in words:\n",
+    "                        presences += [(word, r, c, d)]\n",
+    "    return set(presences)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 141,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# def present_many(grid, words):\n",
+    "#     w = len(grid[0])\n",
+    "#     h = len(grid)\n",
+    "#     wordlens = set(len(w) for w in words)\n",
+    "#     presences = set()\n",
+    "#     for r in range(h):\n",
+    "#         for c in range(w):\n",
+    "#             for d in Direction:\n",
+    "#                 for wordlen in wordlens:\n",
+    "#                     word = cat(gslice(grid, r, c, wordlen, d))\n",
+    "#                     if word in words:\n",
+    "#                         presences.add((word, r, c, d))\n",
+    "#     return presences"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def read_wordsearch(fn):\n",
+    "    lines = [l.strip() for l in open(fn).readlines()]\n",
+    "    w, h = [int(s) for s in lines[0].split('x')]\n",
+    "    grid = lines[1:h+1]\n",
+    "    words = lines[h+1:]\n",
+    "    return w, h, grid, words"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 49,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(['pistrohxegniydutslxt',\n",
+       "  'wmregunarbpiledsyuoo',\n",
+       "  'hojminbmutartslrlmgo',\n",
+       "  'isrsdniiekildabolpll',\n",
+       "  'tstsnyekentypkalases',\n",
+       "  'ssnetengcrfetedirgdt',\n",
+       "  'religstasuslatxauner',\n",
+       "  'elgcpgatsklglzistilo',\n",
+       "  'tndlimitationilkasan',\n",
+       "  'aousropedlygiifeniog',\n",
+       "  'kilrprepszffsyzqsrhs',\n",
+       "  'itlaadorableorpccese',\n",
+       "  'noaeewoodedpngmqicnl',\n",
+       "  'gmrtoitailingchelrok',\n",
+       "  'jadsngninetsahtooeic',\n",
+       "  'xeernighestsailarmtu',\n",
+       "  'aeabsolvednscumdfnon',\n",
+       "  'gydammingawlcandornk',\n",
+       "  'hurlerslvkaccxcinosw',\n",
+       "  'iqnanoitacifitrofqqi'],\n",
+       " ['absolved',\n",
+       "  'adorable',\n",
+       "  'aeon',\n",
+       "  'alias',\n",
+       "  'ancestor',\n",
+       "  'baritone',\n",
+       "  'bemusing',\n",
+       "  'blonds',\n",
+       "  'bran',\n",
+       "  'calcite',\n",
+       "  'candor',\n",
+       "  'conciseness',\n",
+       "  'consequent',\n",
+       "  'cuddle',\n",
+       "  'damming',\n",
+       "  'dashboards',\n",
+       "  'despairing',\n",
+       "  'dint',\n",
+       "  'dullard',\n",
+       "  'dynasty',\n",
+       "  'employer',\n",
+       "  'exhorts',\n",
+       "  'feted',\n",
+       "  'fill',\n",
+       "  'flattens',\n",
+       "  'foghorn',\n",
+       "  'fortification',\n",
+       "  'freakish',\n",
+       "  'frolics',\n",
+       "  'gall',\n",
+       "  'gees',\n",
+       "  'genies',\n",
+       "  'gets',\n",
+       "  'hastening',\n",
+       "  'hits',\n",
+       "  'hopelessness',\n",
+       "  'hurlers',\n",
+       "  'impales',\n",
+       "  'infix',\n",
+       "  'inflow',\n",
+       "  'innumerable',\n",
+       "  'intentional',\n",
+       "  'jerkin',\n",
+       "  'justification',\n",
+       "  'kitty',\n",
+       "  'knuckles',\n",
+       "  'leaving',\n",
+       "  'like',\n",
+       "  'limitation',\n",
+       "  'locoweeds',\n",
+       "  'loot',\n",
+       "  'lucking',\n",
+       "  'lumps',\n",
+       "  'mercerising',\n",
+       "  'monickers',\n",
+       "  'motionless',\n",
+       "  'naturally',\n",
+       "  'nighest',\n",
+       "  'notion',\n",
+       "  'ogled',\n",
+       "  'originality',\n",
+       "  'outings',\n",
+       "  'pendulous',\n",
+       "  'piled',\n",
+       "  'pins',\n",
+       "  'pithier',\n",
+       "  'prep',\n",
+       "  'randomness',\n",
+       "  'rectors',\n",
+       "  'redrew',\n",
+       "  'reformulated',\n",
+       "  'remoteness',\n",
+       "  'retaking',\n",
+       "  'rethink',\n",
+       "  'rope',\n",
+       "  'rubier',\n",
+       "  'sailors',\n",
+       "  'scowls',\n",
+       "  'scum',\n",
+       "  'sepals',\n",
+       "  'sequencers',\n",
+       "  'serf',\n",
+       "  'shoaled',\n",
+       "  'shook',\n",
+       "  'sonic',\n",
+       "  'spottiest',\n",
+       "  'stag',\n",
+       "  'stood',\n",
+       "  'stratum',\n",
+       "  'strong',\n",
+       "  'studying',\n",
+       "  'surtaxing',\n",
+       "  'tailing',\n",
+       "  'tears',\n",
+       "  'teazles',\n",
+       "  'vans',\n",
+       "  'wardrobes',\n",
+       "  'wooded',\n",
+       "  'worsts',\n",
+       "  'zings'])"
+      ]
+     },
+     "execution_count": 49,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "width, height, g, ws = read_wordsearch('wordsearch04.txt')\n",
+    "g, ws"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 50,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "absolved (True, 16, 2, <Direction.right: 2>)\n",
+      "adorable (True, 11, 4, <Direction.right: 2>)\n",
+      "aeon (True, 11, 4, <Direction.down: 4>)\n",
+      "alias (True, 15, 15, <Direction.left: 1>)\n",
+      "ancestor (False, 0, 0, <Direction.left: 1>)\n",
+      "baritone (False, 0, 0, <Direction.left: 1>)\n",
+      "bemusing (False, 0, 0, <Direction.left: 1>)\n",
+      "blonds (False, 0, 0, <Direction.left: 1>)\n",
+      "bran (True, 1, 9, <Direction.left: 1>)\n",
+      "calcite (True, 19, 9, <Direction.upright: 6>)\n",
+      "candor (True, 17, 12, <Direction.right: 2>)\n",
+      "conciseness (False, 0, 0, <Direction.left: 1>)\n",
+      "consequent (False, 0, 0, <Direction.left: 1>)\n",
+      "cuddle (False, 0, 0, <Direction.left: 1>)\n",
+      "damming (True, 17, 2, <Direction.right: 2>)\n",
+      "dashboards (False, 0, 0, <Direction.left: 1>)\n",
+      "despairing (False, 0, 0, <Direction.left: 1>)\n",
+      "dint (False, 0, 0, <Direction.left: 1>)\n",
+      "dullard (True, 8, 2, <Direction.down: 4>)\n",
+      "dynasty (True, 3, 4, <Direction.downright: 8>)\n",
+      "employer (False, 0, 0, <Direction.left: 1>)\n",
+      "exhorts (True, 0, 8, <Direction.left: 1>)\n",
+      "feted (True, 5, 10, <Direction.right: 2>)\n",
+      "fill (True, 9, 14, <Direction.upleft: 5>)\n",
+      "flattens (True, 10, 10, <Direction.upleft: 5>)\n",
+      "foghorn (True, 10, 11, <Direction.downright: 8>)\n",
+      "fortification (True, 19, 16, <Direction.left: 1>)\n",
+      "freakish (False, 0, 0, <Direction.left: 1>)\n",
+      "frolics (True, 16, 16, <Direction.up: 3>)\n",
+      "gall (False, 0, 0, <Direction.left: 1>)\n",
+      "gees (True, 17, 0, <Direction.upright: 6>)\n",
+      "genies (True, 5, 7, <Direction.upleft: 5>)\n",
+      "gets (True, 6, 4, <Direction.upleft: 5>)\n",
+      "hastening (True, 14, 13, <Direction.left: 1>)\n",
+      "hits (True, 2, 0, <Direction.down: 4>)\n",
+      "hopelessness (False, 0, 0, <Direction.left: 1>)\n",
+      "hurlers (True, 18, 0, <Direction.right: 2>)\n",
+      "impales (False, 0, 0, <Direction.left: 1>)\n",
+      "infix (False, 0, 0, <Direction.left: 1>)\n",
+      "inflow (False, 0, 0, <Direction.left: 1>)\n",
+      "innumerable (False, 0, 0, <Direction.left: 1>)\n",
+      "intentional (False, 0, 0, <Direction.left: 1>)\n",
+      "jerkin (False, 0, 0, <Direction.left: 1>)\n",
+      "justification (False, 0, 0, <Direction.left: 1>)\n",
+      "kitty (True, 8, 15, <Direction.upleft: 5>)\n",
+      "knuckles (True, 17, 19, <Direction.up: 3>)\n",
+      "leaving (False, 0, 0, <Direction.left: 1>)\n",
+      "like (True, 3, 11, <Direction.left: 1>)\n",
+      "limitation (True, 8, 3, <Direction.right: 2>)\n",
+      "locoweeds (False, 0, 0, <Direction.left: 1>)\n",
+      "loot (True, 3, 19, <Direction.up: 3>)\n",
+      "lucking (True, 7, 10, <Direction.upleft: 5>)\n",
+      "lumps (True, 0, 17, <Direction.down: 4>)\n",
+      "mercerising (True, 15, 17, <Direction.up: 3>)\n",
+      "monickers (False, 0, 0, <Direction.left: 1>)\n",
+      "motionless (True, 13, 1, <Direction.up: 3>)\n",
+      "naturally (True, 9, 16, <Direction.up: 3>)\n",
+      "nighest (True, 15, 4, <Direction.right: 2>)\n",
+      "notion (True, 17, 18, <Direction.up: 3>)\n",
+      "ogled (True, 1, 18, <Direction.down: 4>)\n",
+      "originality (False, 0, 0, <Direction.left: 1>)\n",
+      "outings (False, 0, 0, <Direction.left: 1>)\n",
+      "pendulous (False, 0, 0, <Direction.left: 1>)\n",
+      "piled (True, 1, 10, <Direction.right: 2>)\n",
+      "pins (True, 7, 4, <Direction.upleft: 5>)\n",
+      "pithier (False, 0, 0, <Direction.left: 1>)\n",
+      "prep (True, 10, 4, <Direction.right: 2>)\n",
+      "randomness (False, 0, 0, <Direction.left: 1>)\n",
+      "rectors (False, 0, 0, <Direction.left: 1>)\n",
+      "redrew (False, 0, 0, <Direction.left: 1>)\n",
+      "reformulated (False, 0, 0, <Direction.left: 1>)\n",
+      "remoteness (False, 0, 0, <Direction.left: 1>)\n",
+      "retaking (True, 6, 0, <Direction.down: 4>)\n",
+      "rethink (False, 0, 0, <Direction.left: 1>)\n",
+      "rope (True, 9, 4, <Direction.right: 2>)\n",
+      "rubier (True, 0, 4, <Direction.downright: 8>)\n",
+      "sailors (True, 7, 15, <Direction.up: 3>)\n",
+      "scowls (False, 0, 0, <Direction.left: 1>)\n",
+      "scum (True, 16, 11, <Direction.right: 2>)\n",
+      "sepals (True, 6, 10, <Direction.upright: 6>)\n",
+      "sequencers (False, 0, 0, <Direction.left: 1>)\n",
+      "serf (False, 0, 0, <Direction.left: 1>)\n",
+      "shoaled (True, 11, 18, <Direction.up: 3>)\n",
+      "shook (False, 0, 0, <Direction.left: 1>)\n",
+      "sonic (True, 18, 18, <Direction.left: 1>)\n",
+      "spottiest (False, 0, 0, <Direction.left: 1>)\n",
+      "stag (True, 7, 8, <Direction.left: 1>)\n",
+      "stood (False, 0, 0, <Direction.left: 1>)\n",
+      "stratum (True, 2, 13, <Direction.left: 1>)\n",
+      "strong (True, 4, 19, <Direction.down: 4>)\n",
+      "studying (True, 0, 16, <Direction.left: 1>)\n",
+      "surtaxing (False, 0, 0, <Direction.left: 1>)\n",
+      "tailing (True, 13, 6, <Direction.right: 2>)\n",
+      "tears (True, 13, 3, <Direction.up: 3>)\n",
+      "teazles (True, 4, 10, <Direction.downright: 8>)\n",
+      "vans (True, 18, 8, <Direction.upright: 6>)\n",
+      "wardrobes (False, 0, 0, <Direction.left: 1>)\n",
+      "wooded (True, 12, 5, <Direction.right: 2>)\n",
+      "worsts (True, 1, 0, <Direction.downright: 8>)\n",
+      "zings (True, 10, 14, <Direction.upleft: 5>)\n"
+     ]
+    }
+   ],
+   "source": [
+    "for w in ws:\n",
+    "    print(w, present(g, w))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Which words are present?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 69,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 loop, best of 3: 1.28 s per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "[w for w in ws if present(g, w)[0]]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 70,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 loop, best of 3: 215 ms per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "[p[0] for p in present_many(g, ws)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 61,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['absolved',\n",
+       " 'adorable',\n",
+       " 'aeon',\n",
+       " 'alias',\n",
+       " 'ancestor',\n",
+       " 'baritone',\n",
+       " 'bemusing',\n",
+       " 'blonds',\n",
+       " 'bran',\n",
+       " 'calcite',\n",
+       " 'candor',\n",
+       " 'conciseness',\n",
+       " 'consequent',\n",
+       " 'cuddle',\n",
+       " 'damming',\n",
+       " 'dashboards',\n",
+       " 'despairing',\n",
+       " 'dint',\n",
+       " 'dullard',\n",
+       " 'dynasty',\n",
+       " 'employer',\n",
+       " 'exhorts',\n",
+       " 'feted',\n",
+       " 'fill',\n",
+       " 'flattens',\n",
+       " 'foghorn',\n",
+       " 'fortification',\n",
+       " 'freakish',\n",
+       " 'frolics',\n",
+       " 'gall',\n",
+       " 'gees',\n",
+       " 'genies',\n",
+       " 'gets',\n",
+       " 'hastening',\n",
+       " 'hits',\n",
+       " 'hopelessness',\n",
+       " 'hurlers',\n",
+       " 'impales',\n",
+       " 'infix',\n",
+       " 'inflow',\n",
+       " 'innumerable',\n",
+       " 'intentional',\n",
+       " 'jerkin',\n",
+       " 'justification',\n",
+       " 'kitty',\n",
+       " 'knuckles',\n",
+       " 'leaving',\n",
+       " 'like',\n",
+       " 'limitation',\n",
+       " 'locoweeds',\n",
+       " 'loot',\n",
+       " 'lucking',\n",
+       " 'lumps',\n",
+       " 'mercerising',\n",
+       " 'monickers',\n",
+       " 'motionless',\n",
+       " 'naturally',\n",
+       " 'nighest',\n",
+       " 'notion',\n",
+       " 'ogled',\n",
+       " 'originality',\n",
+       " 'outings',\n",
+       " 'pendulous',\n",
+       " 'piled',\n",
+       " 'pins',\n",
+       " 'pithier',\n",
+       " 'prep',\n",
+       " 'randomness',\n",
+       " 'rectors',\n",
+       " 'redrew',\n",
+       " 'reformulated',\n",
+       " 'remoteness',\n",
+       " 'retaking',\n",
+       " 'rethink',\n",
+       " 'rope',\n",
+       " 'rubier',\n",
+       " 'sailors',\n",
+       " 'scowls',\n",
+       " 'scum',\n",
+       " 'sepals',\n",
+       " 'sequencers',\n",
+       " 'serf',\n",
+       " 'shoaled',\n",
+       " 'shook',\n",
+       " 'sonic',\n",
+       " 'spottiest',\n",
+       " 'stag',\n",
+       " 'stood',\n",
+       " 'stratum',\n",
+       " 'strong',\n",
+       " 'studying',\n",
+       " 'surtaxing',\n",
+       " 'tailing',\n",
+       " 'tears',\n",
+       " 'teazles',\n",
+       " 'vans',\n",
+       " 'wardrobes',\n",
+       " 'wooded',\n",
+       " 'worsts',\n",
+       " 'zings']"
+      ]
+     },
+     "execution_count": 61,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ws"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "What is the longest word that is present?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'fortification'"
+      ]
+     },
+     "execution_count": 15,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "sorted([w for w in ws if present(g, w)[0]], key=len)[-1]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "What is the longest word that is absent?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'justification'"
+      ]
+     },
+     "execution_count": 16,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "sorted([w for w in ws if not present(g, w)[0]], key=len)[-1]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "How many letters are unused?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "57"
+      ]
+     },
+     "execution_count": 17,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "g0 = empty_grid(width, height)\n",
+    "for w in ws:\n",
+    "    p, r, c, d = present(g, w)\n",
+    "    if p:\n",
+    "        set_grid(g0, r, c, d, w)\n",
+    "len([c for c in cat(cat(l) for l in g0) if c == '.'])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "What is the longest word you can make form the leftover letters?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "Counter({'a': 4,\n",
+       "         'b': 1,\n",
+       "         'c': 5,\n",
+       "         'd': 3,\n",
+       "         'e': 1,\n",
+       "         'g': 2,\n",
+       "         'i': 5,\n",
+       "         'j': 2,\n",
+       "         'k': 3,\n",
+       "         'l': 2,\n",
+       "         'm': 3,\n",
+       "         'n': 3,\n",
+       "         'p': 3,\n",
+       "         'q': 5,\n",
+       "         'r': 3,\n",
+       "         's': 3,\n",
+       "         'w': 2,\n",
+       "         'x': 4,\n",
+       "         'y': 2,\n",
+       "         'z': 1})"
+      ]
+     },
+     "execution_count": 18,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "unused_letters = [l for l, u in zip((c for c in cat(cat(l) for l in g)), (c for c in cat(cat(l) for l in g0)))\n",
+    "                  if u == '.']\n",
+    "unused_letter_count = collections.Counter(unused_letters)\n",
+    "unused_letter_count"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['ancestor',\n",
+       " 'baritone',\n",
+       " 'bemusing',\n",
+       " 'blonds',\n",
+       " 'conciseness',\n",
+       " 'consequent',\n",
+       " 'cuddle',\n",
+       " 'dashboards',\n",
+       " 'despairing',\n",
+       " 'dint',\n",
+       " 'employer',\n",
+       " 'freakish',\n",
+       " 'gall',\n",
+       " 'hopelessness',\n",
+       " 'impales',\n",
+       " 'infix',\n",
+       " 'inflow',\n",
+       " 'innumerable',\n",
+       " 'intentional',\n",
+       " 'jerkin',\n",
+       " 'justification',\n",
+       " 'leaving',\n",
+       " 'locoweeds',\n",
+       " 'monickers',\n",
+       " 'originality',\n",
+       " 'outings',\n",
+       " 'pendulous',\n",
+       " 'pithier',\n",
+       " 'randomness',\n",
+       " 'rectors',\n",
+       " 'redrew',\n",
+       " 'reformulated',\n",
+       " 'remoteness',\n",
+       " 'rethink',\n",
+       " 'scowls',\n",
+       " 'sequencers',\n",
+       " 'serf',\n",
+       " 'shook',\n",
+       " 'spottiest',\n",
+       " 'stood',\n",
+       " 'surtaxing',\n",
+       " 'wardrobes']"
+      ]
+     },
+     "execution_count": 19,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "unused_words = [w for w in ws if not present(g, w)[0]]\n",
+    "unused_words"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ancestor Counter({'t': 1, 'r': 1, 'a': 1, 'e': 1, 'o': 1, 's': 1, 'n': 1, 'c': 1})\n",
+      "baritone Counter({'t': 1, 'i': 1, 'a': 1, 'e': 1, 'n': 1, 'o': 1, 'r': 1, 'b': 1})\n",
+      "bemusing Counter({'m': 1, 'i': 1, 'n': 1, 'g': 1, 'e': 1, 's': 1, 'u': 1, 'b': 1})\n",
+      "blonds Counter({'n': 1, 's': 1, 'd': 1, 'l': 1, 'o': 1, 'b': 1})\n",
+      "conciseness Counter({'s': 3, 'n': 2, 'e': 2, 'c': 2, 'i': 1, 'o': 1})\n",
+      "consequent Counter({'n': 2, 'e': 2, 't': 1, 'q': 1, 's': 1, 'u': 1, 'o': 1, 'c': 1})\n",
+      "cuddle Counter({'d': 2, 'l': 1, 'u': 1, 'e': 1, 'c': 1})\n",
+      "dashboards Counter({'a': 2, 'd': 2, 's': 2, 'r': 1, 'h': 1, 'o': 1, 'b': 1})\n",
+      "*despairing Counter({'i': 2, 'a': 1, 'g': 1, 'e': 1, 'n': 1, 'r': 1, 'd': 1, 'p': 1, 's': 1})\n",
+      "dint Counter({'t': 1, 'i': 1, 'd': 1, 'n': 1})\n",
+      "employer Counter({'e': 2, 'm': 1, 'r': 1, 'p': 1, 'o': 1, 'l': 1, 'y': 1})\n",
+      "freakish Counter({'i': 1, 'a': 1, 'h': 1, 'e': 1, 's': 1, 'r': 1, 'f': 1, 'k': 1})\n",
+      "*gall Counter({'l': 2, 'a': 1, 'g': 1})\n",
+      "hopelessness Counter({'s': 4, 'e': 3, 'n': 1, 'h': 1, 'l': 1, 'o': 1, 'p': 1})\n",
+      "*impales Counter({'m': 1, 'i': 1, 'a': 1, 'e': 1, 'p': 1, 's': 1, 'l': 1})\n",
+      "infix Counter({'i': 2, 'x': 1, 'n': 1, 'f': 1})\n",
+      "inflow Counter({'i': 1, 'n': 1, 'w': 1, 'o': 1, 'f': 1, 'l': 1})\n",
+      "innumerable Counter({'n': 2, 'e': 2, 'm': 1, 'i': 1, 'l': 1, 'r': 1, 'u': 1, 'a': 1, 'b': 1})\n",
+      "intentional Counter({'n': 3, 't': 2, 'i': 2, 'e': 1, 'o': 1, 'l': 1, 'a': 1})\n",
+      "*jerkin Counter({'i': 1, 'n': 1, 'e': 1, 'r': 1, 'j': 1, 'k': 1})\n",
+      "justification Counter({'i': 3, 't': 2, 'a': 1, 'n': 1, 'j': 1, 's': 1, 'f': 1, 'u': 1, 'o': 1, 'c': 1})\n",
+      "leaving Counter({'i': 1, 'a': 1, 'v': 1, 'e': 1, 'l': 1, 'n': 1, 'g': 1})\n",
+      "locoweeds Counter({'e': 2, 'o': 2, 's': 1, 'w': 1, 'l': 1, 'd': 1, 'c': 1})\n",
+      "monickers Counter({'m': 1, 'i': 1, 'n': 1, 'e': 1, 's': 1, 'r': 1, 'o': 1, 'k': 1, 'c': 1})\n",
+      "originality Counter({'i': 3, 't': 1, 'n': 1, 'g': 1, 'y': 1, 'o': 1, 'a': 1, 'l': 1, 'r': 1})\n",
+      "outings Counter({'t': 1, 'i': 1, 'n': 1, 'g': 1, 'o': 1, 'u': 1, 's': 1})\n",
+      "pendulous Counter({'u': 2, 'n': 1, 'l': 1, 'e': 1, 's': 1, 'p': 1, 'd': 1, 'o': 1})\n",
+      "pithier Counter({'i': 2, 't': 1, 'h': 1, 'e': 1, 'r': 1, 'p': 1})\n",
+      "randomness Counter({'n': 2, 's': 2, 'm': 1, 'a': 1, 'e': 1, 'r': 1, 'o': 1, 'd': 1})\n",
+      "rectors Counter({'r': 2, 't': 1, 'e': 1, 's': 1, 'o': 1, 'c': 1})\n",
+      "redrew Counter({'r': 2, 'e': 2, 'w': 1, 'd': 1})\n",
+      "reformulated Counter({'e': 2, 'r': 2, 'm': 1, 't': 1, 'a': 1, 'd': 1, 'l': 1, 'f': 1, 'u': 1, 'o': 1})\n",
+      "remoteness Counter({'e': 3, 's': 2, 'm': 1, 't': 1, 'n': 1, 'r': 1, 'o': 1})\n",
+      "rethink Counter({'t': 1, 'i': 1, 'n': 1, 'h': 1, 'e': 1, 'r': 1, 'k': 1})\n",
+      "scowls Counter({'s': 2, 'w': 1, 'l': 1, 'o': 1, 'c': 1})\n",
+      "sequencers Counter({'e': 3, 's': 2, 'n': 1, 'q': 1, 'u': 1, 'r': 1, 'c': 1})\n",
+      "serf Counter({'s': 1, 'f': 1, 'r': 1, 'e': 1})\n",
+      "shook Counter({'o': 2, 'k': 1, 's': 1, 'h': 1})\n",
+      "spottiest Counter({'t': 3, 's': 2, 'i': 1, 'e': 1, 'p': 1, 'o': 1})\n",
+      "stood Counter({'o': 2, 't': 1, 'd': 1, 's': 1})\n",
+      "surtaxing Counter({'t': 1, 'x': 1, 'a': 1, 'g': 1, 'i': 1, 'n': 1, 's': 1, 'u': 1, 'r': 1})\n",
+      "wardrobes Counter({'r': 2, 'o': 1, 'a': 1, 'e': 1, 's': 1, 'w': 1, 'd': 1, 'b': 1})\n"
+     ]
+    }
+   ],
+   "source": [
+    "makeable_words = []\n",
+    "for w in unused_words:\n",
+    "    unused_word_count = collections.Counter(w)\n",
+    "    if all(unused_word_count[l] <= unused_letter_count[l] for l in unused_word_count):\n",
+    "        makeable_words += [w]\n",
+    "        print('*', end='')\n",
+    "    print(w, unused_word_count)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "10"
+      ]
+     },
+     "execution_count": 21,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "max(len(w) for w in makeable_words)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'despairing'"
+      ]
+     },
+     "execution_count": 22,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "sorted(makeable_words, key=len)[-1]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 78,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def do_wordsearch_tasks_old(fn, show_anyway=False):\n",
+    "    width, height, grid, words = read_wordsearch(fn)\n",
+    "\n",
+    "    used_words = [w for w in words if present(grid, w)[0]]\n",
+    "    unused_words = [w for w in words if not present(grid, w)[0]]\n",
+    "    lwp = sorted([w for w in words if present(grid, w)[0]], key=len)[-1]\n",
+    "    lwa = sorted(unused_words, key=len)[-1]\n",
+    "\n",
+    "    lwps = [w for w in used_words if len(w) == len(lwp)]\n",
+    "    lwas = [w for w in unused_words if len(w) == len(lwa)]\n",
+    "    g0 = empty_grid(width, height)\n",
+    "    for w in words:\n",
+    "        p, r, c, d = present(grid, w)\n",
+    "        if p:\n",
+    "            set_grid(g0, r, c, d, w) \n",
+    "    unused_letters = [l for l, u in zip((c for c in cat(cat(l) for l in grid)), (c for c in cat(cat(l) for l in g0)))\n",
+    "                  if u == '.']\n",
+    "    unused_letter_count = collections.Counter(unused_letters)\n",
+    "    makeable_words = []\n",
+    "    for w in unused_words:\n",
+    "        unused_word_count = collections.Counter(w)\n",
+    "        if all(unused_word_count[l] <= unused_letter_count[l] for l in unused_word_count):\n",
+    "            makeable_words += [w]\n",
+    "    lwm = sorted(makeable_words, key=len)[-1]\n",
+    "    lwms = [w for w in makeable_words if len(w) == len(lwm)]\n",
+    "    if show_anyway or len(set((len(lwp),len(lwa),len(lwm)))) == 3:\n",
+    "        print('\\n{}'.format(fn))\n",
+    "        print('{} words present'.format(len(words) - len(unused_words)))\n",
+    "        print('Longest word present: {}, {} letters ({})'.format(lwp, len(lwp), lwps))\n",
+    "        print('Longest word absent: {}, {} letters ({})'.format(lwa, len(lwa), lwas))\n",
+    "        print('{} unused letters'.format(len([c for c in cat(cat(l) for l in g0) if c == '.'])))\n",
+    "        print('Longest makeable word: {}, {} ({})'.format(lwm, len(lwm), lwms))\n",
+    "        print('All makeable words: {}'.format(makeable_words))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 152,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def do_wordsearch_tasks(fn, show_anyway=False, show_all_makeable=False):\n",
+    "    width, height, grid, words = read_wordsearch(fn)\n",
+    "    used_words = [p[0] for p in present_many(grid, words)]\n",
+    "    unused_words = [w for w in words if w not in used_words]\n",
+    "    lwp = max(used_words, key=len)\n",
+    "    lwps = [w for w in used_words if len(w) == len(lwp)]\n",
+    "\n",
+    "    if unused_words:\n",
+    "        lwa = max(unused_words, key=len)\n",
+    "    \n",
+    "        lwas = [w for w in unused_words if len(w) == len(lwa)]\n",
+    "        unused_grid = [[c for c in r] for r in grid]\n",
+    "        for w, r, c, d in present_many(grid, words):\n",
+    "            set_grid(unused_grid, r, c, d, '.' * len(w))\n",
+    "        unused_letters = [c for l in unused_grid for c in l if c != '.']\n",
+    "        unused_letter_count = collections.Counter(unused_letters)\n",
+    "        makeable_words = []\n",
+    "        for w in unused_words:\n",
+    "            unused_word_count = collections.Counter(w)\n",
+    "            if all(unused_word_count[l] <= unused_letter_count[l] for l in unused_word_count):\n",
+    "                makeable_words += [w]\n",
+    "        lwm = sorted(makeable_words, key=len)[-1]\n",
+    "        lwms = [w for w in makeable_words if len(w) == len(lwm)]\n",
+    "    else:\n",
+    "        lwa = ''\n",
+    "        lwas = []\n",
+    "        lwm = ''\n",
+    "        lwms = []\n",
+    "        \n",
+    "    if show_anyway or len(set((len(lwp),len(lwa),len(lwm)))) == 3:\n",
+    "        print('\\n{}'.format(fn))\n",
+    "        print('{} words present'.format(len(words) - len(unused_words)))\n",
+    "        print('Longest word present: {}, {} letters ({})'.format(lwp, len(lwp), lwps))\n",
+    "        print('Longest word absent: {}, {} letters ({})'.format(lwa, len(lwa), lwas))\n",
+    "        print('{} unused letters'.format(len([c for c in cat(cat(l) for l in g0) if c == '.'])))\n",
+    "        print('Longest makeable word: {}, {} ({})'.format(lwm, len(lwm), lwms))\n",
+    "        if show_all_makeable:\n",
+    "            print('All makeable words: {}'.format(makeable_words))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 136,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n",
+      "wordsearch04.txt\n",
+      "58 words present\n",
+      "Longest word present: fortification, 13 letters (['fortification'])\n",
+      "Longest word absent: justification, 13 letters (['justification'])\n",
+      "57 unused letters\n",
+      "Longest makeable word: despairing, 10 (['despairing'])\n",
+      "All makeable words: ['despairing', 'gall', 'impales', 'jerkin']\n"
+     ]
+    }
+   ],
+   "source": [
+    "do_wordsearch_tasks('wordsearch04.txt', show_anyway=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n",
+      "wordsearch08.txt\n",
+      "62 words present\n",
+      "Longest word present: compassionately, 15 letters (['compassionately'])\n",
+      "Longest word absent: retrospectives, 14 letters (['retrospectives'])\n",
+      "65 unused letters\n",
+      "Longest makeable word: vacationing, 11 (['vacationing'])\n"
+     ]
+    }
+   ],
+   "source": [
+    "do_wordsearch_tasks('wordsearch08.txt')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 80,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n",
+      "04-wordsearch.txt\n",
+      "62 words present\n",
+      "Longest word present: compassionately, 15 letters (['compassionately'])\n",
+      "Longest word absent: retrospectives, 14 letters (['retrospectives'])\n",
+      "65 unused letters\n",
+      "Longest makeable word: vacationing, 11 (['vacationing'])\n",
+      "All makeable words: ['albacore', 'entail', 'excreted', 'factory', 'fornicated', 'frantic', 'grease', 'grocer', 'informal', 'jockeying', 'justified', 'larynxes', 'reviewer', 'sabotage', 'unable', 'vacationing', 'widgeons']\n",
+      "\n",
+      "04-wordsearch.txt\n",
+      "62 words present\n",
+      "Longest word present: compassionately, 15 letters (['compassionately'])\n",
+      "Longest word absent: retrospectives, 14 letters (['retrospectives'])\n",
+      "65 unused letters\n",
+      "Longest makeable word: vacationing, 11 (['vacationing'])\n",
+      "All makeable words: ['albacore', 'entail', 'excreted', 'factory', 'fornicated', 'frantic', 'grease', 'grocer', 'informal', 'jockeying', 'justified', 'larynxes', 'reviewer', 'sabotage', 'unable', 'vacationing', 'widgeons']\n",
+      "\n",
+      "04-wordsearch.txt\n",
+      "62 words present\n",
+      "Longest word present: compassionately, 15 letters (['compassionately'])\n",
+      "Longest word absent: retrospectives, 14 letters (['retrospectives'])\n",
+      "65 unused letters\n",
+      "Longest makeable word: vacationing, 11 (['vacationing'])\n",
+      "All makeable words: ['albacore', 'entail', 'excreted', 'factory', 'fornicated', 'frantic', 'grease', 'grocer', 'informal', 'jockeying', 'justified', 'larynxes', 'reviewer', 'sabotage', 'unable', 'vacationing', 'widgeons']\n",
+      "\n",
+      "04-wordsearch.txt\n",
+      "62 words present\n",
+      "Longest word present: compassionately, 15 letters (['compassionately'])\n",
+      "Longest word absent: retrospectives, 14 letters (['retrospectives'])\n",
+      "65 unused letters\n",
+      "Longest makeable word: vacationing, 11 (['vacationing'])\n",
+      "All makeable words: ['albacore', 'entail', 'excreted', 'factory', 'fornicated', 'frantic', 'grease', 'grocer', 'informal', 'jockeying', 'justified', 'larynxes', 'reviewer', 'sabotage', 'unable', 'vacationing', 'widgeons']\n",
+      "1 loop, best of 3: 4.78 s per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "do_wordsearch_tasks_old('04-wordsearch.txt')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 142,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 loop, best of 3: 463 ms per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "do_wordsearch_tasks('wordsearch04.txt')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 143,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n",
+      "example-wordsearch.txt\n",
+      "14 words present\n",
+      "Longest word present: cowhides, 8 letters (['cowhides'])\n",
+      "Longest word absent: adapting, 8 letters (['adapting', 'coccyxes', 'crumbled', 'molested'])\n",
+      "57 unused letters\n",
+      "Longest makeable word: shinier, 7 (['shinier'])\n",
+      "All makeable words: ['shinier']\n"
+     ]
+    }
+   ],
+   "source": [
+    "do_wordsearch_tasks('example-wordsearch.txt', show_anyway=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {
+    "collapsed": true,
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "# for fn in sorted(os.listdir()):\n",
+    "#     if re.match('wordsearch\\d\\d\\.txt', fn):\n",
+    "#         do_wordsearch_tasks(fn)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "absolved (True, 16, 2, <Direction.right: 2>)\n",
+      "adorable (True, 11, 4, <Direction.right: 2>)\n",
+      "aeon (True, 11, 4, <Direction.down: 4>)\n",
+      "alias (True, 15, 15, <Direction.left: 1>)\n",
+      "ancestor (False, 0, 0, <Direction.left: 1>)\n",
+      "baritone (False, 0, 0, <Direction.left: 1>)\n",
+      "bemusing (False, 0, 0, <Direction.left: 1>)\n",
+      "blonds (False, 0, 0, <Direction.left: 1>)\n",
+      "bran (True, 1, 9, <Direction.left: 1>)\n",
+      "calcite (True, 19, 9, <Direction.upright: 6>)\n",
+      "candor (True, 17, 12, <Direction.right: 2>)\n",
+      "conciseness (False, 0, 0, <Direction.left: 1>)\n",
+      "consequent (False, 0, 0, <Direction.left: 1>)\n",
+      "cuddle (False, 0, 0, <Direction.left: 1>)\n",
+      "damming (True, 17, 2, <Direction.right: 2>)\n",
+      "dashboards (False, 0, 0, <Direction.left: 1>)\n",
+      "despairing (False, 0, 0, <Direction.left: 1>)\n",
+      "dint (False, 0, 0, <Direction.left: 1>)\n",
+      "dullard (True, 8, 2, <Direction.down: 4>)\n",
+      "dynasty (True, 3, 4, <Direction.downright: 8>)\n",
+      "employer (False, 0, 0, <Direction.left: 1>)\n",
+      "exhorts (True, 0, 8, <Direction.left: 1>)\n",
+      "feted (True, 5, 10, <Direction.right: 2>)\n",
+      "fill (True, 9, 14, <Direction.upleft: 5>)\n",
+      "flattens (True, 10, 10, <Direction.upleft: 5>)\n",
+      "foghorn (True, 10, 11, <Direction.downright: 8>)\n",
+      "fortification (True, 19, 16, <Direction.left: 1>)\n",
+      "freakish (False, 0, 0, <Direction.left: 1>)\n",
+      "frolics (True, 16, 16, <Direction.up: 3>)\n",
+      "gall (False, 0, 0, <Direction.left: 1>)\n",
+      "gees (True, 17, 0, <Direction.upright: 6>)\n",
+      "genies (True, 5, 7, <Direction.upleft: 5>)\n",
+      "gets (True, 6, 4, <Direction.upleft: 5>)\n",
+      "hastening (True, 14, 13, <Direction.left: 1>)\n",
+      "hits (True, 2, 0, <Direction.down: 4>)\n",
+      "hopelessness (False, 0, 0, <Direction.left: 1>)\n",
+      "hurlers (True, 18, 0, <Direction.right: 2>)\n",
+      "impales (False, 0, 0, <Direction.left: 1>)\n",
+      "infix (False, 0, 0, <Direction.left: 1>)\n",
+      "inflow (False, 0, 0, <Direction.left: 1>)\n",
+      "innumerable (False, 0, 0, <Direction.left: 1>)\n",
+      "intentional (False, 0, 0, <Direction.left: 1>)\n",
+      "jerkin (False, 0, 0, <Direction.left: 1>)\n",
+      "justification (False, 0, 0, <Direction.left: 1>)\n",
+      "kitty (True, 8, 15, <Direction.upleft: 5>)\n",
+      "knuckles (True, 17, 19, <Direction.up: 3>)\n",
+      "leaving (False, 0, 0, <Direction.left: 1>)\n",
+      "like (True, 3, 11, <Direction.left: 1>)\n",
+      "limitation (True, 8, 3, <Direction.right: 2>)\n",
+      "locoweeds (False, 0, 0, <Direction.left: 1>)\n",
+      "loot (True, 3, 19, <Direction.up: 3>)\n",
+      "lucking (True, 7, 10, <Direction.upleft: 5>)\n",
+      "lumps (True, 0, 17, <Direction.down: 4>)\n",
+      "mercerising (True, 15, 17, <Direction.up: 3>)\n",
+      "monickers (False, 0, 0, <Direction.left: 1>)\n",
+      "motionless (True, 13, 1, <Direction.up: 3>)\n",
+      "naturally (True, 9, 16, <Direction.up: 3>)\n",
+      "nighest (True, 15, 4, <Direction.right: 2>)\n",
+      "notion (True, 17, 18, <Direction.up: 3>)\n",
+      "ogled (True, 1, 18, <Direction.down: 4>)\n",
+      "originality (False, 0, 0, <Direction.left: 1>)\n",
+      "outings (False, 0, 0, <Direction.left: 1>)\n",
+      "pendulous (False, 0, 0, <Direction.left: 1>)\n",
+      "piled (True, 1, 10, <Direction.right: 2>)\n",
+      "pins (True, 7, 4, <Direction.upleft: 5>)\n",
+      "pithier (False, 0, 0, <Direction.left: 1>)\n",
+      "prep (True, 10, 4, <Direction.right: 2>)\n",
+      "randomness (False, 0, 0, <Direction.left: 1>)\n",
+      "rectors (False, 0, 0, <Direction.left: 1>)\n",
+      "redrew (False, 0, 0, <Direction.left: 1>)\n",
+      "reformulated (False, 0, 0, <Direction.left: 1>)\n",
+      "remoteness (False, 0, 0, <Direction.left: 1>)\n",
+      "retaking (True, 6, 0, <Direction.down: 4>)\n",
+      "rethink (False, 0, 0, <Direction.left: 1>)\n",
+      "rope (True, 9, 4, <Direction.right: 2>)\n",
+      "rubier (True, 0, 4, <Direction.downright: 8>)\n",
+      "sailors (True, 7, 15, <Direction.up: 3>)\n",
+      "scowls (False, 0, 0, <Direction.left: 1>)\n",
+      "scum (True, 16, 11, <Direction.right: 2>)\n",
+      "sepals (True, 6, 10, <Direction.upright: 6>)\n",
+      "sequencers (False, 0, 0, <Direction.left: 1>)\n",
+      "serf (False, 0, 0, <Direction.left: 1>)\n",
+      "shoaled (True, 11, 18, <Direction.up: 3>)\n",
+      "shook (False, 0, 0, <Direction.left: 1>)\n",
+      "sonic (True, 18, 18, <Direction.left: 1>)\n",
+      "spottiest (False, 0, 0, <Direction.left: 1>)\n",
+      "stag (True, 7, 8, <Direction.left: 1>)\n",
+      "stood (False, 0, 0, <Direction.left: 1>)\n",
+      "stratum (True, 2, 13, <Direction.left: 1>)\n",
+      "strong (True, 4, 19, <Direction.down: 4>)\n",
+      "studying (True, 0, 16, <Direction.left: 1>)\n",
+      "surtaxing (False, 0, 0, <Direction.left: 1>)\n",
+      "tailing (True, 13, 6, <Direction.right: 2>)\n",
+      "tears (True, 13, 3, <Direction.up: 3>)\n",
+      "teazles (True, 4, 10, <Direction.downright: 8>)\n",
+      "vans (True, 18, 8, <Direction.upright: 6>)\n",
+      "wardrobes (False, 0, 0, <Direction.left: 1>)\n",
+      "wooded (True, 12, 5, <Direction.right: 2>)\n",
+      "worsts (True, 1, 0, <Direction.downright: 8>)\n",
+      "zings (True, 10, 14, <Direction.upleft: 5>)\n"
+     ]
+    }
+   ],
+   "source": [
+    "width, height, grid, words = read_wordsearch('wordsearch04.txt')\n",
+    "for w in words:\n",
+    "    print(w, present(grid, w))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Example for question text"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import copy\n",
+    "grid =  [['.', '.', '.', 'p', '.', 'm', 'o', 'w', 'n', '.'], ['.', 's', 'd', 's', 'e', '.', '.', 'e', 'e', '.'], ['.', 'e', '.', 'e', 'l', 'a', 'd', '.', 'c', 'r'], ['p', 'i', '.', 'd', 't', 'i', 'r', '.', 'a', 'h'], ['r', 'z', 's', 'i', 'w', 'o', 'v', 's', 'p', 'u'], ['o', 'a', 'w', 'h', '.', 'k', 'i', 'e', 'a', 'b'], ['b', 'r', 'o', 'w', '.', 'c', '.', 'r', 'd', 'a'], ['e', 'c', 'n', 'o', 't', 'o', 'p', 's', '.', 'r'], ['d', '.', 'k', 'c', '.', 'd', '.', '.', '.', 'b'], ['.', 's', 't', 'a', 'p', 'l', 'e', '.', '.', '.']]\n",
+    "padded_grid =  [['f', 'h', 'j', 'p', 'a', 'm', 'o', 'w', 'n', 'q'], ['w', 's', 'd', 's', 'e', 'u', 'q', 'e', 'e', 'v'], ['i', 'e', 'a', 'e', 'l', 'a', 'd', 'h', 'c', 'r'], ['p', 'i', 'e', 'd', 't', 'i', 'r', 'i', 'a', 'h'], ['r', 'z', 's', 'i', 'w', 'o', 'v', 's', 'p', 'u'], ['o', 'a', 'w', 'h', 'a', 'k', 'i', 'e', 'a', 'b'], ['b', 'r', 'o', 'w', 'p', 'c', 'f', 'r', 'd', 'a'], ['e', 'c', 'n', 'o', 't', 'o', 'p', 's', 's', 'r'], ['d', 'i', 'k', 'c', 'h', 'd', 'n', 'p', 'n', 'b'], ['b', 's', 't', 'a', 'p', 'l', 'e', 'o', 'k', 'r']]\n",
+    "present_words =  ['probed', 'staple', 'rioted', 'cowhides', 'tops', 'knows', 'lived', 'rhubarb', 'crazies', 'dock', 'apace', 'mown', 'pears', 'wide']\n",
+    "decoy_words =  ['fickler', 'adapting', 'chump', 'foaming', 'molested', 'carnal', 'crumbled', 'guts', 'minuend', 'bombing', 'winced', 'coccyxes', 'solaria', 'shinier', 'cackles']"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'apace, cowhides, crazies, dock, knows, lived, mown, pears, probed, rhubarb, rioted, staple, tops, wide'"
+      ]
+     },
+     "execution_count": 29,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "', '.join(sorted(present_words))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 92,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(76, 14)"
+      ]
+     },
+     "execution_count": 92,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "sum(len(w) for w in present_words), len(present_words)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'adapting, bombing, cackles, carnal, chump, coccyxes, crumbled, fickler, foaming, guts, minuend, molested, shinier, solaria, winced'"
+      ]
+     },
+     "execution_count": 30,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "', '.join(sorted(decoy_words))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'adapting, apace, bombing, cackles, carnal, chump, coccyxes, cowhides, crazies, crumbled, dock, fickler, foaming, guts, knows, lived, minuend, molested, mown, pears, probed, rhubarb, rioted, shinier, solaria, staple, tops, wide, winced'"
+      ]
+     },
+     "execution_count": 31,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "', '.join(sorted(present_words + decoy_words))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "probed 3 0 6 Direction.down [(3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0)]\n",
+      "staple 9 1 6 Direction.right [(9, 1), (9, 2), (9, 3), (9, 4), (9, 5), (9, 6)]\n",
+      "rioted 6 7 6 Direction.upleft [(6, 7), (5, 6), (4, 5), (3, 4), (2, 3), (1, 2)]\n",
+      "cowhides 8 3 8 Direction.up [(8, 3), (7, 3), (6, 3), (5, 3), (4, 3), (3, 3), (2, 3), (1, 3)]\n",
+      "tops 7 4 4 Direction.right [(7, 4), (7, 5), (7, 6), (7, 7)]\n",
+      "knows 8 2 5 Direction.up [(8, 2), (7, 2), (6, 2), (5, 2), (4, 2)]\n",
+      "lived 2 4 5 Direction.downright [(2, 4), (3, 5), (4, 6), (5, 7), (6, 8)]\n",
+      "rhubarb 2 9 7 Direction.down [(2, 9), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9)]\n",
+      "crazies 7 1 7 Direction.up [(7, 1), (6, 1), (5, 1), (4, 1), (3, 1), (2, 1), (1, 1)]\n",
+      "dock 8 5 4 Direction.up [(8, 5), (7, 5), (6, 5), (5, 5)]\n",
+      "apace 5 8 5 Direction.up [(5, 8), (4, 8), (3, 8), (2, 8), (1, 8)]\n",
+      "mown 0 5 4 Direction.right [(0, 5), (0, 6), (0, 7), (0, 8)]\n",
+      "pears 0 3 5 Direction.downright [(0, 3), (1, 4), (2, 5), (3, 6), (4, 7)]\n",
+      "wide 4 4 4 Direction.upright [(4, 4), (3, 5), (2, 6), (1, 7)]\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "[(7, 5), (2, 3), (3, 5)]"
+      ]
+     },
+     "execution_count": 32,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "cts = collections.Counter()\n",
+    "for w in present_words:\n",
+    "    _, r, c, d = present(grid, w)\n",
+    "    inds = indices(grid, r, c, len(w), d)\n",
+    "    for i in inds:\n",
+    "        cts[i] += 1\n",
+    "    print(w, r, c, len(w), d, inds)\n",
+    "[i for i in cts if cts[i] > 1]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n",
+      "example-wordsearch.txt\n",
+      "14 words present\n",
+      "Longest word present: cowhides, 8 letters (['cowhides'])\n",
+      "Longest word absent: molested, 8 letters (['adapting', 'coccyxes', 'crumbled', 'molested'])\n",
+      "27 unused letters\n",
+      "Longest makeable word: shinier, 7 (['shinier'])\n"
+     ]
+    }
+   ],
+   "source": [
+    "do_wordsearch_tasks('example-wordsearch.txt', show_anyway=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "..........\n",
+      "..........\n",
+      "....l.....\n",
+      ".....i....\n",
+      "......v...\n",
+      ".......e..\n",
+      "........d.\n",
+      "..........\n",
+      "..........\n",
+      "..........\n"
+     ]
+    }
+   ],
+   "source": [
+    "g = empty_grid(10, 10)\n",
+    "set_grid(g, 2, 4, Direction.downright, 'lived')\n",
+    "print(show_grid(g))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 35,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "..........\n",
+      ".......e..\n",
+      "....l.d...\n",
+      ".....i....\n",
+      "....w.v...\n",
+      ".......e..\n",
+      "........d.\n",
+      "..........\n",
+      "..........\n",
+      ".staple...\n"
+     ]
+    }
+   ],
+   "source": [
+    "g = empty_grid(10, 10)\n",
+    "set_grid(g, 2, 4, Direction.downright, 'lived')\n",
+    "set_grid(g, 4, 4, Direction.upright, 'wide')\n",
+    "set_grid(g, 9, 1, Direction.right, 'staple')\n",
+    "print(show_grid(g))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 36,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "..........\n",
+      "...s......\n",
+      "...e......\n",
+      "...d......\n",
+      "...i......\n",
+      "...h......\n",
+      "...w......\n",
+      "...o......\n",
+      "...c......\n",
+      "..........\n"
+     ]
+    }
+   ],
+   "source": [
+    "g = empty_grid(10, 10)\n",
+    "set_grid(g, 8, 3, Direction.up, 'cowhides')\n",
+    "print(show_grid(g))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 39,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "..........\n",
+      "...s...e..\n",
+      "...el.d...\n",
+      "...d.i....\n",
+      "...iw.v...\n",
+      "...h...e..\n",
+      "...w....d.\n",
+      "...o......\n",
+      "...c......\n",
+      ".staple...\n"
+     ]
+    }
+   ],
+   "source": [
+    "g = empty_grid(10, 10)\n",
+    "set_grid(g, 2, 4, Direction.downright, 'lived')\n",
+    "set_grid(g, 4, 4, Direction.upright, 'wide')\n",
+    "set_grid(g, 9, 1, Direction.right, 'staple')\n",
+    "set_grid(g, 8, 3, Direction.up, 'cowhides')\n",
+    "print(show_grid(g))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "..........\n",
+      "..........\n",
+      "..........\n",
+      "..........\n",
+      "..........\n",
+      "..........\n",
+      "brow......\n",
+      "..........\n",
+      "..........\n",
+      "..........\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Example of word in grid that is English but isn't in the words listed in the puzzle.\n",
+    "g = empty_grid(10, 10)\n",
+    "set_grid(g, 6, 0, Direction.right, 'brow')\n",
+    "print(show_grid(g))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 38,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "fhj.a....q\n",
+      "w....uq..v\n",
+      "i.a....h..\n",
+      "..e....i..\n",
+      "..........\n",
+      "....a.....\n",
+      "....p.f...\n",
+      "........s.\n",
+      ".i..h.npn.\n",
+      "b......okr\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "'aaabeffhhhiiijknnoppqqrsuvw'"
+      ]
+     },
+     "execution_count": 38,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "unused_grid = copy.deepcopy(padded_grid)\n",
+    "for w in present_words:\n",
+    "    _, r, c, d = present(grid, w)\n",
+    "    set_grid(unused_grid, r, c, d, '.' * len(w))\n",
+    "print(show_grid(unused_grid))\n",
+    "cat(sorted(c for l in unused_grid for c in l if c in string.ascii_letters))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 201,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "9"
+      ]
+     },
+     "execution_count": 201,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(sorted(c for l in unused_grid for c in l if c in 'aeiou'))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# All wordsearch puzzles"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 108,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def read_all_wordsearch(fn):\n",
+    "    with open(fn) as f:\n",
+    "        text = f.read().strip()\n",
+    "        puzzles_text = text.split('\\n\\n')\n",
+    "        puzzles = []\n",
+    "        for p in puzzles_text:\n",
+    "            lines = p.splitlines()\n",
+    "            w, h = [int(s) for s in lines[0].split('x')]\n",
+    "            grid = lines[1:h+1]\n",
+    "            words = lines[h+1:]\n",
+    "            puzzles += [(w, h, grid, words)]\n",
+    "    return puzzles"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 109,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(20,\n",
+       " 20,\n",
+       " ['esaetarotcetorpwvnma',\n",
+       "  'dhuejswellraqzassuzn',\n",
+       "  'riopstewsidftvenlnlo',\n",
+       "  'dltnpupodiafilgeenap',\n",
+       "  'yeooooosvconsgatvenm',\n",
+       "  'tgtonrsdtpgsungsireo',\n",
+       "  'csmtnlaistdklisaeyrp',\n",
+       "  'fguuusortrewfkrfdluo',\n",
+       "  'dotcnpvoyiraicsrieht',\n",
+       "  'drtcoataksogdaekcoyy',\n",
+       "  'igoialcuneoneuasirvy',\n",
+       "  'ajnzdpacoqrbsoshmgnt',\n",
+       "  'mmsxeetcewussviipeei',\n",
+       "  'esbrevrioprivilramsr',\n",
+       "  'tsgerdvcvutesbtrrska',\n",
+       "  'eyselimisapenheettcl',\n",
+       "  'ryponacqcetsdsddiouu',\n",
+       "  'streitsaotsedalaanlg',\n",
+       "  'foretselppusdfrsleae',\n",
+       "  'utsolacebeardingpher'],\n",
+       " ['aboveboard',\n",
+       "  'accents',\n",
+       "  'applicants',\n",
+       "  'arbitrarily',\n",
+       "  'atlas',\n",
+       "  'bazillions',\n",
+       "  'bearding',\n",
+       "  'biathlon',\n",
+       "  'bivouacking',\n",
+       "  'canopy',\n",
+       "  'captivated',\n",
+       "  'chicory',\n",
+       "  'cockroach',\n",
+       "  'construct',\n",
+       "  'coups',\n",
+       "  'credit',\n",
+       "  'depreciates',\n",
+       "  'diameters',\n",
+       "  'diffuses',\n",
+       "  'douse',\n",
+       "  'downbeats',\n",
+       "  'dregs',\n",
+       "  'envy',\n",
+       "  'expects',\n",
+       "  'expurgations',\n",
+       "  'fact',\n",
+       "  'fastens',\n",
+       "  'festively',\n",
+       "  'flubbing',\n",
+       "  'fops',\n",
+       "  'fore',\n",
+       "  'gage',\n",
+       "  'gapes',\n",
+       "  'gawks',\n",
+       "  'gemstone',\n",
+       "  'grog',\n",
+       "  'grossly',\n",
+       "  'handlebar',\n",
+       "  'haranguing',\n",
+       "  'honorary',\n",
+       "  'hulls',\n",
+       "  'impartial',\n",
+       "  'insists',\n",
+       "  'lades',\n",
+       "  'lane',\n",
+       "  'levied',\n",
+       "  'loaned',\n",
+       "  'locust',\n",
+       "  'loons',\n",
+       "  'lucks',\n",
+       "  'lying',\n",
+       "  'memoir',\n",
+       "  'methods',\n",
+       "  'mutton',\n",
+       "  'nodular',\n",
+       "  'nunnery',\n",
+       "  'onlookers',\n",
+       "  'outputted',\n",
+       "  'overhearing',\n",
+       "  'panicky',\n",
+       "  'particularly',\n",
+       "  'peeving',\n",
+       "  'podia',\n",
+       "  'pompon',\n",
+       "  'presenting',\n",
+       "  'protectorate',\n",
+       "  'pummels',\n",
+       "  'ransoms',\n",
+       "  'regularity',\n",
+       "  'roof',\n",
+       "  'salvaged',\n",
+       "  'scanting',\n",
+       "  'scions',\n",
+       "  'shipping',\n",
+       "  'shirred',\n",
+       "  'silted',\n",
+       "  'similes',\n",
+       "  'smartened',\n",
+       "  'snicker',\n",
+       "  'snowdrops',\n",
+       "  'sobs',\n",
+       "  'solace',\n",
+       "  'stews',\n",
+       "  'stitches',\n",
+       "  'sulfides',\n",
+       "  'supplest',\n",
+       "  'suppositions',\n",
+       "  'swell',\n",
+       "  'theirs',\n",
+       "  'toastier',\n",
+       "  'tutorial',\n",
+       "  'unaccepted',\n",
+       "  'unionising',\n",
+       "  'vanquish',\n",
+       "  'venous',\n",
+       "  'verbs',\n",
+       "  'vitiation',\n",
+       "  'waving',\n",
+       "  'wrens',\n",
+       "  'yock'])"
+      ]
+     },
+     "execution_count": 109,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "puzzles = read_all_wordsearch('all-wordsearches.txt')\n",
+    "puzzles[3]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 110,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def found_words_length(puzzle):\n",
+    "    width, height, grid, words = puzzle\n",
+    "    return sum(len(p[0]) for p in present_many(grid, words))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 113,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[309,\n",
+       " 335,\n",
+       " 338,\n",
+       " 346,\n",
+       " 364,\n",
+       " 372,\n",
+       " 337,\n",
+       " 340,\n",
+       " 353,\n",
+       " 371,\n",
+       " 343,\n",
+       " 348,\n",
+       " 375,\n",
+       " 343,\n",
+       " 363,\n",
+       " 376,\n",
+       " 347,\n",
+       " 363,\n",
+       " 342,\n",
+       " 348,\n",
+       " 377,\n",
+       " 342,\n",
+       " 355,\n",
+       " 351,\n",
+       " 342,\n",
+       " 331,\n",
+       " 362,\n",
+       " 354,\n",
+       " 323,\n",
+       " 353,\n",
+       " 337,\n",
+       " 340,\n",
+       " 349,\n",
+       " 362,\n",
+       " 361,\n",
+       " 350,\n",
+       " 348,\n",
+       " 327,\n",
+       " 370,\n",
+       " 362,\n",
+       " 334,\n",
+       " 333,\n",
+       " 341,\n",
+       " 354,\n",
+       " 355,\n",
+       " 358,\n",
+       " 355,\n",
+       " 358,\n",
+       " 357,\n",
+       " 351,\n",
+       " 351,\n",
+       " 346,\n",
+       " 326,\n",
+       " 332,\n",
+       " 352,\n",
+       " 347,\n",
+       " 346,\n",
+       " 369,\n",
+       " 363,\n",
+       " 361,\n",
+       " 365,\n",
+       " 364,\n",
+       " 359,\n",
+       " 352,\n",
+       " 344,\n",
+       " 352,\n",
+       " 348,\n",
+       " 360,\n",
+       " 333,\n",
+       " 352,\n",
+       " 374,\n",
+       " 360,\n",
+       " 349,\n",
+       " 343,\n",
+       " 360,\n",
+       " 345,\n",
+       " 364,\n",
+       " 355,\n",
+       " 349,\n",
+       " 349,\n",
+       " 355,\n",
+       " 328,\n",
+       " 358,\n",
+       " 344,\n",
+       " 335,\n",
+       " 339,\n",
+       " 365,\n",
+       " 328,\n",
+       " 343,\n",
+       " 350,\n",
+       " 340,\n",
+       " 342,\n",
+       " 342,\n",
+       " 357,\n",
+       " 362,\n",
+       " 333,\n",
+       " 357,\n",
+       " 346,\n",
+       " 341,\n",
+       " 348]"
+      ]
+     },
+     "execution_count": 113,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "[found_words_length(p) for p in puzzles]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 114,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "34988"
+      ]
+     },
+     "execution_count": 114,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "sum(found_words_length(p) for p in puzzles)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 122,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def max_unfound_word_length(puzzle):\n",
+    "    width, height, grid, words = puzzle\n",
+    "    presences = present_many(grid, words)\n",
+    "    used_words = [p[0] for p in presences]\n",
+    "    unused_words = [w for w in words if w not in used_words]\n",
+    "    \n",
+    "    unused_grid = [[c for c in r] for r in grid]\n",
+    "    for w, r, c, d in presences:\n",
+    "        set_grid(unused_grid, r, c, d, '.' * len(w))\n",
+    "    unused_letters = [c for l in unused_grid for c in l if c != '.']\n",
+    "    unused_letter_count = collections.Counter(unused_letters)\n",
+    "    \n",
+    "    makeable_words = []\n",
+    "    for w in unused_words:\n",
+    "        unused_word_count = collections.Counter(w)\n",
+    "        if all(unused_word_count[l] <= unused_letter_count[l] for l in unused_word_count):\n",
+    "            makeable_words += [w]\n",
+    "    lwm = max(len(w) for w in makeable_words)\n",
+    "    return lwm"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 123,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[11,\n",
+       " 13,\n",
+       " 11,\n",
+       " 11,\n",
+       " 10,\n",
+       " 9,\n",
+       " 12,\n",
+       " 12,\n",
+       " 11,\n",
+       " 10,\n",
+       " 15,\n",
+       " 11,\n",
+       " 10,\n",
+       " 11,\n",
+       " 10,\n",
+       " 12,\n",
+       " 11,\n",
+       " 9,\n",
+       " 11,\n",
+       " 11,\n",
+       " 10,\n",
+       " 12,\n",
+       " 11,\n",
+       " 12,\n",
+       " 13,\n",
+       " 12,\n",
+       " 10,\n",
+       " 10,\n",
+       " 11,\n",
+       " 9,\n",
+       " 11,\n",
+       " 11,\n",
+       " 8,\n",
+       " 12,\n",
+       " 13,\n",
+       " 10,\n",
+       " 11,\n",
+       " 11,\n",
+       " 9,\n",
+       " 8,\n",
+       " 12,\n",
+       " 13,\n",
+       " 11,\n",
+       " 9,\n",
+       " 13,\n",
+       " 11,\n",
+       " 11,\n",
+       " 11,\n",
+       " 13,\n",
+       " 12,\n",
+       " 10,\n",
+       " 11,\n",
+       " 11,\n",
+       " 12,\n",
+       " 10,\n",
+       " 8,\n",
+       " 12,\n",
+       " 11,\n",
+       " 10,\n",
+       " 11,\n",
+       " 8,\n",
+       " 12,\n",
+       " 10,\n",
+       " 11,\n",
+       " 12,\n",
+       " 12,\n",
+       " 12,\n",
+       " 12,\n",
+       " 11,\n",
+       " 11,\n",
+       " 12,\n",
+       " 12,\n",
+       " 13,\n",
+       " 10,\n",
+       " 10,\n",
+       " 10,\n",
+       " 10,\n",
+       " 12,\n",
+       " 11,\n",
+       " 11,\n",
+       " 12,\n",
+       " 11,\n",
+       " 9,\n",
+       " 14,\n",
+       " 11,\n",
+       " 13,\n",
+       " 12,\n",
+       " 10,\n",
+       " 10,\n",
+       " 12,\n",
+       " 13,\n",
+       " 10,\n",
+       " 10,\n",
+       " 12,\n",
+       " 11,\n",
+       " 12,\n",
+       " 11,\n",
+       " 11,\n",
+       " 12,\n",
+       " 11]"
+      ]
+     },
+     "execution_count": 123,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "[max_unfound_word_length(p) for p in puzzles]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 121,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1106"
+      ]
+     },
+     "execution_count": 121,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "sum(max_unfound_word_length(p) for p in puzzles)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 124,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 loop, best of 3: 18.8 s per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "sum(found_words_length(p) for p in puzzles)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 125,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 loop, best of 3: 18.7 s per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "sum(max_unfound_word_length(p) for p in puzzles)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 190,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n",
+      "huge-wordsearch.txt\n",
+      "1149 words present\n",
+      "Longest word present: hypersensitivities, 18 letters (['hypersensitivities'])\n",
+      "Longest word absent: rambunctiousness, 16 letters (['rambunctiousness'])\n",
+      "57 unused letters\n",
+      "Longest makeable word: rambunctiousness, 16 (['rambunctiousness'])\n"
+     ]
+    }
+   ],
+   "source": [
+    "do_wordsearch_tasks('huge-wordsearch.txt', show_anyway=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 191,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 loop, best of 3: 1min 4s per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "do_wordsearch_tasks('huge-wordsearch.txt')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 192,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "width, height, grid, words = read_wordsearch('huge-wordsearch.txt')\n",
+    "pm = present_many(grid, words)\n",
+    "pold = [w for w in words if present(grid, w)[0]]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 193,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1149"
+      ]
+     },
+     "execution_count": 193,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(pm)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 194,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1149"
+      ]
+     },
+     "execution_count": 194,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(pold)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 195,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1149"
+      ]
+     },
+     "execution_count": 195,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pm_extra = [p for p in pm if p not in pold]\n",
+    "len(pm_extra)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 196,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[('poltroons', 62, 65, <Direction.downleft: 7>),\n",
+       " ('dogged', 7, 45, <Direction.down: 4>),\n",
+       " ('activist', 51, 35, <Direction.downright: 8>)]"
+      ]
+     },
+     "execution_count": 196,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "list(pm)[:3]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 197,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['abound', 'abstracted', 'accidents']"
+      ]
+     },
+     "execution_count": 197,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pold[:3]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 198,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[('retreading', 1),\n",
+       " ('disavows', 1),\n",
+       " ('finals', 1),\n",
+       " ('conniver', 1),\n",
+       " ('warding', 1),\n",
+       " ('melon', 1),\n",
+       " ('paging', 1),\n",
+       " ('booties', 1),\n",
+       " ('civilises', 1),\n",
+       " ('hugged', 1)]"
+      ]
+     },
+     "execution_count": 198,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "collections.Counter(p[0] for p in pm).most_common(10)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 199,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[]"
+      ]
+     },
+     "execution_count": 199,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "[p for p in pm if p[0] == 'seen']"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.2+"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 1
+}
diff --git a/04-word-search/wordsearch-solution.ipynb b/04-word-search/wordsearch-solution.ipynb
new file mode 100644 (file)
index 0000000..01309f6
--- /dev/null
@@ -0,0 +1,546 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Wordsearch\n",
+    "Given a text file, consisting of three parts (a grid size, a grid, and a list of words), find:\n",
+    "* the words present in the grid, \n",
+    "* the longest word present in the grid, \n",
+    "* the number of words not present in the grid, \n",
+    "* the longest word not present that can be formed from the leftover letters\n",
+    "\n",
+    "The only words that need be considered are the ones given in the list in the puzzle input.\n",
+    "\n",
+    "The puzzle consists of:\n",
+    "1. A line consisting of _w_`x`_h_, where _w_ and _h_ are integers giving the width and height of the grid.\n",
+    "2. The grid itself, consisting of _h_ lines each of _w_ letters.\n",
+    "3. A list of words, one word per line, of arbitrary length. "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Example\n",
+    "\n",
+    "\n",
+    "`...p.mown.\n",
+    ".sdse..ee.\n",
+    ".e.elad.cr\n",
+    "pi.dtir.ah\n",
+    "rzsiwovspu\n",
+    "oawh.kieab\n",
+    "brow.c.rda\n",
+    "ecnotops.r\n",
+    "d.kc.d...b\n",
+    ".staple...`\n",
+    "\n",
+    "```\n",
+    "fhjpamownq\n",
+    "wsdseuqeev\n",
+    "ieaeladhcr\n",
+    "piedtiriah\n",
+    "rzsiwovspu\n",
+    "oawhakieab\n",
+    "browpcfrda\n",
+    "ecnotopssr\n",
+    "dikchdnpnb\n",
+    "bstapleokr\n",
+    "```\n",
+    "\n",
+    "14 words added;  6 directions\n",
+    "\n",
+    "Present: apace cowhides crazies dock knows lived mown pears probed rhubarb rioted staple tops wide\n",
+    "\n",
+    "Decoys: adapting bombing boor brick cackles carnal casino chaplets chump coaster coccyxes coddle collies creels crumbled cunt curds curled curlier deepen demeanor dicier dowses ensuing faddish fest fickler foaming gambol garoting gliding gristle grunts guts ibex impugns instants kielbasy lanyard loamier lugs market meanly minuend misprint mitts molested moonshot mucking oaks olives orgasmic pastrami perfect proceed puckered quashed refined regards retraces revel ridges ringlet scoff shinier siren solaria sprain sunder sunup tamped tapes thirds throw tiller times trains tranquil transfix typesets uric wariness welts whimsy winced winced\n",
+    "\n",
+    "Decoys: fickler, adapting, chump, foaming, molested, carnal, crumbled, guts, minuend, bombing, winced, coccyxes, solaria, shinier, cackles\n",
+    "\n",
+    "All words: adapting, apace, bombing, cackles, carnal, chump, coccyxes, cowhides, crazies, crumbled, dock, fickler, foaming, guts, knows, lived, minuend, molested, mown, pears, probed, rhubarb, rioted, shinier, solaria, staple, tops, wide, winced\n",
+    "\n",
+    "Directions:  [('probed', '`(True, 3, 0, <Direction.down: 4>)`'), ('staple', '`(True, 9, 1, <Direction.right: 2>)`'), ('rioted', '`(True, 6, 7, <Direction.upleft: 5>)`'), ('cowhides', '`(True, 8, 3, <Direction.up: 3>)`'), ('tops', '`(True, 7, 4, <Direction.right: 2>)`'), ('knows', '`(True, 8, 2, <Direction.up: 3>)`'), ('lived', '`(True, 2, 4, <Direction.downright: 8>)`'), ('rhubarb', '`(True, 2, 9, <Direction.down: 4>)`'), ('crazies', '`(True, 7, 1, <Direction.up: 3>)`'), ('dock', '`(True, 8, 5, <Direction.up: 3>)`'), ('apace', '`(True, 5, 8, <Direction.up: 3>)`'), ('mown', '`(True, 0, 5, <Direction.right: 2>)`'), ('pears', '`(True, 0, 3, <Direction.downright: 8>)`'), ('wide', '`(True, 4, 4, <Direction.upright: 6>)`')]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 114,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import string\n",
+    "import re\n",
+    "import collections\n",
+    "import copy\n",
+    "import os\n",
+    "\n",
+    "from enum import Enum\n",
+    "Direction = Enum('Direction', 'left right up down upleft upright downleft downright')\n",
+    "    \n",
+    "delta = {Direction.left: (0, -1),Direction.right: (0, 1), \n",
+    "         Direction.up: (-1, 0), Direction.down: (1, 0), \n",
+    "         Direction.upleft: (-1, -1), Direction.upright: (-1, 1), \n",
+    "         Direction.downleft: (1, -1), Direction.downright: (1, 1)}\n",
+    "\n",
+    "cat = ''.join\n",
+    "wcat = ' '.join\n",
+    "lcat = '\\n'.join"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 115,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def empty_grid(w, h):\n",
+    "    return [['.' for c in range(w)] for r in range(h)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 116,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def show_grid(grid):\n",
+    "    return lcat(cat(r) for r in grid)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 117,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def indices(grid, r, c, l, d):\n",
+    "    dr, dc = delta[d]\n",
+    "    w = len(grid[0])\n",
+    "    h = len(grid)\n",
+    "    inds = [(r + i * dr, c + i * dc) for i in range(l)]\n",
+    "    return [(i, j) for i, j in inds\n",
+    "           if i >= 0\n",
+    "           if j >= 0\n",
+    "           if i < h\n",
+    "           if j < w]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 118,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def gslice(grid, r, c, l, d):\n",
+    "    return [grid[i][j] for i, j in indices(grid, r, c, l, d)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 119,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def set_grid(grid, r, c, d, word):\n",
+    "    for (i, j), l in zip(indices(grid, r, c, len(word), d), word):\n",
+    "        grid[i][j] = l\n",
+    "    return grid"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 120,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def present_many(grid, words):\n",
+    "    w = len(grid[0])\n",
+    "    h = len(grid)\n",
+    "    wordlens = set(len(w) for w in words)\n",
+    "    presences = []\n",
+    "    for r in range(h):\n",
+    "        for c in range(w):\n",
+    "            for d in Direction:\n",
+    "                for wordlen in wordlens:\n",
+    "                    word = cat(gslice(grid, r, c, wordlen, d))\n",
+    "                    if word in words:\n",
+    "                        presences += [(word, r, c, d)]\n",
+    "    return set(presences)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 121,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def read_wordsearch(fn):\n",
+    "    lines = [l.strip() for l in open(fn).readlines()]\n",
+    "    w, h = [int(s) for s in lines[0].split('x')]\n",
+    "    grid = lines[1:h+1]\n",
+    "    words = lines[h+1:]\n",
+    "    return w, h, grid, words"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# All wordsearch puzzles"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 122,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def read_all_wordsearch(fn):\n",
+    "    with open(fn) as f:\n",
+    "        text = f.read().strip()\n",
+    "        puzzles_text = text.split('\\n\\n')\n",
+    "        puzzles = []\n",
+    "        for p in puzzles_text:\n",
+    "            lines = p.splitlines()\n",
+    "            w, h = [int(s) for s in lines[0].split('x')]\n",
+    "            grid = lines[1:h+1]\n",
+    "            words = lines[h+1:]\n",
+    "            puzzles += [(w, h, grid, words)]\n",
+    "    return puzzles"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Huge wordsearch"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 123,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(100, 100)"
+      ]
+     },
+     "execution_count": 123,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "puzzle = read_wordsearch('04-wordsearch.txt')\n",
+    "puzzle[:2]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Part 1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 124,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def found_words_length(puzzle):\n",
+    "    width, height, grid, words = puzzle\n",
+    "    return sum(len(p[0]) for p in present_many(grid, words))\n",
+    "\n",
+    "def total_found_words_length(puzzles):\n",
+    "    return sum(found_words_length(p) for p in puzzles)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 125,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "8092"
+      ]
+     },
+     "execution_count": 125,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "found_words_length(puzzle)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 126,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 loop, best of 3: 31.4 s per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "found_words_length(puzzle)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 127,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1149"
+      ]
+     },
+     "execution_count": 127,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "width, height, grid, words = puzzle\n",
+    "len(present_many(grid, words))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Part 2"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 128,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def max_unfound_word_length(puzzle):\n",
+    "    width, height, grid, words = puzzle\n",
+    "    presences = present_many(grid, words)\n",
+    "    used_words = [p[0] for p in presences]\n",
+    "    unused_words = [w for w in words if w not in used_words]\n",
+    "    \n",
+    "    unused_grid = [[c for c in r] for r in grid]\n",
+    "    for w, r, c, d in presences:\n",
+    "        set_grid(unused_grid, r, c, d, '.' * len(w))\n",
+    "    unused_letters = [c for l in unused_grid for c in l if c != '.']\n",
+    "    unused_letter_count = collections.Counter(unused_letters)\n",
+    "    \n",
+    "    makeable_words = []\n",
+    "    for w in unused_words:\n",
+    "        unused_word_count = collections.Counter(w)\n",
+    "        if all(unused_word_count[l] <= unused_letter_count[l] for l in unused_word_count):\n",
+    "            makeable_words += [w]\n",
+    "    lwm = max(len(w) for w in makeable_words)\n",
+    "    return lwm"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 129,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def unused_letters(puzzle):\n",
+    "    width, height, grid, words = puzzle\n",
+    "    presences = present_many(grid, words)\n",
+    "    used_words = [p[0] for p in presences]\n",
+    "    unused_words = [w for w in words if w not in used_words]\n",
+    "    \n",
+    "    unused_grid = [[c for c in r] for r in grid]\n",
+    "    for w, r, c, d in presences:\n",
+    "        set_grid(unused_grid, r, c, d, '.' * len(w))\n",
+    "    unused_letters = [c for l in unused_grid for c in l if c != '.']\n",
+    "    unused_letter_count = collections.Counter(unused_letters)\n",
+    "    \n",
+    "    return used_words, unused_letter_count"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 130,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def unused_vowels(puzzle):\n",
+    "    width, height, grid, words = puzzle\n",
+    "    presences = present_many(grid, words)\n",
+    "    used_words = [p[0] for p in presences]\n",
+    "    unused_words = [w for w in words if w not in used_words]\n",
+    "    \n",
+    "    unused_grid = [[c for c in r] for r in grid]\n",
+    "    for w, r, c, d in presences:\n",
+    "        set_grid(unused_grid, r, c, d, '.' * len(w))\n",
+    "    unused_vowel_count = sum(1 for l in unused_grid for c in l if c in 'aeiou')\n",
+    "    return unused_vowel_count"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 131,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def total_max_unfound_word_length(puzzles):\n",
+    "    return sum(max_unfound_word_length(p) for p in puzzles)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 132,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "594"
+      ]
+     },
+     "execution_count": 132,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "unused_vowels(puzzle)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 133,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 loop, best of 3: 31.3 s per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "unused_vowels(puzzle)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 134,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# max_unfound_word_length(puzzle)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 135,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# %%timeit\n",
+    "# max_unfound_word_length(puzzle)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 138,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "2217"
+      ]
+     },
+     "execution_count": 138,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "uw, unlc = unused_letters(puzzle)\n",
+    "sum(unlc[l] for l in unlc)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.2+"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 1
+}
diff --git a/04-word-search/wordsearch-solving.ipynb b/04-word-search/wordsearch-solving.ipynb
deleted file mode 100644 (file)
index 758380a..0000000
+++ /dev/null
@@ -1,1446 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "# Wordsearch\n",
-    "Given a text file, consisting of three parts (a grid size, a grid, and a list of words), find:\n",
-    "* the words present in the grid, \n",
-    "* the longest word present in the grid, \n",
-    "* the number of words not present in the grid, \n",
-    "* the longest word not present that can be formed from the leftover letters\n",
-    "\n",
-    "The only words that need be considered are the ones given in the list in the puzzle input.\n",
-    "\n",
-    "The puzzle consists of:\n",
-    "1. A line consisting of _w_`x`_h_, where _w_ and _h_ are integers giving the width and height of the grid.\n",
-    "2. The grid itself, consisting of _h_ lines each of _w_ letters.\n",
-    "3. A list of words, one word per line, of arbitrary length. "
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Example\n",
-    "\n",
-    "\n",
-    "`...p.mown.\n",
-    ".sdse..ee.\n",
-    ".e.elad.cr\n",
-    "pi.dtir.ah\n",
-    "rzsiwovspu\n",
-    "oawh.kieab\n",
-    "brow.c.rda\n",
-    "ecnotops.r\n",
-    "d.kc.d...b\n",
-    ".staple...`\n",
-    "\n",
-    "```\n",
-    "fhjpamownq\n",
-    "wsdseuqeev\n",
-    "ieaeladhcr\n",
-    "piedtiriah\n",
-    "rzsiwovspu\n",
-    "oawhakieab\n",
-    "browpcfrda\n",
-    "ecnotopssr\n",
-    "dikchdnpnb\n",
-    "bstapleokr\n",
-    "```\n",
-    "\n",
-    "14 words added;  6 directions\n",
-    "\n",
-    "Present: apace cowhides crazies dock knows lived mown pears probed rhubarb rioted staple tops wide\n",
-    "\n",
-    "Decoys: adapting bombing boor brick cackles carnal casino chaplets chump coaster coccyxes coddle collies creels crumbled cunt curds curled curlier deepen demeanor dicier dowses ensuing faddish fest fickler foaming gambol garoting gliding gristle grunts guts ibex impugns instants kielbasy lanyard loamier lugs market meanly minuend misprint mitts molested moonshot mucking oaks olives orgasmic pastrami perfect proceed puckered quashed refined regards retraces revel ridges ringlet scoff shinier siren solaria sprain sunder sunup tamped tapes thirds throw tiller times trains tranquil transfix typesets uric wariness welts whimsy winced winced\n",
-    "\n",
-    "Decoys: fickler, adapting, chump, foaming, molested, carnal, crumbled, guts, minuend, bombing, winced, coccyxes, solaria, shinier, cackles\n",
-    "\n",
-    "All words: adapting, apace, bombing, cackles, carnal, chump, coccyxes, cowhides, crazies, crumbled, dock, fickler, foaming, guts, knows, lived, minuend, molested, mown, pears, probed, rhubarb, rioted, shinier, solaria, staple, tops, wide, winced\n",
-    "\n",
-    "Directions:  [('probed', '`(True, 3, 0, <Direction.down: 4>)`'), ('staple', '`(True, 9, 1, <Direction.right: 2>)`'), ('rioted', '`(True, 6, 7, <Direction.upleft: 5>)`'), ('cowhides', '`(True, 8, 3, <Direction.up: 3>)`'), ('tops', '`(True, 7, 4, <Direction.right: 2>)`'), ('knows', '`(True, 8, 2, <Direction.up: 3>)`'), ('lived', '`(True, 2, 4, <Direction.downright: 8>)`'), ('rhubarb', '`(True, 2, 9, <Direction.down: 4>)`'), ('crazies', '`(True, 7, 1, <Direction.up: 3>)`'), ('dock', '`(True, 8, 5, <Direction.up: 3>)`'), ('apace', '`(True, 5, 8, <Direction.up: 3>)`'), ('mown', '`(True, 0, 5, <Direction.right: 2>)`'), ('pears', '`(True, 0, 3, <Direction.downright: 8>)`'), ('wide', '`(True, 4, 4, <Direction.upright: 6>)`')]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "import string\n",
-    "import re\n",
-    "import collections\n",
-    "import copy\n",
-    "import os\n",
-    "\n",
-    "from enum import Enum\n",
-    "Direction = Enum('Direction', 'left right up down upleft upright downleft downright')\n",
-    "    \n",
-    "delta = {Direction.left: (0, -1),Direction.right: (0, 1), \n",
-    "         Direction.up: (-1, 0), Direction.down: (1, 0), \n",
-    "         Direction.upleft: (-1, -1), Direction.upright: (-1, 1), \n",
-    "         Direction.downleft: (1, -1), Direction.downright: (1, 1)}\n",
-    "\n",
-    "cat = ''.join\n",
-    "wcat = ' '.join\n",
-    "lcat = '\\n'.join"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def empty_grid(w, h):\n",
-    "    return [['.' for c in range(w)] for r in range(h)]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def show_grid(grid):\n",
-    "    return lcat(cat(r) for r in grid)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def indices(grid, r, c, l, d):\n",
-    "    dr, dc = delta[d]\n",
-    "    w = len(grid[0])\n",
-    "    h = len(grid)\n",
-    "    inds = [(r + i * dr, c + i * dc) for i in range(l)]\n",
-    "    return [(i, j) for i, j in inds\n",
-    "           if i >= 0\n",
-    "           if j >= 0\n",
-    "           if i < h\n",
-    "           if j < w]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 8,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def gslice(grid, r, c, l, d):\n",
-    "    return [grid[i][j] for i, j in indices(grid, r, c, l, d)]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def set_grid(grid, r, c, d, word):\n",
-    "    for (i, j), l in zip(indices(grid, r, c, len(word), d), word):\n",
-    "        grid[i][j] = l\n",
-    "    return grid"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 10,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def present(grid, word):\n",
-    "    w = len(grid[0])\n",
-    "    h = len(grid)\n",
-    "    for r in range(h):\n",
-    "        for c in range(w):\n",
-    "            for d in Direction:\n",
-    "                if cat(gslice(grid, r, c, len(word), d)) == word:\n",
-    "                    return True, r, c, d\n",
-    "    return False, 0, 0, list(Direction)[0]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 11,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def read_wordsearch(fn):\n",
-    "    lines = [l.strip() for l in open(fn).readlines()]\n",
-    "    w, h = [int(s) for s in lines[0].split('x')]\n",
-    "    grid = lines[1:h+1]\n",
-    "    words = lines[h+1:]\n",
-    "    return w, h, grid, words"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 12,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "(['pistrohxegniydutslxt',\n",
-       "  'wmregunarbpiledsyuoo',\n",
-       "  'hojminbmutartslrlmgo',\n",
-       "  'isrsdniiekildabolpll',\n",
-       "  'tstsnyekentypkalases',\n",
-       "  'ssnetengcrfetedirgdt',\n",
-       "  'religstasuslatxauner',\n",
-       "  'elgcpgatsklglzistilo',\n",
-       "  'tndlimitationilkasan',\n",
-       "  'aousropedlygiifeniog',\n",
-       "  'kilrprepszffsyzqsrhs',\n",
-       "  'itlaadorableorpccese',\n",
-       "  'noaeewoodedpngmqicnl',\n",
-       "  'gmrtoitailingchelrok',\n",
-       "  'jadsngninetsahtooeic',\n",
-       "  'xeernighestsailarmtu',\n",
-       "  'aeabsolvednscumdfnon',\n",
-       "  'gydammingawlcandornk',\n",
-       "  'hurlerslvkaccxcinosw',\n",
-       "  'iqnanoitacifitrofqqi'],\n",
-       " ['absolved',\n",
-       "  'adorable',\n",
-       "  'aeon',\n",
-       "  'alias',\n",
-       "  'ancestor',\n",
-       "  'baritone',\n",
-       "  'bemusing',\n",
-       "  'blonds',\n",
-       "  'bran',\n",
-       "  'calcite',\n",
-       "  'candor',\n",
-       "  'conciseness',\n",
-       "  'consequent',\n",
-       "  'cuddle',\n",
-       "  'damming',\n",
-       "  'dashboards',\n",
-       "  'despairing',\n",
-       "  'dint',\n",
-       "  'dullard',\n",
-       "  'dynasty',\n",
-       "  'employer',\n",
-       "  'exhorts',\n",
-       "  'feted',\n",
-       "  'fill',\n",
-       "  'flattens',\n",
-       "  'foghorn',\n",
-       "  'fortification',\n",
-       "  'freakish',\n",
-       "  'frolics',\n",
-       "  'gall',\n",
-       "  'gees',\n",
-       "  'genies',\n",
-       "  'gets',\n",
-       "  'hastening',\n",
-       "  'hits',\n",
-       "  'hopelessness',\n",
-       "  'hurlers',\n",
-       "  'impales',\n",
-       "  'infix',\n",
-       "  'inflow',\n",
-       "  'innumerable',\n",
-       "  'intentional',\n",
-       "  'jerkin',\n",
-       "  'justification',\n",
-       "  'kitty',\n",
-       "  'knuckles',\n",
-       "  'leaving',\n",
-       "  'like',\n",
-       "  'limitation',\n",
-       "  'locoweeds',\n",
-       "  'loot',\n",
-       "  'lucking',\n",
-       "  'lumps',\n",
-       "  'mercerising',\n",
-       "  'monickers',\n",
-       "  'motionless',\n",
-       "  'naturally',\n",
-       "  'nighest',\n",
-       "  'notion',\n",
-       "  'ogled',\n",
-       "  'originality',\n",
-       "  'outings',\n",
-       "  'pendulous',\n",
-       "  'piled',\n",
-       "  'pins',\n",
-       "  'pithier',\n",
-       "  'prep',\n",
-       "  'randomness',\n",
-       "  'rectors',\n",
-       "  'redrew',\n",
-       "  'reformulated',\n",
-       "  'remoteness',\n",
-       "  'retaking',\n",
-       "  'rethink',\n",
-       "  'rope',\n",
-       "  'rubier',\n",
-       "  'sailors',\n",
-       "  'scowls',\n",
-       "  'scum',\n",
-       "  'sepals',\n",
-       "  'sequencers',\n",
-       "  'serf',\n",
-       "  'shoaled',\n",
-       "  'shook',\n",
-       "  'sonic',\n",
-       "  'spottiest',\n",
-       "  'stag',\n",
-       "  'stood',\n",
-       "  'stratum',\n",
-       "  'strong',\n",
-       "  'studying',\n",
-       "  'surtaxing',\n",
-       "  'tailing',\n",
-       "  'tears',\n",
-       "  'teazles',\n",
-       "  'vans',\n",
-       "  'wardrobes',\n",
-       "  'wooded',\n",
-       "  'worsts',\n",
-       "  'zings'])"
-      ]
-     },
-     "execution_count": 12,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "width, height, g, ws = read_wordsearch('wordsearch04.txt')\n",
-    "g, ws"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 13,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "absolved (True, 16, 2, <Direction.right: 2>)\n",
-      "adorable (True, 11, 4, <Direction.right: 2>)\n",
-      "aeon (True, 11, 4, <Direction.down: 4>)\n",
-      "alias (True, 15, 15, <Direction.left: 1>)\n",
-      "ancestor (False, 0, 0, <Direction.left: 1>)\n",
-      "baritone (False, 0, 0, <Direction.left: 1>)\n",
-      "bemusing (False, 0, 0, <Direction.left: 1>)\n",
-      "blonds (False, 0, 0, <Direction.left: 1>)\n",
-      "bran (True, 1, 9, <Direction.left: 1>)\n",
-      "calcite (True, 19, 9, <Direction.upright: 6>)\n",
-      "candor (True, 17, 12, <Direction.right: 2>)\n",
-      "conciseness (False, 0, 0, <Direction.left: 1>)\n",
-      "consequent (False, 0, 0, <Direction.left: 1>)\n",
-      "cuddle (False, 0, 0, <Direction.left: 1>)\n",
-      "damming (True, 17, 2, <Direction.right: 2>)\n",
-      "dashboards (False, 0, 0, <Direction.left: 1>)\n",
-      "despairing (False, 0, 0, <Direction.left: 1>)\n",
-      "dint (False, 0, 0, <Direction.left: 1>)\n",
-      "dullard (True, 8, 2, <Direction.down: 4>)\n",
-      "dynasty (True, 3, 4, <Direction.downright: 8>)\n",
-      "employer (False, 0, 0, <Direction.left: 1>)\n",
-      "exhorts (True, 0, 8, <Direction.left: 1>)\n",
-      "feted (True, 5, 10, <Direction.right: 2>)\n",
-      "fill (True, 9, 14, <Direction.upleft: 5>)\n",
-      "flattens (True, 10, 10, <Direction.upleft: 5>)\n",
-      "foghorn (True, 10, 11, <Direction.downright: 8>)\n",
-      "fortification (True, 19, 16, <Direction.left: 1>)\n",
-      "freakish (False, 0, 0, <Direction.left: 1>)\n",
-      "frolics (True, 16, 16, <Direction.up: 3>)\n",
-      "gall (False, 0, 0, <Direction.left: 1>)\n",
-      "gees (True, 17, 0, <Direction.upright: 6>)\n",
-      "genies (True, 5, 7, <Direction.upleft: 5>)\n",
-      "gets (True, 6, 4, <Direction.upleft: 5>)\n",
-      "hastening (True, 14, 13, <Direction.left: 1>)\n",
-      "hits (True, 2, 0, <Direction.down: 4>)\n",
-      "hopelessness (False, 0, 0, <Direction.left: 1>)\n",
-      "hurlers (True, 18, 0, <Direction.right: 2>)\n",
-      "impales (False, 0, 0, <Direction.left: 1>)\n",
-      "infix (False, 0, 0, <Direction.left: 1>)\n",
-      "inflow (False, 0, 0, <Direction.left: 1>)\n",
-      "innumerable (False, 0, 0, <Direction.left: 1>)\n",
-      "intentional (False, 0, 0, <Direction.left: 1>)\n",
-      "jerkin (False, 0, 0, <Direction.left: 1>)\n",
-      "justification (False, 0, 0, <Direction.left: 1>)\n",
-      "kitty (True, 8, 15, <Direction.upleft: 5>)\n",
-      "knuckles (True, 17, 19, <Direction.up: 3>)\n",
-      "leaving (False, 0, 0, <Direction.left: 1>)\n",
-      "like (True, 3, 11, <Direction.left: 1>)\n",
-      "limitation (True, 8, 3, <Direction.right: 2>)\n",
-      "locoweeds (False, 0, 0, <Direction.left: 1>)\n",
-      "loot (True, 3, 19, <Direction.up: 3>)\n",
-      "lucking (True, 7, 10, <Direction.upleft: 5>)\n",
-      "lumps (True, 0, 17, <Direction.down: 4>)\n",
-      "mercerising (True, 15, 17, <Direction.up: 3>)\n",
-      "monickers (False, 0, 0, <Direction.left: 1>)\n",
-      "motionless (True, 13, 1, <Direction.up: 3>)\n",
-      "naturally (True, 9, 16, <Direction.up: 3>)\n",
-      "nighest (True, 15, 4, <Direction.right: 2>)\n",
-      "notion (True, 17, 18, <Direction.up: 3>)\n",
-      "ogled (True, 1, 18, <Direction.down: 4>)\n",
-      "originality (False, 0, 0, <Direction.left: 1>)\n",
-      "outings (False, 0, 0, <Direction.left: 1>)\n",
-      "pendulous (False, 0, 0, <Direction.left: 1>)\n",
-      "piled (True, 1, 10, <Direction.right: 2>)\n",
-      "pins (True, 7, 4, <Direction.upleft: 5>)\n",
-      "pithier (False, 0, 0, <Direction.left: 1>)\n",
-      "prep (True, 10, 4, <Direction.right: 2>)\n",
-      "randomness (False, 0, 0, <Direction.left: 1>)\n",
-      "rectors (False, 0, 0, <Direction.left: 1>)\n",
-      "redrew (False, 0, 0, <Direction.left: 1>)\n",
-      "reformulated (False, 0, 0, <Direction.left: 1>)\n",
-      "remoteness (False, 0, 0, <Direction.left: 1>)\n",
-      "retaking (True, 6, 0, <Direction.down: 4>)\n",
-      "rethink (False, 0, 0, <Direction.left: 1>)\n",
-      "rope (True, 9, 4, <Direction.right: 2>)\n",
-      "rubier (True, 0, 4, <Direction.downright: 8>)\n",
-      "sailors (True, 7, 15, <Direction.up: 3>)\n",
-      "scowls (False, 0, 0, <Direction.left: 1>)\n",
-      "scum (True, 16, 11, <Direction.right: 2>)\n",
-      "sepals (True, 6, 10, <Direction.upright: 6>)\n",
-      "sequencers (False, 0, 0, <Direction.left: 1>)\n",
-      "serf (False, 0, 0, <Direction.left: 1>)\n",
-      "shoaled (True, 11, 18, <Direction.up: 3>)\n",
-      "shook (False, 0, 0, <Direction.left: 1>)\n",
-      "sonic (True, 18, 18, <Direction.left: 1>)\n",
-      "spottiest (False, 0, 0, <Direction.left: 1>)\n",
-      "stag (True, 7, 8, <Direction.left: 1>)\n",
-      "stood (False, 0, 0, <Direction.left: 1>)\n",
-      "stratum (True, 2, 13, <Direction.left: 1>)\n",
-      "strong (True, 4, 19, <Direction.down: 4>)\n",
-      "studying (True, 0, 16, <Direction.left: 1>)\n",
-      "surtaxing (False, 0, 0, <Direction.left: 1>)\n",
-      "tailing (True, 13, 6, <Direction.right: 2>)\n",
-      "tears (True, 13, 3, <Direction.up: 3>)\n",
-      "teazles (True, 4, 10, <Direction.downright: 8>)\n",
-      "vans (True, 18, 8, <Direction.upright: 6>)\n",
-      "wardrobes (False, 0, 0, <Direction.left: 1>)\n",
-      "wooded (True, 12, 5, <Direction.right: 2>)\n",
-      "worsts (True, 1, 0, <Direction.downright: 8>)\n",
-      "zings (True, 10, 14, <Direction.upleft: 5>)\n"
-     ]
-    }
-   ],
-   "source": [
-    "for w in ws:\n",
-    "    print(w, present(g, w))"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Which words are present?"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 14,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['absolved',\n",
-       " 'adorable',\n",
-       " 'aeon',\n",
-       " 'alias',\n",
-       " 'bran',\n",
-       " 'calcite',\n",
-       " 'candor',\n",
-       " 'damming',\n",
-       " 'dullard',\n",
-       " 'dynasty',\n",
-       " 'exhorts',\n",
-       " 'feted',\n",
-       " 'fill',\n",
-       " 'flattens',\n",
-       " 'foghorn',\n",
-       " 'fortification',\n",
-       " 'frolics',\n",
-       " 'gees',\n",
-       " 'genies',\n",
-       " 'gets',\n",
-       " 'hastening',\n",
-       " 'hits',\n",
-       " 'hurlers',\n",
-       " 'kitty',\n",
-       " 'knuckles',\n",
-       " 'like',\n",
-       " 'limitation',\n",
-       " 'loot',\n",
-       " 'lucking',\n",
-       " 'lumps',\n",
-       " 'mercerising',\n",
-       " 'motionless',\n",
-       " 'naturally',\n",
-       " 'nighest',\n",
-       " 'notion',\n",
-       " 'ogled',\n",
-       " 'piled',\n",
-       " 'pins',\n",
-       " 'prep',\n",
-       " 'retaking',\n",
-       " 'rope',\n",
-       " 'rubier',\n",
-       " 'sailors',\n",
-       " 'scum',\n",
-       " 'sepals',\n",
-       " 'shoaled',\n",
-       " 'sonic',\n",
-       " 'stag',\n",
-       " 'stratum',\n",
-       " 'strong',\n",
-       " 'studying',\n",
-       " 'tailing',\n",
-       " 'tears',\n",
-       " 'teazles',\n",
-       " 'vans',\n",
-       " 'wooded',\n",
-       " 'worsts',\n",
-       " 'zings']"
-      ]
-     },
-     "execution_count": 14,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "[w for w in ws if present(g, w)[0]]"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "What is the longest word that is present?"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 15,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'fortification'"
-      ]
-     },
-     "execution_count": 15,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "sorted([w for w in ws if present(g, w)[0]], key=len)[-1]"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "What is the longest word that is absent?"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 16,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'justification'"
-      ]
-     },
-     "execution_count": 16,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "sorted([w for w in ws if not present(g, w)[0]], key=len)[-1]"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "How many letters are unused?"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 17,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "57"
-      ]
-     },
-     "execution_count": 17,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "g0 = empty_grid(width, height)\n",
-    "for w in ws:\n",
-    "    p, r, c, d = present(g, w)\n",
-    "    if p:\n",
-    "        set_grid(g0, r, c, d, w)\n",
-    "len([c for c in cat(cat(l) for l in g0) if c == '.'])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "What is the longest word you can make form the leftover letters?"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 18,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "Counter({'a': 4,\n",
-       "         'b': 1,\n",
-       "         'c': 5,\n",
-       "         'd': 3,\n",
-       "         'e': 1,\n",
-       "         'g': 2,\n",
-       "         'i': 5,\n",
-       "         'j': 2,\n",
-       "         'k': 3,\n",
-       "         'l': 2,\n",
-       "         'm': 3,\n",
-       "         'n': 3,\n",
-       "         'p': 3,\n",
-       "         'q': 5,\n",
-       "         'r': 3,\n",
-       "         's': 3,\n",
-       "         'w': 2,\n",
-       "         'x': 4,\n",
-       "         'y': 2,\n",
-       "         'z': 1})"
-      ]
-     },
-     "execution_count": 18,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "unused_letters = [l for l, u in zip((c for c in cat(cat(l) for l in g)), (c for c in cat(cat(l) for l in g0)))\n",
-    "                  if u == '.']\n",
-    "unused_letter_count = collections.Counter(unused_letters)\n",
-    "unused_letter_count"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 19,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['ancestor',\n",
-       " 'baritone',\n",
-       " 'bemusing',\n",
-       " 'blonds',\n",
-       " 'conciseness',\n",
-       " 'consequent',\n",
-       " 'cuddle',\n",
-       " 'dashboards',\n",
-       " 'despairing',\n",
-       " 'dint',\n",
-       " 'employer',\n",
-       " 'freakish',\n",
-       " 'gall',\n",
-       " 'hopelessness',\n",
-       " 'impales',\n",
-       " 'infix',\n",
-       " 'inflow',\n",
-       " 'innumerable',\n",
-       " 'intentional',\n",
-       " 'jerkin',\n",
-       " 'justification',\n",
-       " 'leaving',\n",
-       " 'locoweeds',\n",
-       " 'monickers',\n",
-       " 'originality',\n",
-       " 'outings',\n",
-       " 'pendulous',\n",
-       " 'pithier',\n",
-       " 'randomness',\n",
-       " 'rectors',\n",
-       " 'redrew',\n",
-       " 'reformulated',\n",
-       " 'remoteness',\n",
-       " 'rethink',\n",
-       " 'scowls',\n",
-       " 'sequencers',\n",
-       " 'serf',\n",
-       " 'shook',\n",
-       " 'spottiest',\n",
-       " 'stood',\n",
-       " 'surtaxing',\n",
-       " 'wardrobes']"
-      ]
-     },
-     "execution_count": 19,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "unused_words = [w for w in ws if not present(g, w)[0]]\n",
-    "unused_words"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 20,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "ancestor Counter({'e': 1, 'a': 1, 's': 1, 'c': 1, 'n': 1, 'o': 1, 'r': 1, 't': 1})\n",
-      "baritone Counter({'i': 1, 'e': 1, 'a': 1, 'n': 1, 't': 1, 'o': 1, 'r': 1, 'b': 1})\n",
-      "bemusing Counter({'i': 1, 'e': 1, 's': 1, 'g': 1, 'n': 1, 'b': 1, 'u': 1, 'm': 1})\n",
-      "blonds Counter({'n': 1, 'l': 1, 's': 1, 'd': 1, 'o': 1, 'b': 1})\n",
-      "conciseness Counter({'s': 3, 'e': 2, 'n': 2, 'c': 2, 'i': 1, 'o': 1})\n",
-      "consequent Counter({'e': 2, 'n': 2, 'c': 1, 's': 1, 'q': 1, 'o': 1, 'u': 1, 't': 1})\n",
-      "cuddle Counter({'d': 2, 'l': 1, 'e': 1, 'u': 1, 'c': 1})\n",
-      "dashboards Counter({'a': 2, 's': 2, 'd': 2, 'o': 1, 'h': 1, 'r': 1, 'b': 1})\n",
-      "*despairing Counter({'i': 2, 'n': 1, 'e': 1, 'a': 1, 'p': 1, 'g': 1, 's': 1, 'd': 1, 'r': 1})\n",
-      "dint Counter({'i': 1, 'd': 1, 'n': 1, 't': 1})\n",
-      "employer Counter({'e': 2, 'p': 1, 'l': 1, 'y': 1, 'o': 1, 'm': 1, 'r': 1})\n",
-      "freakish Counter({'f': 1, 'i': 1, 'e': 1, 'a': 1, 's': 1, 'k': 1, 'h': 1, 'r': 1})\n",
-      "*gall Counter({'l': 2, 'g': 1, 'a': 1})\n",
-      "hopelessness Counter({'s': 4, 'e': 3, 'n': 1, 'p': 1, 'l': 1, 'h': 1, 'o': 1})\n",
-      "*impales Counter({'i': 1, 'e': 1, 'a': 1, 'p': 1, 'l': 1, 's': 1, 'm': 1})\n",
-      "infix Counter({'i': 2, 'f': 1, 'x': 1, 'n': 1})\n",
-      "inflow Counter({'f': 1, 'i': 1, 'n': 1, 'l': 1, 'w': 1, 'o': 1})\n",
-      "innumerable Counter({'e': 2, 'n': 2, 'i': 1, 'a': 1, 'l': 1, 'r': 1, 'b': 1, 'u': 1, 'm': 1})\n",
-      "intentional Counter({'n': 3, 'i': 2, 't': 2, 'e': 1, 'a': 1, 'l': 1, 'o': 1})\n",
-      "*jerkin Counter({'i': 1, 'e': 1, 'n': 1, 'k': 1, 'j': 1, 'r': 1})\n",
-      "justification Counter({'i': 3, 't': 2, 'f': 1, 'a': 1, 's': 1, 'c': 1, 'j': 1, 'o': 1, 'u': 1, 'n': 1})\n",
-      "leaving Counter({'g': 1, 'i': 1, 'e': 1, 'a': 1, 'n': 1, 'l': 1, 'v': 1})\n",
-      "locoweeds Counter({'e': 2, 'o': 2, 'w': 1, 'l': 1, 'c': 1, 's': 1, 'd': 1})\n",
-      "monickers Counter({'i': 1, 'e': 1, 'n': 1, 'c': 1, 's': 1, 'k': 1, 'o': 1, 'm': 1, 'r': 1})\n",
-      "originality Counter({'i': 3, 'a': 1, 'n': 1, 'l': 1, 'y': 1, 'g': 1, 't': 1, 'o': 1, 'r': 1})\n",
-      "outings Counter({'i': 1, 'n': 1, 's': 1, 'g': 1, 't': 1, 'o': 1, 'u': 1})\n",
-      "pendulous Counter({'u': 2, 'e': 1, 'n': 1, 'l': 1, 's': 1, 'p': 1, 'd': 1, 'o': 1})\n",
-      "pithier Counter({'i': 2, 'e': 1, 'p': 1, 't': 1, 'h': 1, 'r': 1})\n",
-      "randomness Counter({'n': 2, 's': 2, 'e': 1, 'a': 1, 'd': 1, 'o': 1, 'r': 1, 'm': 1})\n",
-      "rectors Counter({'r': 2, 'e': 1, 's': 1, 'c': 1, 't': 1, 'o': 1})\n",
-      "redrew Counter({'e': 2, 'r': 2, 'w': 1, 'd': 1})\n",
-      "reformulated Counter({'e': 2, 'r': 2, 'f': 1, 'a': 1, 'l': 1, 'u': 1, 't': 1, 'd': 1, 'o': 1, 'm': 1})\n",
-      "remoteness Counter({'e': 3, 's': 2, 'n': 1, 't': 1, 'o': 1, 'r': 1, 'm': 1})\n",
-      "rethink Counter({'i': 1, 'e': 1, 'n': 1, 'k': 1, 't': 1, 'h': 1, 'r': 1})\n",
-      "scowls Counter({'s': 2, 'o': 1, 'l': 1, 'w': 1, 'c': 1})\n",
-      "sequencers Counter({'e': 3, 's': 2, 'n': 1, 'q': 1, 'c': 1, 'u': 1, 'r': 1})\n",
-      "serf Counter({'f': 1, 'e': 1, 's': 1, 'r': 1})\n",
-      "shook Counter({'o': 2, 'h': 1, 's': 1, 'k': 1})\n",
-      "spottiest Counter({'t': 3, 's': 2, 'i': 1, 'e': 1, 'p': 1, 'o': 1})\n",
-      "stood Counter({'o': 2, 't': 1, 's': 1, 'd': 1})\n",
-      "surtaxing Counter({'x': 1, 'i': 1, 'a': 1, 's': 1, 'g': 1, 't': 1, 'n': 1, 'u': 1, 'r': 1})\n",
-      "wardrobes Counter({'r': 2, 'e': 1, 'a': 1, 'w': 1, 's': 1, 'd': 1, 'o': 1, 'b': 1})\n"
-     ]
-    }
-   ],
-   "source": [
-    "makeable_words = []\n",
-    "for w in unused_words:\n",
-    "    unused_word_count = collections.Counter(w)\n",
-    "    if all(unused_word_count[l] <= unused_letter_count[l] for l in unused_word_count):\n",
-    "        makeable_words += [w]\n",
-    "        print('*', end='')\n",
-    "    print(w, unused_word_count)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 21,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "10"
-      ]
-     },
-     "execution_count": 21,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "max(len(w) for w in makeable_words)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 22,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'despairing'"
-      ]
-     },
-     "execution_count": 22,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "sorted(makeable_words, key=len)[-1]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 23,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def do_wordsearch_tasks(fn, show_anyway=False):\n",
-    "    width, height, grid, words = read_wordsearch(fn)\n",
-    "    used_words = [w for w in words if present(grid, w)[0]]\n",
-    "    unused_words = [w for w in words if not present(grid, w)[0]]\n",
-    "    lwp = sorted([w for w in words if present(grid, w)[0]], key=len)[-1]\n",
-    "    lwps = [w for w in used_words if len(w) == len(lwp)]\n",
-    "    lwa = sorted(unused_words, key=len)[-1]\n",
-    "    lwas = [w for w in unused_words if len(w) == len(lwa)]\n",
-    "    g0 = empty_grid(width, height)\n",
-    "    for w in words:\n",
-    "        p, r, c, d = present(grid, w)\n",
-    "        if p:\n",
-    "            set_grid(g0, r, c, d, w) \n",
-    "    unused_letters = [l for l, u in zip((c for c in cat(cat(l) for l in grid)), (c for c in cat(cat(l) for l in g0)))\n",
-    "                  if u == '.']\n",
-    "    unused_letter_count = collections.Counter(unused_letters)\n",
-    "    makeable_words = []\n",
-    "    for w in unused_words:\n",
-    "        unused_word_count = collections.Counter(w)\n",
-    "        if all(unused_word_count[l] <= unused_letter_count[l] for l in unused_word_count):\n",
-    "            makeable_words += [w]\n",
-    "    lwm = sorted(makeable_words, key=len)[-1]\n",
-    "    lwms = [w for w in makeable_words if len(w) == len(lwm)]\n",
-    "    if show_anyway or len(set((len(lwp),len(lwa),len(lwm)))) == 3:\n",
-    "        print('\\n{}'.format(fn))\n",
-    "        print('{} words present'.format(len(words) - len(unused_words)))\n",
-    "        print('Longest word present: {}, {} letters ({})'.format(lwp, len(lwp), lwps))\n",
-    "        print('Longest word absent: {}, {} letters ({})'.format(lwa, len(lwa), lwas))\n",
-    "        print('{} unused letters'.format(len([c for c in cat(cat(l) for l in g0) if c == '.'])))\n",
-    "        print('Longest makeable word: {}, {} ({})'.format(lwm, len(lwm), lwms))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 24,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "\n",
-      "wordsearch04.txt\n",
-      "58 words present\n",
-      "Longest word present: fortification, 13 letters (['fortification'])\n",
-      "Longest word absent: justification, 13 letters (['justification'])\n",
-      "57 unused letters\n",
-      "Longest makeable word: despairing, 10 (['despairing'])\n"
-     ]
-    }
-   ],
-   "source": [
-    "do_wordsearch_tasks('wordsearch04.txt', show_anyway=True)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 25,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "\n",
-      "wordsearch08.txt\n",
-      "62 words present\n",
-      "Longest word present: compassionately, 15 letters (['compassionately'])\n",
-      "Longest word absent: retrospectives, 14 letters (['retrospectives'])\n",
-      "65 unused letters\n",
-      "Longest makeable word: vacationing, 11 (['vacationing'])\n"
-     ]
-    }
-   ],
-   "source": [
-    "do_wordsearch_tasks('wordsearch08.txt')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 26,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "\n",
-      "wordsearch08.txt\n",
-      "62 words present\n",
-      "Longest word present: compassionately, 15 letters (['compassionately'])\n",
-      "Longest word absent: retrospectives, 14 letters (['retrospectives'])\n",
-      "65 unused letters\n",
-      "Longest makeable word: vacationing, 11 (['vacationing'])\n",
-      "\n",
-      "wordsearch17.txt\n",
-      "58 words present\n",
-      "Longest word present: complementing, 13 letters (['complementing'])\n",
-      "Longest word absent: upholstering, 12 letters (['domestically', 'upholstering'])\n",
-      "56 unused letters\n",
-      "Longest makeable word: plunderer, 9 (['plunderer'])\n",
-      "\n",
-      "wordsearch32.txt\n",
-      "60 words present\n",
-      "Longest word present: reciprocating, 13 letters (['reciprocating'])\n",
-      "Longest word absent: parenthesise, 12 letters (['collectibles', 'frontrunners', 'parenthesise'])\n",
-      "65 unused letters\n",
-      "Longest makeable word: sultanas, 8 (['sultanas'])\n",
-      "\n",
-      "wordsearch52.txt\n",
-      "51 words present\n",
-      "Longest word present: prefabricated, 13 letters (['prefabricated'])\n",
-      "Longest word absent: catastrophic, 12 letters (['capitalistic', 'catastrophic'])\n",
-      "86 unused letters\n",
-      "Longest makeable word: unimpressed, 11 (['bloodstream', 'brainstorms', 'reassembles', 'rhapsodises', 'synergistic', 'unimpressed'])\n",
-      "\n",
-      "wordsearch62.txt\n",
-      "58 words present\n",
-      "Longest word present: diametrically, 13 letters (['diametrically'])\n",
-      "Longest word absent: streetlights, 12 letters (['harmonically', 'skyrocketing', 'streetlights'])\n",
-      "59 unused letters\n",
-      "Longest makeable word: tabernacle, 10 (['falterings', 'tabernacle'])\n",
-      "\n",
-      "wordsearch76.txt\n",
-      "60 words present\n",
-      "Longest word present: bloodthirstier, 14 letters (['bloodthirstier'])\n",
-      "Longest word absent: incriminating, 13 letters (['incriminating'])\n",
-      "59 unused letters\n",
-      "Longest makeable word: stubbornly, 10 (['leafletted', 'stubbornly'])\n",
-      "\n",
-      "wordsearch94.txt\n",
-      "59 words present\n",
-      "Longest word present: unforgettable, 13 letters (['unforgettable'])\n",
-      "Longest word absent: accommodated, 12 letters (['accommodated'])\n",
-      "69 unused letters\n",
-      "Longest makeable word: respectably, 11 (['predictions', 'respectably'])\n"
-     ]
-    }
-   ],
-   "source": [
-    "for fn in sorted(os.listdir()):\n",
-    "    if re.match('wordsearch\\d\\d\\.txt', fn):\n",
-    "        do_wordsearch_tasks(fn)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 27,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "absolved (True, 16, 2, <Direction.right: 2>)\n",
-      "adorable (True, 11, 4, <Direction.right: 2>)\n",
-      "aeon (True, 11, 4, <Direction.down: 4>)\n",
-      "alias (True, 15, 15, <Direction.left: 1>)\n",
-      "ancestor (False, 0, 0, <Direction.left: 1>)\n",
-      "baritone (False, 0, 0, <Direction.left: 1>)\n",
-      "bemusing (False, 0, 0, <Direction.left: 1>)\n",
-      "blonds (False, 0, 0, <Direction.left: 1>)\n",
-      "bran (True, 1, 9, <Direction.left: 1>)\n",
-      "calcite (True, 19, 9, <Direction.upright: 6>)\n",
-      "candor (True, 17, 12, <Direction.right: 2>)\n",
-      "conciseness (False, 0, 0, <Direction.left: 1>)\n",
-      "consequent (False, 0, 0, <Direction.left: 1>)\n",
-      "cuddle (False, 0, 0, <Direction.left: 1>)\n",
-      "damming (True, 17, 2, <Direction.right: 2>)\n",
-      "dashboards (False, 0, 0, <Direction.left: 1>)\n",
-      "despairing (False, 0, 0, <Direction.left: 1>)\n",
-      "dint (False, 0, 0, <Direction.left: 1>)\n",
-      "dullard (True, 8, 2, <Direction.down: 4>)\n",
-      "dynasty (True, 3, 4, <Direction.downright: 8>)\n",
-      "employer (False, 0, 0, <Direction.left: 1>)\n",
-      "exhorts (True, 0, 8, <Direction.left: 1>)\n",
-      "feted (True, 5, 10, <Direction.right: 2>)\n",
-      "fill (True, 9, 14, <Direction.upleft: 5>)\n",
-      "flattens (True, 10, 10, <Direction.upleft: 5>)\n",
-      "foghorn (True, 10, 11, <Direction.downright: 8>)\n",
-      "fortification (True, 19, 16, <Direction.left: 1>)\n",
-      "freakish (False, 0, 0, <Direction.left: 1>)\n",
-      "frolics (True, 16, 16, <Direction.up: 3>)\n",
-      "gall (False, 0, 0, <Direction.left: 1>)\n",
-      "gees (True, 17, 0, <Direction.upright: 6>)\n",
-      "genies (True, 5, 7, <Direction.upleft: 5>)\n",
-      "gets (True, 6, 4, <Direction.upleft: 5>)\n",
-      "hastening (True, 14, 13, <Direction.left: 1>)\n",
-      "hits (True, 2, 0, <Direction.down: 4>)\n",
-      "hopelessness (False, 0, 0, <Direction.left: 1>)\n",
-      "hurlers (True, 18, 0, <Direction.right: 2>)\n",
-      "impales (False, 0, 0, <Direction.left: 1>)\n",
-      "infix (False, 0, 0, <Direction.left: 1>)\n",
-      "inflow (False, 0, 0, <Direction.left: 1>)\n",
-      "innumerable (False, 0, 0, <Direction.left: 1>)\n",
-      "intentional (False, 0, 0, <Direction.left: 1>)\n",
-      "jerkin (False, 0, 0, <Direction.left: 1>)\n",
-      "justification (False, 0, 0, <Direction.left: 1>)\n",
-      "kitty (True, 8, 15, <Direction.upleft: 5>)\n",
-      "knuckles (True, 17, 19, <Direction.up: 3>)\n",
-      "leaving (False, 0, 0, <Direction.left: 1>)\n",
-      "like (True, 3, 11, <Direction.left: 1>)\n",
-      "limitation (True, 8, 3, <Direction.right: 2>)\n",
-      "locoweeds (False, 0, 0, <Direction.left: 1>)\n",
-      "loot (True, 3, 19, <Direction.up: 3>)\n",
-      "lucking (True, 7, 10, <Direction.upleft: 5>)\n",
-      "lumps (True, 0, 17, <Direction.down: 4>)\n",
-      "mercerising (True, 15, 17, <Direction.up: 3>)\n",
-      "monickers (False, 0, 0, <Direction.left: 1>)\n",
-      "motionless (True, 13, 1, <Direction.up: 3>)\n",
-      "naturally (True, 9, 16, <Direction.up: 3>)\n",
-      "nighest (True, 15, 4, <Direction.right: 2>)\n",
-      "notion (True, 17, 18, <Direction.up: 3>)\n",
-      "ogled (True, 1, 18, <Direction.down: 4>)\n",
-      "originality (False, 0, 0, <Direction.left: 1>)\n",
-      "outings (False, 0, 0, <Direction.left: 1>)\n",
-      "pendulous (False, 0, 0, <Direction.left: 1>)\n",
-      "piled (True, 1, 10, <Direction.right: 2>)\n",
-      "pins (True, 7, 4, <Direction.upleft: 5>)\n",
-      "pithier (False, 0, 0, <Direction.left: 1>)\n",
-      "prep (True, 10, 4, <Direction.right: 2>)\n",
-      "randomness (False, 0, 0, <Direction.left: 1>)\n",
-      "rectors (False, 0, 0, <Direction.left: 1>)\n",
-      "redrew (False, 0, 0, <Direction.left: 1>)\n",
-      "reformulated (False, 0, 0, <Direction.left: 1>)\n",
-      "remoteness (False, 0, 0, <Direction.left: 1>)\n",
-      "retaking (True, 6, 0, <Direction.down: 4>)\n",
-      "rethink (False, 0, 0, <Direction.left: 1>)\n",
-      "rope (True, 9, 4, <Direction.right: 2>)\n",
-      "rubier (True, 0, 4, <Direction.downright: 8>)\n",
-      "sailors (True, 7, 15, <Direction.up: 3>)\n",
-      "scowls (False, 0, 0, <Direction.left: 1>)\n",
-      "scum (True, 16, 11, <Direction.right: 2>)\n",
-      "sepals (True, 6, 10, <Direction.upright: 6>)\n",
-      "sequencers (False, 0, 0, <Direction.left: 1>)\n",
-      "serf (False, 0, 0, <Direction.left: 1>)\n",
-      "shoaled (True, 11, 18, <Direction.up: 3>)\n",
-      "shook (False, 0, 0, <Direction.left: 1>)\n",
-      "sonic (True, 18, 18, <Direction.left: 1>)\n",
-      "spottiest (False, 0, 0, <Direction.left: 1>)\n",
-      "stag (True, 7, 8, <Direction.left: 1>)\n",
-      "stood (False, 0, 0, <Direction.left: 1>)\n",
-      "stratum (True, 2, 13, <Direction.left: 1>)\n",
-      "strong (True, 4, 19, <Direction.down: 4>)\n",
-      "studying (True, 0, 16, <Direction.left: 1>)\n",
-      "surtaxing (False, 0, 0, <Direction.left: 1>)\n",
-      "tailing (True, 13, 6, <Direction.right: 2>)\n",
-      "tears (True, 13, 3, <Direction.up: 3>)\n",
-      "teazles (True, 4, 10, <Direction.downright: 8>)\n",
-      "vans (True, 18, 8, <Direction.upright: 6>)\n",
-      "wardrobes (False, 0, 0, <Direction.left: 1>)\n",
-      "wooded (True, 12, 5, <Direction.right: 2>)\n",
-      "worsts (True, 1, 0, <Direction.downright: 8>)\n",
-      "zings (True, 10, 14, <Direction.upleft: 5>)\n"
-     ]
-    }
-   ],
-   "source": [
-    "width, height, grid, words = read_wordsearch('wordsearch04.txt')\n",
-    "for w in words:\n",
-    "    print(w, present(grid, w))"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Example for question text"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 28,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "import copy\n",
-    "grid =  [['.', '.', '.', 'p', '.', 'm', 'o', 'w', 'n', '.'], ['.', 's', 'd', 's', 'e', '.', '.', 'e', 'e', '.'], ['.', 'e', '.', 'e', 'l', 'a', 'd', '.', 'c', 'r'], ['p', 'i', '.', 'd', 't', 'i', 'r', '.', 'a', 'h'], ['r', 'z', 's', 'i', 'w', 'o', 'v', 's', 'p', 'u'], ['o', 'a', 'w', 'h', '.', 'k', 'i', 'e', 'a', 'b'], ['b', 'r', 'o', 'w', '.', 'c', '.', 'r', 'd', 'a'], ['e', 'c', 'n', 'o', 't', 'o', 'p', 's', '.', 'r'], ['d', '.', 'k', 'c', '.', 'd', '.', '.', '.', 'b'], ['.', 's', 't', 'a', 'p', 'l', 'e', '.', '.', '.']]\n",
-    "padded_grid =  [['f', 'h', 'j', 'p', 'a', 'm', 'o', 'w', 'n', 'q'], ['w', 's', 'd', 's', 'e', 'u', 'q', 'e', 'e', 'v'], ['i', 'e', 'a', 'e', 'l', 'a', 'd', 'h', 'c', 'r'], ['p', 'i', 'e', 'd', 't', 'i', 'r', 'i', 'a', 'h'], ['r', 'z', 's', 'i', 'w', 'o', 'v', 's', 'p', 'u'], ['o', 'a', 'w', 'h', 'a', 'k', 'i', 'e', 'a', 'b'], ['b', 'r', 'o', 'w', 'p', 'c', 'f', 'r', 'd', 'a'], ['e', 'c', 'n', 'o', 't', 'o', 'p', 's', 's', 'r'], ['d', 'i', 'k', 'c', 'h', 'd', 'n', 'p', 'n', 'b'], ['b', 's', 't', 'a', 'p', 'l', 'e', 'o', 'k', 'r']]\n",
-    "present_words =  ['probed', 'staple', 'rioted', 'cowhides', 'tops', 'knows', 'lived', 'rhubarb', 'crazies', 'dock', 'apace', 'mown', 'pears', 'wide']\n",
-    "decoy_words =  ['fickler', 'adapting', 'chump', 'foaming', 'molested', 'carnal', 'crumbled', 'guts', 'minuend', 'bombing', 'winced', 'coccyxes', 'solaria', 'shinier', 'cackles']"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 29,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'fickler, adapting, chump, foaming, molested, carnal, crumbled, guts, minuend, bombing, winced, coccyxes, solaria, shinier, cackles'"
-      ]
-     },
-     "execution_count": 29,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "', '.join(decoy_words)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 30,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'adapting, apace, bombing, cackles, carnal, chump, coccyxes, cowhides, crazies, crumbled, dock, fickler, foaming, guts, knows, lived, minuend, molested, mown, pears, probed, rhubarb, rioted, shinier, solaria, staple, tops, wide, winced'"
-      ]
-     },
-     "execution_count": 30,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "', '.join(sorted(present_words + decoy_words))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 31,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "probed 3 0 6 Direction.down [(3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0)]\n",
-      "staple 9 1 6 Direction.right [(9, 1), (9, 2), (9, 3), (9, 4), (9, 5), (9, 6)]\n",
-      "rioted 6 7 6 Direction.upleft [(6, 7), (5, 6), (4, 5), (3, 4), (2, 3), (1, 2)]\n",
-      "cowhides 8 3 8 Direction.up [(8, 3), (7, 3), (6, 3), (5, 3), (4, 3), (3, 3), (2, 3), (1, 3)]\n",
-      "tops 7 4 4 Direction.right [(7, 4), (7, 5), (7, 6), (7, 7)]\n",
-      "knows 8 2 5 Direction.up [(8, 2), (7, 2), (6, 2), (5, 2), (4, 2)]\n",
-      "lived 2 4 5 Direction.downright [(2, 4), (3, 5), (4, 6), (5, 7), (6, 8)]\n",
-      "rhubarb 2 9 7 Direction.down [(2, 9), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9)]\n",
-      "crazies 7 1 7 Direction.up [(7, 1), (6, 1), (5, 1), (4, 1), (3, 1), (2, 1), (1, 1)]\n",
-      "dock 8 5 4 Direction.up [(8, 5), (7, 5), (6, 5), (5, 5)]\n",
-      "apace 5 8 5 Direction.up [(5, 8), (4, 8), (3, 8), (2, 8), (1, 8)]\n",
-      "mown 0 5 4 Direction.right [(0, 5), (0, 6), (0, 7), (0, 8)]\n",
-      "pears 0 3 5 Direction.downright [(0, 3), (1, 4), (2, 5), (3, 6), (4, 7)]\n",
-      "wide 4 4 4 Direction.upright [(4, 4), (3, 5), (2, 6), (1, 7)]\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "[(7, 5), (2, 3), (3, 5)]"
-      ]
-     },
-     "execution_count": 31,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "cts = collections.Counter()\n",
-    "for w in present_words:\n",
-    "    _, r, c, d = present(grid, w)\n",
-    "    inds = indices(grid, r, c, len(w), d)\n",
-    "    for i in inds:\n",
-    "        cts[i] += 1\n",
-    "    print(w, r, c, len(w), d, inds)\n",
-    "[i for i in cts if cts[i] > 1]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 32,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "\n",
-      "example-wordsearch.txt\n",
-      "14 words present\n",
-      "Longest word present: cowhides, 8 letters (['cowhides'])\n",
-      "Longest word absent: molested, 8 letters (['adapting', 'coccyxes', 'crumbled', 'molested'])\n",
-      "27 unused letters\n",
-      "Longest makeable word: shinier, 7 (['shinier'])\n"
-     ]
-    }
-   ],
-   "source": [
-    "do_wordsearch_tasks('example-wordsearch.txt', show_anyway=True)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 33,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "..........\n",
-      "..........\n",
-      "....l.....\n",
-      ".....i....\n",
-      "......v...\n",
-      ".......e..\n",
-      "........d.\n",
-      "..........\n",
-      "..........\n",
-      "..........\n"
-     ]
-    }
-   ],
-   "source": [
-    "g = empty_grid(10, 10)\n",
-    "set_grid(g, 2, 4, Direction.downright, 'lived')\n",
-    "print(show_grid(g))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 34,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "..........\n",
-      ".......e..\n",
-      "....l.d...\n",
-      ".....i....\n",
-      "....w.v...\n",
-      ".......e..\n",
-      "........d.\n",
-      "..........\n",
-      "..........\n",
-      ".staple...\n"
-     ]
-    }
-   ],
-   "source": [
-    "g = empty_grid(10, 10)\n",
-    "set_grid(g, 2, 4, Direction.downright, 'lived')\n",
-    "set_grid(g, 4, 4, Direction.upright, 'wide')\n",
-    "set_grid(g, 9, 1, Direction.right, 'staple')\n",
-    "print(show_grid(g))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 35,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "..........\n",
-      "...s......\n",
-      "...e......\n",
-      "...d......\n",
-      "...i......\n",
-      "...h......\n",
-      "...w......\n",
-      "...o......\n",
-      "...c......\n",
-      "..........\n"
-     ]
-    }
-   ],
-   "source": [
-    "g = empty_grid(10, 10)\n",
-    "set_grid(g, 8, 3, Direction.up, 'cowhides')\n",
-    "print(show_grid(g))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 36,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "..........\n",
-      "..........\n",
-      "..........\n",
-      "..........\n",
-      "..........\n",
-      "..........\n",
-      "brow......\n",
-      "..........\n",
-      "..........\n",
-      "..........\n"
-     ]
-    }
-   ],
-   "source": [
-    "# Example of word in grid that is English but isn't in the words listed in the puzzle.\n",
-    "g = empty_grid(10, 10)\n",
-    "set_grid(g, 6, 0, Direction.right, 'brow')\n",
-    "print(show_grid(g))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 42,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "fhj.a....q\n",
-      "w....uq..v\n",
-      "i.a....h..\n",
-      "..e....i..\n",
-      "..........\n",
-      "....a.....\n",
-      "....p.f...\n",
-      "........s.\n",
-      ".i..h.npn.\n",
-      "b......okr\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "'aaabeffhhhiiijknnoppqqrsuvw'"
-      ]
-     },
-     "execution_count": 42,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "unused_grid = copy.deepcopy(padded_grid)\n",
-    "for w in present_words:\n",
-    "    _, r, c, d = present(grid, w)\n",
-    "    set_grid(unused_grid, r, c, d, '.' * len(w))\n",
-    "print(show_grid(unused_grid))\n",
-    "cat(sorted(c for l in unused_grid for c in l if c in string.ascii_letters))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.5.2+"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 1
-}