--!name Four Groups
--!icon puzzle
--!category Puzzles
local ap=[[
#ablue|navy te;azure3balt|C!9#D(snap!hmmy!$k)bri!7$*keys#%ano[p lo8laptop%FISH|s#>,t!\ld s!4
B!Mkf!8!<o!(to!82c6cere;waff!PPlane0ma#t@!=sat#(|Ch#/!;ec(k>que!/!xk?wn%BALL|foo7now m~ odd
D#Mt#"o!Sltz r!La!$lka|Sauc(pesto#Cvy aioli#$l!C$.![!cj!n3#3!Z #'p#}lett#?!w !W#P#N
Tre(oak elm birch[p!PGemston(ruby op;jade!%paz$*shel!O!Z nu7n!f!:co/n!L#?oft!/we#=,n!+!#r!A
P!8a!Tap(penne orzo ziti fu!vli|W~h!rra4h!f sle`fog|G!&k#`s|alpha!1ta#Dm#Glta#wSTOP|pots!%p!Xpot!$st
Bir!(rob4c!` wr!/her!m#xharp #m tuba$*necks!Htt+giraff5hirt vase%CAKE|cup?n_sh#[
#n!vk w!z l!+n denim|FIRE#zfly work pl##[n|B!M!(naan2g!0rye}ioche|Pal!Irom(lev!0radar civ#-kayak
#{pa!y!Gme oslo lima|#rpug!]x)p!{+beag#Jteeth#&mb saw z!og@|C!@!3es!Knus!#eir_rst#`|pa4ran[n had
Meta!Oir6zinc3pp)tin$*c!`!6k>too!=t!& hat|Herbs!,!v!#ym5ag!Eill#}n!L#?w6too!<r !d
Insec0a!.wasp mo!=flea|Sho(bo!2clog s<;loafer$.#2w|s#>2!=bl!{}~h/f#Ap@l sl!D_gur!E!dd
F!C#&d#9ou7alm6perch|Bon(femur!gbia ulna skull%BOARD|key,rd#Tsurf|A#Y!Xp#0ed2ckwar!(tab!:ng!\d !4
F!B#?ro!5tul!odaisy!$ppy|S!l0golf!$lo judo!hgby|S!3ped=zeb!Ytig)skunk2!7r&SUN|b#( di;!y5et
V#jleek ka+onion,rrot|G!&k!\!(zeus he!Yares apollo$*scal(f!C[p!;ano #2gon/vehicl(s!}f s!V4van!C,bin
C!Js(brie feta edam!\uda#clength|in^fo!2y!9!Kl!qpi!>|te!.idea2!'vo#,#iK|k!| kn!2knife k#*
Boa0yacht,noe2rge f#F|Colo!u#;med aft)f#Al!D#N^plum1#F$.b!Mk|news i!F#_}!)|B#Xt plus a#`|china!T!+ h<y k!|l
F!e=cow!;g!\a7!Jp|Ha0ber`fedo!Ybowl)!3lby$*ey(!|d+potato #W,mera/tre(s!Wk_rs7p!+#h
#x#U#Ha2njo organ|Ki!>en!%o!O#'sk !b+sieve#C!-$.ca!>#&ld!!s}~h_re/a#Ys!,t^ratio!\!d5cowl
Nu0pec!"almond,shew!Slnut|Currenci(y!/euro peso!hpee]bank|riv)bl!{!;ggy!<od%STONE|key!K+tomb l!D
Shap(circ+squ#Lov;cube|Music!tyl(jazz!<lk soul punk$*w:#Be #"el27tage&WATER|fa!'mel6p!xf[rk
Spic(cum4clove#Omeg[ce|S!4 sig!6leo aries lib!Yvirgo$.run|r##2!=!yk!:p/colo!u|shred!t< pl!L sc!Mm
Reptil(gecko iguana3b!Ypyth!mCoa0p#4#7norak blaz)poncho$.raise|g#E#b!Qg1ild&SNOW!,ll[n fl#@drift
D#/er0!3f+sundae mous!5fu!7|Sea=wha+squid!T#4 !wl$.#ueye!X!ji dough%BIRD|!by#Ts!N j!f
Pizza!%pp:ham olive pepp)sa#+i|Mythic;cr~ur(elf#9o!'ogr!Eragon$*!|dl(p!+,ctus_r syr!*e#}b#X0knows he;h#Lmussel
Car?r0w!Jl}#@clut^bonnet$4a!Sll!Rcash,rd photo!gck!RD!)l!_i!6prid#1!&d env!_loth&COW!Hy!1!'girl hide
Tropic;f#Am#"o mel6guava?paya#^t)keys|tab!Tift ent)escape|Anim;group#;m(pri#3murd)sch!z!$d/b#X0chips p@l!Tiny legal
Too!Osaw dri!'#Be1isel|P!nrZfl!j!<ld bluff ant#.brew|!W3ffee!1)#W#wLISTEN|!ve!.enli!?tins!0inlets
#{cairo delhi!%kyo dublin|Bo!9#D(ludo !yk clu5orry%FLY|#K)#2g6horse[y%MAN|post2t ir6snow
Bir!(owl hawk swan_nch#cwe#=|!@ce!$und#Cm!%n$.tie|kn!2la!Fribb6apron#}v#jleak b~[ze!1en
#rcorgi husky3lli5et!-|D#Mjiv5#5a disco twist|Ways!%3ok|b#@fry!]il!G!8/f!C|!}pet3dex!iy6sh#6n
Riv#?ni+thame!Xe!+ rh!+]pie|#!+!lk pec!"mud&TOOTH|br!j?s{ache!;!c#kMOON|spo6tun!Eune c!xn
G!&k#`s|sigma!#eta k#!a omega|W~h!rsle`mi!?ga+h!f|NATO alphab!Rbravo hot!0kilo zulu%L#]mo6!Qsh sp!2h!)
#nvelv`tweed satin3tt!mS!l0rugby h#I!_quash!]x!*$*a !Jl|sho5o8h< loaf#VS#|n!f #> p@ !4
F#Abanana1#F#Cpe#Nch#^t)bi0mou!5c!u!amodem1ip!^!3ke|mat^gold!$se1#)/relativ(dau!.m!L+gra!.!Mson
B!M!(pitta!Gll!!n#;an|Nor!5go!(th!aod4loki!Ueya|#lshoe|so+he!0l##!%ngue%POT|!W ja8![8hot
Trous#?jeans1ino!Xlacks3r!(Horned=go!~rhino bis6ibex|In!#e#gy#de7!4 #B!RS!4ts *PAN|p<a?nic?nel?ntry
Ha0cap!1anie turb!"fez|F!C|tuna,rp!;ke2ss$*legs|tab+st!z#$lay !3pod%PAPER|new!X<!S!'tissue
Herbs|m!p1ive2!_orrel#ct!D|second!Knu{hour decad!qth!`|party_t pun^d#,#sARM|ch!e sw!e#bw!eth
C!@!3(peru1i+cuba[li|Meta!Ol!) !vver1rome!gn$*a}i!7|no!5#H4sh!og#Ees%RING|@ key!%e!!ll
F#Akiwi #pd!d|GolfZbirdie eag+bogey?r|PLAY#zd!) fair saf!E!L%JACK|bla8!Qp,r union
F#(iture|sof#Gsk!t!z!1nch|Vehicl(!}!!s !Vm#9u!cToys|ki{yoyo do!'teddy#iW|w!y7#> answ)wreck
Insec0beet+locu!?aphid[ntis|Marti;ar0judo kara{k!so aikido$*caps!Htt+p!/k!| #,&BUTTER|cup!Klk nu7co!>
Compos#?ba^liszt verdi elgar|Pa!p#?mon`dali!\ya klimt$*b!b(knif5ka{f!"oar/drinks|beg4s!l7ca+s!Wl
Asi#qchina jap!"!Iia#:pal|#ared|ruby1#F}i8w!+$*a f##|clo8di!Fcliff!$ker%SHIP|war spa!F!Qg!Ui!s
Orga!6liv)lung#<dne!_pleen|Seaf!{|![b prawn c#+ oys!-!^pin|top yarn#8b w!Jl&DEAD|l!+ lo8p!"!s
Sea[mma!Owha+s#~|Coffee #)#?lat{moch#Gcaf!U#!!qki!chabit!!cket,n !Jls/#\c!`d wren^bowl!gtle
Sho(brogue mu+pump#8!7|Ki!>!/#!li#Mov!/kett+fri!7!Kx!rG!9en!%o!Or#@ho5pad5h@s%TAIL|pony!;g38ox
Bodie#Qwa!-|l#6!$nd2y lago!mCh#/Zfork p4g#5it,st#Jbulbs|#+p oni6tul!ogarlic|Beg4#y!}p`b!j!0va#*y !Vmp
Y!@g=calf!<;cub#<d|C!Js(pane)ricotta!tilt6gouda$9b!ut|bubb+pipe tyr!Eam&N#]mare,p fa!'gown
F#Ap@#N^apric!2quince|Sp##Zorbit3m`nebula quasar$*a crust#%e}!) @th!;zza%NUT|dough1e!?hazel3co
Gems|garn`#5)onyx!1ryl|M!@tai!6fuji etn#Gnali eiger%BAG|h< s<!1!"w!I/TOM!Httom custom atom!tomp
Spiri0g4rum s#@m!)|C!9#D(#'!?euchre h@ts!hmmy$.launch|r#I7h!oattack,!&r|S!@d like=d@2re hoar!5links
Rainbow3lo!u|or#"e !Iigo #H`yel!B#R c#E!xm|desk1alk!hl)glob!qc!8|spe!'vo{ne7hadow%BELL|door2r d!L3w
Offic5uppli(fold)#feras)b!Ier$*str:pupp`ki{harp!icket&SWEET|h@t3rn}!) m~#}do-re-mi not(doe!i!_ew far
Bea!6kidney}oad!hnn)p!po#R_repl##|log3;gra{p!nr$.fi!Pn!f!:xes claim#$!lt|S!4t *a f!e a#Y#%ge6henna!imp3wl
Snak(cob!Yvip)add)m#5a|C!@!3(ir!"iraq om!"laos$9r!*|be!'ph!A#b@s%PIPE!,g w!I #24pe##
Roy;th:c!`n!#r!A orb sceptre]!Z|fried!]iled scot^eas!-$*s!4s|!Qg sky hot!0sheriff/KING|ask>bak>jok>lik!*
K!I#Qc#6|sp!Ne,rr!2fruit #"el|Sno!nr2l!Ob!`n!;nk#Tyel!B$9#uwhe!0credits2rrel%PRINT|foot_ng)th!L#:ws
Poe0k~s byr6b#(s bl#6|TennisZac!Eeu!Flove lob$9f!B|riv)lava!g#3h!Ay%MARK!Hok !V#3l< birth
V#jrad!C t#(!ocelery okra|Bath!xm!#:tow!0soap sp!Ne!izor$.br!j|tee!=#Shors5uede#wEAST|s~ !Ws ~!X!d
Isl<s|crete[lta java2li|Olymp#-s!l0!`>div>s!f>judo$.gr!d|c!Jse,rr!2nutmeg g!*er%BONE!,8w!C jaw1eek
Big,0li6puma lynx jaguar|#ag!&n|olive!K!.jad5age$*t!Nu(shoe!1!'!Qm5n#6%STICK|lip1op #Ujoy
#lship|de8m!8 hu!'keel|D#Mm#5o jig !&l!]lero|Kno0!&f#Cnny hit^slip&JELLY|f!C!1!"roll2by
Grai!6wh~ oats2rley!Kll!RWeapo!6s#> sp@ lan!Fax#.#Lwoven!,sk`web!hg!:le#iB|#+b3mb!#!L debt
Swee0toffee fu!7 noug!~pral!+|B!`n!C!Tad(t!"beige khaki sepia$*li!(p!"jar#P!;ano%WOOD|holly drift_r5<al
Moo!6tit!"europa phobos !3t!mTeas|!z!N1ai[!>#7ssam!^huff!Pc!9s feet?per!X!Ns%LINE|d!) pun^h!)3!8
Bicyc+par0pedal1a4sadd+sp!n|Roden0mou!5vo+beav)gerbil$.tune#%ano!idio eng!+ #Hin%WEAR|fo!2und)swim k#*
Win(merlo7hiraz[lbec rioja|On a!\lf3!ue|te#1!&n!!nk)ho#Jr:tre5at#( oni6circus#vAPE|grape,p!Erape?per
Faci;f~ur(nose1in1eek}ow|Casino#D(![ps keno!$k)slots$.b!B|#'st+bubb+kiss fuse%SHELL|!Z !w#O!]mb
V#jpea!1an3rn!1!RAus!Vlian=koala emu!$ssum d!*o$.t#0|j!n lie#9u!=t!D&ARM|c#Spit2nd our
Bird#Qprey|hawk#<{falc6osprey#opeopl(maya inc#7ztec celts$*locks|can;do!a#Ssafe|End #yscab nimbus os!}#$bus
Citrus f#A#pyuzu citr!mCo!8;f~ur(cove cliff !&f dun!qbook|!xm!:b+fl#=!:xi%DROP|dew t@28snow
#xsi!4 lu{bug+oboe|Desert!#:oasis,mel,ctus!Krag#.drip|tap,nd+no!5icicle%MAIL|black1a4sn!f junk
Sp!M!(jam h!Ay#Zcurd|Pira{th:parr!2#Bk cut#E?!>$.!3m|he!7 b@d!!dg`fat&BED|bug!Gom!G8t!D
Mexic!"f!{|taco#;cho salsa fajita|Mus#-!-ms|tempo!<r{largo1#)$*!x0t!&!%o!=#S#>|Lose!#e_rst#`!<r !"a#Y|bra7cat!]wl?nt
Measure#Qvolume|litre!;!.gall6quart|Fiction;detectiv(holmes!$irot[rp+morse$*!es|c#Ssofa!Gb!2![ne&CAT|walk_sh#;p,ll
W#)s!<r a!Ui!s|p;m!d1um!!ddy|C#@!*redien0flour sugar !Z!!t!-|In!#5ky|cloud3m`ki{moon#wea^oth!rpas7pat!:ps?ts
Soups|bro!=bisqu#1!Lo!Kso|Fore!?floor|moss fern fungus ivy!^!Rtab+#_#b!Vp%WORM!Hok g!B !vk!:pe
W!{w!I|#m!;ccolo_fe#R1urch|pew al!4!<n7pire%BAR|c!` s< sna8sa!b#iL|calf half yolk?lm
Exercis(squ!~lunge crun^#Bk|Primat(lemur gibbon2boon1imp$.grill|s!Wk kebab suspect#[&NEWS|pap)!Qsh!Gom !&l
Rom!"go!(juno[#tpluto$*stems|f!B)g#E!;pe #!l#.expire|milk3up6lea!5visa#sCAT|loca{vacat5cat!-,!>
S!jiZnori!Ssabi[ki!Kso$9sh!+|sun s!4!%r^sho(B#Xts 9#Lverbs|elbow#P h!)!%e&SAND|paper,st+#W wich
Fl#=l#/ #\emu#<wi rhea dodo|W!Iy w~h!rb!&z#1us7qua!'ga#Jh<l(cup door}oom?n&AIR|!lt l!+2g ![ft
Clean>th:mop}oom dust)buck!RBalletZplie jete2rre!$!p#.pop#&rk!!bb+pi!'@s|#kSHOE|glu#1nu zoo flew
Boa0pu!.junk sloop d!*hy#R !3f!Pj#0!_p!Ne c!Mm!T#F$.pr#/|#K6f!B)suit?use&LAND|m#4 l#) slide_ll
H#IyZpu8sti8rink!\al|Worn 6the#:!cs!}f1!nr3llar ![vat$9ar5ealed|de;f!d#`#<ss%TIE!Hw#Tcup zip
Afric#qkenya ghana egyp7udan|Dog3mm<s|si7tay he!0fe!>$9b!@ce!,ll1eque em!f echo#vTEN|kitt!/!k!alis!k!$!kt
In a g!9en!$nd|koi!Uog#:wt !&d]sauce|soy #!+m!p}!)$.cr!j|i!Fgarlic,n#Os%ACHE|too!=h!)28@
Fairy-ta+figur(wit^gia!.princ!Ewarf|Sew>kit|!|d+thr!)!#imb+#K!m#agrey|ash slat5m!n fl!p/meta!Oiron#-pl!)!gns!0golden
Sch!z subjec0maths mus#-#2ma latin|F!8en:zip!!ck+clasp!%ggl#.b~|h@t #Uw!*s!iin&QUARTER!,8de8m!8)final
Pe0rabbit gerbil ferr`budgi!qpi!clo8no!5f#= !Wm]chart!,r f!B s!4!Sll&FRUIT|c#@fly27a!b
Hairstyl(bob!!n}aid mull!RConst#0atio!6ori6ly!Y#2co cygnus$*#G!cship,rds!:pe!!s%SIDE|!w!Gad!1d_re
Potato d!C(mash1ips#8!7s#Ctin|Sh#4s|tig)n!ue!!!'lemon$.lo!cdo!ahorns#Ps ph!A#VW#|h!oh~ it^ink
Gymn!8ics|vault!1am flo!ar:Hal!Been|gho!?wit^spid)mummy|Sa!b leav(cos!Gck`cr#/ !sive&NUT|meg!T#0,!5ha!>
T~!D t!M0!Wc#@muff4sc!A2gel|Famous!Tips|#4!gtan#-b!@ty victory$9#'st!Pkett+!V4w!I#$fe!&&HONEY#db!1!Eew
Mili!4y!inks|maj!aensign priv!d,ptain|Indi!"d!C(korma d;samosa!gkka|At a#8dd!*|veil r!*,ke vows%WARD!,8f!ahome af!-
Scientis0darw4galileo m!s!0kepl!rElec!3c;uni0volt!Stt ohm amp$*fi!6sh#4!Gck`wha+diver%PROOF|wat)fir5!@d!<ol
Bedd!*#%l!B duv`quil7!Jt|Deser0saha!Ygobi mojave!#ar$9!Qsh|came!Ysmi+news!%rch&SHOW|man,!5down!Gom
Ro!2v#j!}rot?rsn!oswe#3yam|Air![ft|j`glid)blimp bi#B!qcross|road}i!7_ngers l!+#VLET#%g!]ok drop r!*
Playgr!@d|sw>slid5eesaw s<pit|G!&t:howdy hiy#7loh#7hoy]!4t|jam lem6t!Mc+!Z%FALL|wat)l< n#= down
B@s|grizzly!$lar?nda kodiak$.tap|keg!<!2ph!A[ple&WHITE!H!9!Ssh!St)out|#kBEAR|c#Sp@ !Qir prayer
Yel!Bs|lemon,nary#Zh!Ay#R#:st|!Z twig1i8s!Vw$.pay|re!.tax !Jd visit#vSEA|!ws6uns~#;u!w !wm
Magic!Tow|w< hat,pe!ibbit|K#*t!*Zk#* purl!tit^yarn$.toss#&4sa!b,b)hair%CAP|k!|#gu!'#,
Seaso!6spr>summ)autumn win!-|Percussi!m#Ug!N cymb;b!No|On a f!e!,rn !vo#9ough_eld#wITEMS|t!D!Xmi{mites emits
Bea^th:towel!!cke7pad5unhat#oEgypt|sphinx ni+mummy!%mb!^hed|sk4t@s l#=!$unds&PINE|#!+c!A#O w!{
Circus|c!Bn juggl)!Vpeze !kt$9hum|bee!Ui!7 eng!+ tune]fork|tun>g!9!/road sa!b&EAR|r>wig lob!Erum
Coi!6penny d!D nick!0cent$.fold|napk4!es[p#`|GOLDEN#ztick`goo!5ga{rule#iG|gnom#1na7ign#$ign
Party!#:c#6,nd+pinata2nn!rCut#Qbeef|sirlo4rump}isk`!Qnk$.flip#&4swi!>!!rg)page&STAR|f!C du!?l>bo!9
M!@ta4r#"(alps <es urals atlas]map|road m!I #e~|Pudd:r#,}!)#Tplum#vAND|c<+s<y}<y g<er
Fir!?aid|pl!8)sl>gauz5pl!p|Sea #\gu!'!-n puff4gannet!^tre!>|legs#9uth!!dg`rules&TEA|p!2cup2g spoon
Jobs!,k)nur!5pil!2ju!7|Draw>too!O#f![yon1alk?stel|Ligh7ourc(#+p,nd+torch!!lb|Beg4*TEN|!k!a!knis !ka!.!kder
F!8!<od|burg)pizza kebab!:co$9st!*|bee!Ssp#:tt+ray$*tips|f!*)pen!%ngue!Si!-&CROSS|#>!Gads!]w_re
In a!tab!Pha!_add+brid+stirrup!^tir|soup?in7au!F!yotto%CUP|!Z#Z#eic#vOAT!Hat3!~gloat!#roat
#lbook|sp!+3v)page !Iex|S!lts *goa!Oh#I!_occ)polo!hgby&OVER!H!93!~t!D lap|#kSOCK|clo8ro8kno8flock
Fren^#>s#8 use|cafe menu1ef2llet]pepp!rbe!'bla8g!&n1ili!^erve|dinn)not#,2!'t!D&BLOOD|h!@d2!=shed l!+
W!z3mes!Uom|s!Jp l#+#7lpaca yak#^!-Zby{pixel,che virus$.b~|#U!Zs!hg #_&MOUSE|!Vp[t ho+pad
Egypti!"go!(!Yisis osi!y anubis|#a#'te|ivory c!Mm p@l1alk$9s!Rsun j#0y ceme!.b!A&BIRD|cag5!N seed2th
A kn#='s#<t|lanc5#>!Tield#h$9![sh|wave[rket?rty,r!^ow|seeds doubt oats disc#)%BOX|po!?juk5<#`
P!8ry|puff_lo1oux !Qky]show|talk#De!Gad quiz$.ha!>|!Z pl!"plo7cheme#VER!<r a job|b#@f!e?i!.!Wch
Writ#?aust!/twa4orwe!'joyce#R,st!Pmoat!%w)keep turret$.l!s|h< @#8#= m!Ay&KEY!H!9 ho+not5t!A
Whiskered=ca7#~]#W|bra4snow s<_r!qpeel!,nana!$tato!tick)ey(#kN#]ki{bi{he#=!U#=
G!9!/#\rob4wren_n^thr!j|Kept 4the!Ui!7|milk#Zyogurt#[$9wobb!Pw!Jl!%oth!:b+!bder%NAIL|f!*)toe!#!L h#"
Play!*,r!(a!Fk>que!/ja!c#ls!N|verse1orus}i!7 !pro$*#Ko!6shirt#$mote3!~lift&LIFE!H!~gu!9 lin5tyle]]local aE=[[
|Things 
|Words before 
|Words after 
es|
er 
with 
le 
 ca
you 
|Hidden 
ts|
 ch
 ba
 co
in 
e s
on 
t s
ck 
that 
ings|
al 
and
 animals|
ing 
 pa
ear
 words|
 ma
|Kind#Q
ch 
 fi
et 
te 
 br
eat]]local aF=[[
 buan  th po toreell ds|eadingine|baternt en el  beot tritarse ns|dgeastard ta pi foth tchst ounonelowishimee dce  ro|boindhee miumbreaongls|le|flaet| wa sh frtrateas sra eggcra go bo$.sy srowor ladck|atearmail ti ru raushtenporon|okeip inte$.er|end sturssilsearoorisooloodneecarat appangace re|pi|cowhiurnordnitlamiceic e$9esselle gdrade arkambakea a we tr ne na kiightworders|ake rui0plan gra gamlasserrya deviolockele$*buttare anc( pea nut eyes of |In ahair  bla8drum |Add stormody?rnimal!!tt)1eesebir!(IGHT||Compurecord letterShade#Q alarm |Unit#Q|moon3mworld hpencil  nigh7k helmet|Silent egetabl(Rhymes *Part#Qa flu{oboeFabrics||Ancie!.lem6l!D an3un!3(Dog}ee!(|All3nta4rs venus roll|di!F|All hide |Anagram#QInstrumen0*a vehic!P plus a #>|Capit;citi(!%!#e!Uont||Sound like e;ott)walrus]]local aH={0,0,122,20,13,2,9,10,3,4,3,2}local as,aq="$%&()*+,./0123456789:;<=>?@Z[]^_`{}~","!#"local Z=""for f=33,126 do Z=Z..string.char(f)end local function av(j)return"["..j:gsub("%p","%%%0").."]"end local aK,aJ=av(aq)..".",av(as)local _={}for aV in(aE.."\n"):gmatch("(.-)\n")do _[#_+1]=aV end local function aW(D)local T,H=1,1 for B,m in ipairs(aH)do if D<m then return aF:sub(T+D*H,T+D*H+H-1)end D,T,H=D-m,T+m*H,H+1 end return""end local W local function a8(u)return W(aW((aq:find(u:sub(1,1),1,true)-1)*94+Z:find(u:sub(2),1,true)-1))end local function a7(u)return W(_[as:find(u,1,true)])end function W(j)return(j:gsub(aK,a8):gsub(aJ,a7))end local function a0(j,d)local w=1 for B=2,d do w=j:find("\n",w,true)+1 end local aN=j:find("\n",w,true)return j:sub(w,(aN or 0)-1)end local k=1 for B in ap:gmatch("\n")do k=k+1 end local function a3(d)local i={}for Q in(W(a0(ap,d)).."|"):gmatch("([^|]*)|")do i[#i+1]=Q end local y={labels={},words={}}for a=1,4 do y.labels[a]=i[a*2-1]local f=(a-1)*4 for L in i[a*2]:gmatch("%a+")do f=f+1 y.words[f]=L end end return y end local function ad(h)return(h-1)//4+1 end local aG=os.time({year=2026,month=1,day=1,hour=12})//86400 local function A()local c=os.time()if not c or c<1700000000 then return nil end local g=os.date("*t",c)return os.time({year=g.year,month=g.month,day=g.day,hour=12})//86400 end local function G(g)return(g-aG)%k+1 end local M="0123456789abcdef"local e={played=0,won=0,perfect=0,streak=0,best=0,last=0,d0=0,d1=0,d2=0,d3=0,pplay=0,pwon=0}local aa={"played","won","perfect","streak","best","last","d0","d1","d2","d3","pplay","pwon"}local z=string.rep(".",k)local o={day=0,g=nil}local s=nil local N,b,y=nil,nil,nil local p,q,x=1,1,nil local n,v,r="menu",1,1 local function J(a)return a and(a.mist>=4 or#a.found==4)end local function au(a)if not a then return""end local I,X={},{}for f,h in ipairs(a.order)do I[f]=M:sub(h,h)end for h in pairs(a.pick)do X[#X+1]=M:sub(h,h)end table.sort(X)return table.concat({a.idx,table.concat(I),a.found,a.mist,table.concat(X),table.concat(a.tried,".")},",")end local function at(j)local i={}for Q in((j or"")..","):gmatch("([^,]*),")do i[#i+1]=Q end local t=math.tointeger(tonumber(i[1]))if not t or t<1 or t>k or#i<6 then return nil end local a={idx=t,order={},found=(i[3]:gsub("[^1-4]","")),mist=math.min(4,math.tointeger(tonumber(i[4]))or 0),pick={},tried={}}for l in i[2]:gmatch(".")do a.order[#a.order+1]=M:find(l,1,true)end for l in i[5]:gmatch(".")do a.pick[M:find(l,1,true)or 1]=true end for c in i[6]:gmatch("[^.]+")do a.tried[#a.tried+1]=c end if#a.order~=16-4*#a.found then return nil end return a end local function al()local c={"F1"}for B,d in ipairs(aa)do c[#c+1]=e[d]end c[#c+1]=z c[#c+1]=o.day c[#c+1]=au(o.g)c[#c+1]=au(s)snail.save(table.concat(c,";"))end local function aZ()local j=snail.load()if type(j)~="string"or j:sub(1,3)~="F1;"then return end local i={}for Q in(j..";"):gmatch("([^;]*);")do i[#i+1]=Q end for f,d in ipairs(aa)do e[d]=math.tointeger(tonumber(i[f+1]))or 0 end local m=#aa+1 local a6=(i[m+1]or""):gsub("[^.osxp]",".")z=(a6..string.rep(".",k)):sub(1,k)o.day=math.tointeger(tonumber(i[m+2]))or 0 o.g=at(i[m+3])s=at(i[m+4])end local ar={["."]=0,o=1,x=2,s=3,p=4}local function ax(f,l)if ar[l]>ar[z:sub(f,f)]then z=z:sub(1,f-1)..l..z:sub(f+1)end end local function am()local B,m=z:gsub("[sp]","")return m end local function an()local g=A()if g and e.last>=g-1 then return e.streak end return 0 end local function aD(c)for f=#c,2,-1 do local D=math.random(f)c[f],c[D]=c[D],c[f]end end local function az(t)local a={idx=t,order={},found="",mist=0,pick={},tried={}}for f=1,16 do a.order[f]=f end aD(a.order)return a end local function ag(u,a)N,b,y=u,a,a3(a.idx)p,q,x=1,1,nil n="game"ax(a.idx,"o")al()end local function ai()local g=A()if not g then n="noclock";return end if o.day~=g or not o.g then o.day,o.g=g,az(G(g))end ag("daily",o.g)end local function aB(t)local g=A()if g and t==G(g)then return ai()end if not(s and s.idx==t and not J(s))then s=az(t)end ag("practice",s)end local S={"Shuffle","Clear","","Submit"}local aL={"Perfect! No mistakes","Solved with 1 mistake","Solved with 2 mistakes","Phew! Solved with 3 mistakes"}local aI={"Group found!","Nice one!","Good spot!"}local function K()return#b.order//4 end local function ah()local C={}for h in pairs(b.pick)do C[#C+1]=h end table.sort(C)return C end local function aw(R)local f=b.idx ax(f,R and(b.mist==0 and"p"or"s")or"x")if N=="daily"then e.played=e.played+1 if R then e.won=e.won+1 local d="d"..b.mist e[d]=e[d]+1 if b.mist==0 then e.perfect=e.perfect+1 end e.streak=e.last==o.day-1 and e.streak+1 or 1 e.last=o.day if e.streak>e.best then e.best=e.streak end else e.streak=0 end else e.pplay=e.pplay+1 if R then e.pwon=e.pwon+1 end end x=nil end local function a5()local C=ah()if#C<4 then x="Pick four words first";return end local Y=""for B,h in ipairs(C)do Y=Y..M:sub(h,h)end for B,c in ipairs(b.tried)do if c==Y then x="You tried those four already";return end end local V={0,0,0,0}for B,h in ipairs(C)do V[ad(h)]=V[ad(h)]+1 end local U,ab=0,0 for a=1,4 do if V[a]>U then U,ab=V[a],a end end if U==4 then local a1=p>K()b.found=b.found..ab local I={}for B,h in ipairs(b.order)do if ad(h)~=ab then I[#I+1]=h end end b.order,b.pick=I,{}if#b.found==4 then aw(true)else x=aI[#b.found]if a1 or p>K()then p=K()+1 end end else b.tried[#b.tried+1]=Y b.mist=b.mist+1 if b.mist>=4 then aw(false)else x=U==3 and"One away..."or"Not a group"end end al()end local function a_()local g=A()for d=1,k do local f=(b.idx+d-1)%k+1 local l=z:sub(f,f)if l~="s"and l~="p"and not(g and f==G(g))then return aB(f)end end n="menu"end local function aX(d)if J(b)then if d=="ok"and N=="practice"then a_()elseif d=="ok"or d=="top"then n,v="menu",1 end return end x=nil if d=="top"then n,v="menu",1;return end local E=K()if d=="up"then p=(p-2)%(E+1)+1 elseif d=="down"then p=p%(E+1)+1 elseif d=="left"then q=(q-2)%4+1 elseif d=="right"then q=q%4+1 elseif d=="ok"then if p<=E then local h=b.order[(p-1)*4+q]if b.pick[h]then b.pick[h]=nil elseif#ah()>=4 then x="Four picked: submit, or clear some"else b.pick[h]=true end elseif q==1 then aD(b.order)elseif q==2 then b.pick={}else a5()end if not J(b)then al()end end if p==E+1 and S[q]==""then q=d=="left"and 2 or 4 end end local function a4(a)if#a.found==4 then return"solved"end if a.mist>=4 then return"missed"end return"carry on"end local function ay()local c={}local g=A()if g then local ae="Today's puzzle #"..G(g)if o.day==g and o.g then ae=ae.." - "..a4(o.g)end c[#c+1]={ae,"daily"}else c[#c+1]={"Today's puzzle: needs the clock","noclock"}end if s and not J(s)then c[#c+1]={"Carry on: puzzle #"..s.idx,"prac"}end c[#c+1]={"All puzzles","list"}c[#c+1]={"Statistics","stats"}c[#c+1]={"How to play","help"}return c end local aM={o=" - started",x=" - missed",s=" - solved",p=" - perfect"}function key(d)if n=="game"then return aX(d)end if n=="menu"then local F=ay()if d=="up"then v=(v-2)%#F+1 elseif d=="down"then v=v%#F+1 elseif d=="ok"then local w=F[v][2]if w=="daily"then ai()elseif w=="prac"then ag("practice",s)elseif w=="list"then local g=A()r=b and b.idx or(g and G(g))or 1 n="list"else n=w end end return end if n=="list"then if d=="top"then n="menu"elseif d=="up"then r=(r-2)%k+1 elseif d=="down"then r=r%k+1 elseif d=="left"then r=math.max(1,r-10)elseif d=="right"then r=math.min(k,r+10)elseif d=="ok"then aB(r)end return end if d=="top"or d=="ok"then n="menu"end end local function ac(a)local L={}for f=1,4 do L[f]=y.words[(a-1)*4+f]:upper()end return y.labels[a]..": "..table.concat(L,", ")end local function aP()local E=K()local c,P={},{"."}for l=1,4 do P[l+1]=l==q and"v"or"."end c[1]=table.concat(P)for aj=1,E+1 do local ak={aj==p and">"or"."}for l=1,4 do if aj<=E then local h=b.order[(aj-1)*4+l]ak[l+1]="{"..(b.pick[h]and y.words[h]:upper()or y.words[h]).."}"else ak[l+1]=S[l]==""and"."or"{"..S[l].."}"end end c[#c+1]=table.concat(ak)end return table.concat(c,"/")end local function aT()local R=#b.found==4 snail.status(R and aL[b.mist+1]or"Out of mistakes. Here are the groups:")local aC={}for d=1,#b.found do local a=tonumber(b.found:sub(d,d))aC[a]=true snail.text(ac(a))end for a=1,4 do if not aC[a]then snail.text(ac(a).." (missed)")end end snail.rule()if N=="daily"then local j=an()snail.small("Streak: "..j..(j==1 and" day"or" days")..", best "..e.best..". A new puzzle tomorrow.")snail.hint("BACK OK done")else snail.small(am().." of "..k.." puzzles solved.")snail.hint("BACK OK next puzzle")end end local function aR()snail.title((N=="daily"and"Today's puzzle #"or"Puzzle #")..b.idx)if J(b)then return aT()end local m=#ah()snail.status(x or("Mistakes left: "..(4-b.mist).."   Picked "..m.." of 4"))for d=1,#b.found do snail.text(ac(tonumber(b.found:sub(d,d))))end snail.board(aP())local af if p<=K()then af=b.pick[b.order[(p-1)*4+q]]and"unpick"or"pick"else af=S[q]:lower()end snail.hint("BACK OK "..af)end local function aS()snail.title("All puzzles")local g=A()local aQ=g and G(g)local aA=13 local P=math.max(1,math.min(r-6,k-aA+1))for f=P,math.min(k,P+aA-1)do local ao=aM[z:sub(f,f)]or""if f==aQ then ao=" - today"..ao:gsub(" %- ",", ")end snail.row("Puzzle "..f..ao,f==r)end snail.small(am().." of "..k.." solved.")snail.hint("BACK back OK play L/R jump 10 UP/DN move")end local function aO(m,O)local L=O>0 and(m*12+O-1)//O or 0 return string.rep("#",L)end local function aU()snail.title("Statistics")local a2=e.played>0 and(e.won*100//e.played)or 0 snail.text("Daily puzzles: "..e.played.." played, "..e.won.." solved ("..a2.."%)")local j=an()snail.text("Streak: "..j..(j==1 and" day"or" days")..", best "..e.best)snail.text("Perfect days, no mistakes: "..e.perfect)snail.rule()snail.small("Mistakes on the days you solved it:")local O=math.max(e.d0,e.d1,e.d2,e.d3)for u=0,3 do local m=e["d"..u]snail.small(u..(u==1 and" mistake:  "or" mistakes: ")..aO(m,O).." "..m)end snail.rule()snail.small("Practice games: "..e.pplay.." played, "..e.pwon.." solved.")snail.small("Puzzles solved so far: "..am().." of "..k..".")snail.hint("BACK back OK back")end function draw()if n=="game"then return aR()end if n=="list"then return aS()end if n=="stats"then return aU()end if n=="menu"then snail.title("Four Groups")local g=A()if g then snail.status(os.date("%A, %B ")..tonumber(os.date("%d")).." - streak "..an())else snail.status("Every puzzle works any time")end local F=ay()if v>#F then v=#F end for f,aY in ipairs(F)do snail.row(aY[1],f==v)end snail.gap()snail.small(k.." puzzles. Find four groups of four words.")snail.hint("BACK leave OK choose UP/DN move")return end if n=="help"then snail.title("How to play")snail.text("Sixteen words hide four groups of four that share something.")snail.text("Arrows move the pointers. OK picks a word; picked words show in CAPITALS.")snail.text("With four picked, go down to Submit. A right group moves to the top.")snail.text("Four mistakes and the puzzle is over. One away means three of your four belong together.")snail.text("Groups go from easy to tricky; the last is often wordplay.")snail.text("Shuffle moves the words around. Clear drops your picks.")snail.hint("BACK back OK back")return end snail.title("Today's puzzle")snail.text("The daily puzzle needs the date. Connect to Wi-Fi once so the clock gets set, then come back.")snail.text("Every puzzle can still be played from All puzzles.")snail.hint("BACK back OK back")end function start()math.randomseed(os.time())aZ()local g=A()if g and not(o.day==g and J(o.g))then ai()end end
