--!name Hangman
--!icon puzzle
--!category Puzzles
local ad="!$%&()+,-0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnpqrstuvwxyz|"local function z(g)return ad:sub(g+1,g+1)end local ak,af,ac,ai,S,ae=26,27,28,31,32,33 local J="#Animals:elephant,giraffe,kangaroo,penguin,dolphin,tiger,zebra,rabbit,squirrel,hamster,turtle,octopus,butterfly,crocodile,gorilla,cheetah,panda,koala,camel,donkey,beaver,hedgehog,raccoon,flamingo,ostrich,parrot,peacock,owl,eagle,falcon,salmon,shark,whale,jellyfish,lobster,spider,ladybug,grasshopper,frog,lizard,chameleon,rhinoceros,hippopotamus,leopard,wolf,fox,deer,moose,buffalo,lion,monkey,sheep,goat,horse,chicken,duck,goose,mouse,badger,otter,walrus,seal,polar bear,sea horse,guinea pig,starfish,woodpecker,caterpillar,reindeer,llama,puppy,kitten,alligator,porcupine,armadillo#Food:pizza,pancake,spaghetti,sandwich,hamburger,cheese,chocolate,popcorn,pretzel,cookie,muffin,waffle,omelette,noodles,lasagna,burrito,taco,sushi,salad,soup,bread,butter,yogurt,cereal,banana,strawberry,pineapple,watermelon,blueberry,apple,orange,grape,lemon,mango,peach,cherry,carrot,broccoli,potato,tomato,cucumber,pumpkin,mushroom,onion,garlic,ice cream,hot dog,french fries,peanut butter,apple pie,cupcake,doughnut,meatball,honey,rice,toast,cauliflower,avocado,coconut,raspberry,milkshake,cinnamon roll,scrambled eggs#Countries:canada,mexico,brazil,argentina,chile,peru,colombia,france,germany,italy,spain,portugal,ireland,norway,sweden,finland,denmark,iceland,poland,greece,turkey,egypt,morocco,kenya,nigeria,ethiopia,south africa,india,china,japan,south korea,thailand,vietnam,indonesia,philippines,australia,new zealand,ukraine,switzerland,austria,netherlands,belgium,jamaica,cuba,madagascar,nepal,mongolia,venezuela,singapore,malaysia,croatia,hungary,tanzania#Sports:soccer,football,basketball,baseball,tennis,golf,hockey,volleyball,swimming,cycling,skiing,snowboarding,surfing,skateboarding,gymnastics,badminton,cricket,rugby,archery,bowling,karate,judo,fencing,rowing,sailing,diving,rock climbing,marathon,table tennis,ice skating,water polo,lacrosse,softball,triathlon,curling,canoeing,kayaking,snooker,horse riding,handball,figure skating,long jump,high jump,pole vault,relay race,weightlifting,taekwondo#Around the house:table,chair,sofa,pillow,blanket,lamp,mirror,curtain,carpet,bookshelf,refrigerator,oven,toaster,kettle,microwave,dishwasher,washing machine,vacuum cleaner,broom,bucket,sponge,towel,toothbrush,toothpaste,soap,shampoo,bathtub,shower,cupboard,drawer,wardrobe,clock,telephone,television,radio,computer,doorbell,window,staircase,fireplace,frying pan,teapot,spoon,fork,plate,bowl,umbrella,candle,alarm clock,laundry basket,ironing board,coat hanger,light bulb,doormat,bookcase,cushion#Nature:mountain,volcano,waterfall,river,ocean,forest,jungle,desert,island,glacier,canyon,valley,meadow,cave,beach,lake,pond,rainbow,thunder,lightning,tornado,hurricane,snowflake,sunshine,cloud,breeze,blizzard,sunflower,daisy,tulip,rose,oak tree,pine cone,acorn,moss,fern,cactus,coral reef,seashell,pebble,boulder,moonlight,sunrise,sunset,waves,puddle,dewdrop,northern lights,icicle,willow,bamboo,dandelion,hillside#Jobs:teacher,doctor,nurse,farmer,baker,chef,pilot,firefighter,police officer,astronaut,scientist,engineer,architect,carpenter,plumber,electrician,mechanic,dentist,veterinarian,librarian,journalist,photographer,musician,painter,sculptor,gardener,florist,tailor,barber,lifeguard,zookeeper,mail carrier,cashier,waiter,judge,lawyer,banker,accountant,programmer,designer,actor,dancer,singer,author,poet,sailor,fisherman,shepherd,beekeeper,magician,clown,detective,optician#Clothing:jacket,sweater,hoodie,blouse,skirt,dress,jeans,trousers,shorts,pajamas,raincoat,overcoat,scarf,gloves,mittens,beanie,baseball cap,sun hat,sneakers,sandals,slippers,boots,socks,necktie,bow tie,belt,apron,uniform,swimsuit,cardigan,vest,poncho,overalls,tuxedo,kimono,rain boots,flip flops,earmuffs,bathrobe,leggings,sunglasses,wristwatch,bobble hat#Getting around:bicycle,motorcycle,scooter,skateboard,car,bus,truck,tractor,ambulance,fire engine,police car,taxi,train,tram,subway,helicopter,airplane,rocket,hot air balloon,sailboat,canoe,kayak,submarine,ferry,yacht,cruise ship,speedboat,limousine,van,camper van,bulldozer,excavator,forklift,cable car,monorail,spaceship,glider,unicycle,tricycle,steam train,school bus,golf cart,snowmobile,sled,wagon,carriage,rowboat#Music:piano,guitar,violin,cello,drums,trumpet,trombone,saxophone,clarinet,flute,harp,banjo,ukulele,accordion,harmonica,xylophone,tambourine,triangle,bagpipes,double bass,french horn,tuba,oboe,bassoon,recorder,maracas,cymbals,bongo drums,organ,synthesizer,mandolin,glockenspiel,castanets,didgeridoo,piccolo,electric guitar,orchestra,choir,lullaby,melody#At school:pencil,eraser,notebook,backpack,ruler,crayon,marker,scissors,glue stick,calculator,chalkboard,whiteboard,classroom,homework,library,playground,lunchbox,textbook,dictionary,globe,highlighter,pencil case,paper clip,stapler,recess,spelling test,science lab,principal,timetable,exam,lesson,alphabet,geography,history,mathematics,field trip,school bell,report card#Space:planet,galaxy,comet,asteroid,meteor,nebula,telescope,satellite,moon,star,orbit,gravity,eclipse,constellation,milky way,black hole,solar system,space station,mars,jupiter,saturn,venus,mercury,neptune,pluto,launch pad,crater,shooting star,sunspot,cosmos,universe,spacesuit,moon landing#Toys and games:puzzle,kite,yo yo,teddy bear,doll,robot,marbles,building blocks,jigsaw,board game,chess,checkers,dominoes,playing cards,dice,balloon,jump rope,spinning top,rocking horse,toy train,rubber duck,sandcastle,bubbles,puppet,kaleidoscope,trampoline,swing,slide,seesaw,roller skates,paper plane,dollhouse,hide and seek,treasure hunt,musical chairs"local aj="........./........./NOPQRSTUV/WXYZ[]^_`/...a.bc../dddefdddd"local u,v={},0 for aw,p,W in J:gmatch("#([^:]+):()[^#]*()")do local j=1 for T in J:sub(p,W-1):gmatch(",")do j=j+1 end u[#u+1]={name=aw,s=p,e=W-1,n=j,lo=v}v=v+j end local function ap(h,k)while k>0 do h,k=k,h%k end return h end local function ab(j)local p=j*5//8+1 while ap(p,j)~=1 do p=p+1 end return p end local function aB(g)for f,a in ipairs(u)do if g<a.lo+a.n then local N=g-a.lo for P in J:sub(a.s,a.e):gmatch("[^,]+")do if N==0 then return P,f end N=N-1 end end end end local Q,ag={9,7,5},{"Easy","Normal","Hard"}local ah={1,3,5,7,9,8,6,4,2}local R={"ABCDEFGHI","JKLMNOPQR","STUVWXYZ?"}local b={played=0,won=0,streak=0,best=0,perfect=0,e=0,n=0,h=0}local e={diff=2,cat=0,off=0,seq=0}local d=nil local s,l,r,E="game",1,nil,false local x,A=1,1 local I={"played","won","streak","best","perfect","e","n","h"}local function H()local c={"G1"}for T,f in ipairs(I)do c[#c+1]=b[f]end c[#c+1]=e.diff c[#c+1]=e.cat c[#c+1]=e.off c[#c+1]=e.seq if d then c[#c+1]=d.i c[#c+1]=d.lives c[#c+1]=d.tried c[#c+1]=d.hints end snail.save(table.concat(c,";"))end local function Z(g,au,az,as)local P,f=aB(g)d={i=g,w=P,k=f,lives=au,tried=az or"",hints=as or""}end local function av()local p=snail.load()if type(p)~="string"or p:sub(1,3)~="G1;"then return end local n={}for aA in(p..";"):gmatch("([^;]*);")do n[#n+1]=aA end for g,f in ipairs(I)do b[f]=tonumber(n[g+1])or 0 end local k=#I+1 e.diff=math.min(3,math.max(1,tonumber(n[k+1])or 2))e.cat=tonumber(n[k+2])or 0 if e.cat>#u then e.cat=0 end e.off,e.seq=tonumber(n[k+3])or 0,tonumber(n[k+4])or 0 local g=tonumber(n[k+5])if g and g>=0 and g<v then Z(g,tonumber(n[k+6])or 7,n[k+7]or"",n[k+8]or"")end end local function F(a)return d.tried:find(a,1,true)or d.hints:find(a,1,true)end local function y()local j=#d.hints for a in d.tried:gmatch(".")do if not d.w:find(a,1,true)then j=j+1 end end return j end local function ay()for a in d.w:gmatch("%a")do if not F(a)then return false end end return true end local function C()if ay()then return"won"end if y()>=d.lives then return"lost"end end local function G()local g if e.cat==0 then g=(e.off+e.seq*ab(v))%v else local a=u[e.cat]g=a.lo+(e.off+e.seq*ab(a.n))%a.n end e.seq=e.seq+1 Z(g,Q[e.diff])r,E,x,A=nil,false,1,1 s="game"H()end local function L(i)b.played=b.played+1 if i=="won"then b.won=b.won+1 b.streak=b.streak+1 if b.streak>b.best then b.best=b.streak end if y()==0 then b.perfect=b.perfect+1 end if d.lives==9 then b.e=b.e+1 elseif d.lives==5 then b.h=b.h+1 else b.n=b.n+1 end else b.streak=0 end end local function aq(a)if F(a)or d.tried:find(a,1,true)then r="Already tried "..a:upper();return end d.tried=d.tried..a if not d.w:find(a,1,true)then E=true r="No "..a:upper().." - pop!"else local j=0 for T in d.w:gmatch(a)do j=j+1 end r=j==1 and("There is one "..a:upper())or("There are "..j.." "..a:upper().."s")end local i=C()if i then L(i);r=nil end H()end local function ar()if d.lives-y()<=1 then r="Not enough balloons for a hint";return end local o={}for a in d.w:gmatch("%a")do if not F(a)and not o[a]then o[#o+1]=a;o[a]=true end end local a=o[math.random(#o)]d.hints=d.hints..a E=true r="Hint: "..a:upper()..", for one balloon"local i=C()if i then L(i);r=nil end H()end local function Y()local c={}local _=not d or C()c[#c+1]={_ and"Next word"or"Continue","play"}if not _ and(#d.tried>0 or#d.hints>0)then c[#c+1]={"Skip this word (counts as a loss)","skip"}end c[#c+1]={"Category: "..(e.cat==0 and"Any"or u[e.cat].name),"cat"}c[#c+1]={"Balloons: "..Q[e.diff].." ("..ag[e.diff]..")","diff"}c[#c+1]={"Statistics","stats"}c[#c+1]={"How to play","help"}return c end local function U(h,V)if h=="cat"then e.cat=(e.cat+V)%(#u+1)elseif h=="diff"then e.diff=(e.diff-1+V)%3+1 end H()end function key(f)if s=="menu"then local q=Y()if l>#q then l=#q end local h=q[l][2]if f=="up"then l=(l-2)%#q+1 elseif f=="down"then l=l%#q+1 elseif(f=="left"or f=="right")and(h=="cat"or h=="diff")then U(h,f=="left"and-1 or 1)elseif f=="ok"then if h=="play"then if not d or C()then G()else s="game"end elseif h=="skip"then L("lost");G()elseif h=="cat"or h=="diff"then U(h,1)else s=h end end return end if s~="game"then if f=="top"or f=="ok"then s="menu"end return end r,E=nil,false if f=="top"then s,l="menu",1;return end if C()then if f=="ok"then G()end return end if f=="left"then x=(x-2)%9+1 elseif f=="right"then x=x%9+1 elseif f=="up"then A=(A-2)%3+1 elseif f=="down"then A=A%3+1 elseif f=="ok"then local a=R[A]:sub(x,x)if a=="?"then ar()else aq(a:lower())end end end local function aC(al)local c={}for a in d.w:gmatch(".")do if a==" "then c[#c+1]=" "elseif al or F(a)then c[#c+1]=a:upper()else c[#c+1]="_"end end return table.concat(c,"  ")end local function am(i)local m={}for ax in aj:gmatch("[^/]+")do local w={}for a in ax:gmatch(".")do w[#w+1]=a end m[#m+1]=w end local X=9-d.lives+y()for a=1,9 do local t=a%2==1 and 2 or 1 local aa=ah[a]if aa>X then m[t][a]=z(ac+a%3)if t==1 then m[2][a]=z(S)end elseif aa==X and E then m[t][a]=z(ai)if t==1 then m[2][a]=z(S)end end end local o=d.lives-y()local ao=i=="won"and 4 or(i=="lost"and 3 or(y()==0 and 0 or(o*2>d.lives and 1 or 2)))m[5][5]=z(ae+ao)for t=1,6 do m[t]=table.concat(m[t])end if not i then for t=1,3 do local w={}for D=1,9 do local a=R[t]:sub(D,D)local M=D==x and t==A if a=="?"then w[D]=M and z(af)or"{?}"elseif F(a:lower())then w[D]=M and z(ak)or"."else w[D]=M and z(a:byte()-65)or("{"..a.."}")end end m[#m+1]=table.concat(w)end end return table.concat(m,"/")end local function an()local i=C()local o=d.lives-y()snail.title("Hangman")snail.center(true)local K=u[d.k].name if i=="won"then snail.status((y()==0 and"Perfect! "or"Solved! ").."Win streak "..b.streak)elseif i=="lost"then snail.status("Out of balloons! The answer:")else snail.status(r or(K.." - "..o..(o==1 and" balloon left"or" balloons left")))end snail.text(aC(i~=nil))local B={}for a in d.tried:gmatch(".")do if not d.w:find(a,1,true)then B[#B+1]=a:upper()end end if i then snail.small("Category: "..K)elseif#B>0 then snail.small("Missed: "..table.concat(B," "))else snail.small("Category: "..K)end snail.board(am(i))if i then snail.gap()snail.text(#B>0 and("Missed: "..table.concat(B," "))or"No wrong letters")if#d.hints>0 then snail.text("Hints: "..#d.hints)end local O=b.played>0 and(b.won*100//b.played)or 0 snail.text("Solved "..b.won.." of "..b.played.." ("..O.."%)")snail.text("Win streak "..b.streak..", best "..b.best)snail.hint("BACK options OK next word")else snail.hint("BACK options OK guess L/R move UP/DN move")end end function draw()if s=="game"then return an()end if s=="menu"then snail.title("Hangman")local q=Y()if l>#q then l=#q end for g,at in ipairs(q)do snail.row(at[1],g==l)end snail.gap()snail.small("Win streak "..b.streak..", best "..b.best..".")snail.small("Category and balloons apply from the next word.")local h=q[l][2]if h=="cat"or h=="diff"then snail.hint("BACK leave OK change L/R change UP/DN move")else snail.hint("BACK leave OK choose UP/DN move")end return end if s=="stats"then snail.title("Statistics")local O=b.played>0 and(b.won*100//b.played)or 0 snail.text("Words played: "..b.played..", solved "..b.won.." ("..O.."%)")snail.text("Win streak: "..b.streak..", best "..b.best)snail.text("Perfect words (no misses): "..b.perfect)snail.text("Solved on Easy "..b.e..", Normal "..b.n..", Hard "..b.h)snail.gap()snail.small(v.." words and phrases in "..#u.." categories.")snail.hint("BACK back OK back")return end snail.title("How to play")snail.text("Guess the hidden word or phrase one letter at a time.")snail.text("The category is your clue. Pick letters with the arrows and OK.")snail.text("Every wrong letter pops a balloon. Solve it before the last one pops.")snail.text("The ? key shows a letter, but it costs a balloon.")snail.text("Easy gives you 9 balloons, Normal 7 and Hard 5.")snail.hint("BACK back OK back")end function start()math.randomseed(os.time())av()if e.off==0 then e.off=math.random(v)-1 end if not d then G()end end
