galaxies.c 136 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485
  1. /*
  2. * galaxies.c: implementation of 'Tentai Show' from Nikoli,
  3. * also sometimes called 'Spiral Galaxies'.
  4. *
  5. * Notes:
  6. *
  7. * Grid is stored as size (2n-1), holding edges as well as spaces
  8. * (and thus vertices too, at edge intersections).
  9. *
  10. * Any dot will thus be positioned at one of our grid points,
  11. * which saves any faffing with half-of-a-square stuff.
  12. *
  13. * Edges have on/off state; obviously the actual edges of the
  14. * board are fixed to on, and everything else starts as off.
  15. *
  16. * Future solver directions:
  17. *
  18. * - Non-local version of the exclave extension? Suppose you have an
  19. * exclave with multiple potential paths back home, but all of them
  20. * go through the same tile somewhere in the middle of the path.
  21. * Then _that_ critical square can be assigned to the home dot,
  22. * even if we don't yet know the details of the path from it to
  23. * either existing region.
  24. *
  25. * - Permit non-simply-connected puzzle instances in sub-Unreasonable
  26. * mode? Even the simplest case 5x3:ubb is graded Unreasonable at
  27. * present, because we have no solution technique short of
  28. * recursion that can handle it.
  29. *
  30. * The reasoning a human uses for that puzzle is to observe that
  31. * the centre left square has to connect to the centre dot, so it
  32. * must have _some_ path back there. It could go round either side
  33. * of the dot in the way. But _whichever_ way it goes, that rules
  34. * out the left dot extending to the squares above and below it,
  35. * because if it did that, that would block _both_ routes back to
  36. * the centre.
  37. *
  38. * But the exclave-extending deduction we have at present is only
  39. * capable of extending an exclave with _one_ liberty. This has
  40. * two, so the only technique we have available is to try them one
  41. * by one via recursion.
  42. *
  43. * My vague plan to fix this would be to re-run the exclave
  44. * extension on a per-dot basis (probably after working out a
  45. * non-local version as described above): instead of trying to find
  46. * all exclaves at once, try it for one exclave at a time, or
  47. * perhaps all exclaves relating to a particular home dot H. The
  48. * point of this is that then you could spot pairs of squares with
  49. * _two_ possible dots, one of which is H, and which are opposite
  50. * to each other with respect to their other dot D (such as the
  51. * squares above/below the left dot in this example). And then you
  52. * merge those into one vertex of the connectivity graph, on the
  53. * grounds that they're either both H or both D - and _then_ you
  54. * have an exclave with only one path back home, and can make
  55. * progress.
  56. *
  57. * Bugs:
  58. *
  59. * Notable puzzle IDs:
  60. *
  61. * Nikoli's example [web site has wrong highlighting]
  62. * (at http://www.nikoli.co.jp/en/puzzles/astronomical_show/):
  63. * 5x5:eBbbMlaBbOEnf
  64. *
  65. * The 'spiral galaxies puzzles are NP-complete' paper
  66. * (at http://www.stetson.edu/~efriedma/papers/spiral.pdf):
  67. * 7x7:chpgdqqqoezdddki
  68. *
  69. * Puzzle competition pdf examples
  70. * (at http://www.puzzleratings.org/Yurekli2006puz.pdf):
  71. * 6x6:EDbaMucCohbrecEi
  72. * 10x10:beFbufEEzowDlxldibMHezBQzCdcFzjlci
  73. * 13x13:dCemIHFFkJajjgDfdbdBzdzEgjccoPOcztHjBczLDjczqktJjmpreivvNcggFi
  74. *
  75. */
  76. #include <stdio.h>
  77. #include <stdlib.h>
  78. #include <string.h>
  79. #include <assert.h>
  80. #include <ctype.h>
  81. #include <limits.h>
  82. #ifdef NO_TGMATH_H
  83. # include <math.h>
  84. #else
  85. # include <tgmath.h>
  86. #endif
  87. #include "puzzles.h"
  88. #ifdef DEBUGGING
  89. #define solvep debug
  90. #elif defined STANDALONE_SOLVER
  91. static bool solver_show_working;
  92. #define solvep(x) do { if (solver_show_working) { printf x; } } while(0)
  93. #else
  94. #define solvep(x) ((void)0)
  95. #endif
  96. #ifdef STANDALONE_PICTURE_GENERATOR
  97. /*
  98. * Dirty hack to enable the generator to construct a game ID which
  99. * solves to a specified black-and-white bitmap. We define a global
  100. * variable here which gives the desired colour of each square, and
  101. * we arrange that the grid generator never merges squares of
  102. * different colours.
  103. *
  104. * The bitmap as stored here is a simple int array (at these sizes
  105. * it isn't worth doing fiddly bit-packing). picture[y*w+x] is 1
  106. * iff the pixel at (x,y) is intended to be black.
  107. *
  108. * (It might be nice to be able to specify some pixels as
  109. * don't-care, to give the generator more leeway. But that might be
  110. * fiddly.)
  111. */
  112. static int *picture;
  113. #endif
  114. enum {
  115. COL_BACKGROUND,
  116. COL_WHITEBG,
  117. COL_BLACKBG,
  118. COL_WHITEDOT,
  119. COL_BLACKDOT,
  120. COL_GRID,
  121. COL_EDGE,
  122. COL_ARROW,
  123. COL_CURSOR,
  124. NCOLOURS
  125. };
  126. #define DIFFLIST(A) \
  127. A(NORMAL,Normal,n) \
  128. A(UNREASONABLE,Unreasonable,u)
  129. #define ENUM(upper,title,lower) DIFF_ ## upper,
  130. #define TITLE(upper,title,lower) #title,
  131. #define ENCODE(upper,title,lower) #lower
  132. #define CONFIG(upper,title,lower) ":" #title
  133. enum { DIFFLIST(ENUM)
  134. DIFF_IMPOSSIBLE, DIFF_AMBIGUOUS, DIFF_UNFINISHED, DIFF_MAX };
  135. static char const *const galaxies_diffnames[] = {
  136. DIFFLIST(TITLE) "Impossible", "Ambiguous", "Unfinished" };
  137. static char const galaxies_diffchars[] = DIFFLIST(ENCODE);
  138. #define DIFFCONFIG DIFFLIST(CONFIG)
  139. struct game_params {
  140. /* X and Y is the area of the board as seen by
  141. * the user, not the (2n+1) area the game uses. */
  142. int w, h, diff;
  143. };
  144. enum { s_tile, s_edge, s_vertex };
  145. #define F_DOT 1 /* there's a dot here */
  146. #define F_EDGE_SET 2 /* the edge is set */
  147. #define F_TILE_ASSOC 4 /* this tile is associated with a dot. */
  148. #define F_DOT_BLACK 8 /* (ui only) dot is black. */
  149. #define F_MARK 16 /* scratch flag */
  150. #define F_REACHABLE 32
  151. #define F_SCRATCH 64
  152. #define F_MULTIPLE 128
  153. #define F_DOT_HOLD 256
  154. #define F_GOOD 512
  155. typedef struct space {
  156. int x, y; /* its position */
  157. int type;
  158. unsigned int flags;
  159. int dotx, doty; /* if flags & F_TILE_ASSOC */
  160. int nassoc; /* if flags & F_DOT */
  161. } space;
  162. #define INGRID(s,x,y) ((x) >= 0 && (y) >= 0 && \
  163. (x) < (state)->sx && (y) < (state)->sy)
  164. #define INUI(s,x,y) ((x) > 0 && (y) > 0 && \
  165. (x) < ((state)->sx-1) && (y) < ((state)->sy-1))
  166. #define GRID(s,g,x,y) ((s)->g[((y)*(s)->sx)+(x)])
  167. #define SPACE(s,x,y) GRID(s,grid,x,y)
  168. struct game_state {
  169. int w, h; /* size from params */
  170. int sx, sy; /* allocated size, (2x-1)*(2y-1) */
  171. space *grid;
  172. bool completed, used_solve;
  173. int ndots;
  174. space **dots;
  175. midend *me; /* to call supersede_game_desc */
  176. int cdiff; /* difficulty of current puzzle (for status bar),
  177. or -1 if stale. */
  178. };
  179. static bool check_complete(const game_state *state, DSF *dsf, int *colours);
  180. static int solver_state_inner(game_state *state, int maxdiff, int depth);
  181. static int solver_state(game_state *state, int maxdiff);
  182. static int solver_obvious(game_state *state);
  183. static int solver_obvious_dot(game_state *state, space *dot);
  184. static space *space_opposite_dot(const game_state *state, const space *sp,
  185. const space *dot);
  186. static space *tile_opposite(const game_state *state, const space *sp);
  187. static game_state *execute_move(const game_state *state, const char *move);
  188. /* ----------------------------------------------------------
  189. * Game parameters and presets
  190. */
  191. /* make up some sensible default sizes */
  192. #define DEFAULT_PRESET 0
  193. static const game_params galaxies_presets[] = {
  194. { 7, 7, DIFF_NORMAL },
  195. { 7, 7, DIFF_UNREASONABLE },
  196. { 10, 10, DIFF_NORMAL },
  197. { 10, 10, DIFF_UNREASONABLE },
  198. { 15, 15, DIFF_NORMAL },
  199. { 15, 15, DIFF_UNREASONABLE },
  200. };
  201. static bool game_fetch_preset(int i, char **name, game_params **params)
  202. {
  203. game_params *ret;
  204. char buf[80];
  205. if (i < 0 || i >= lenof(galaxies_presets))
  206. return false;
  207. ret = snew(game_params);
  208. *ret = galaxies_presets[i]; /* structure copy */
  209. sprintf(buf, "%dx%d %s", ret->w, ret->h,
  210. galaxies_diffnames[ret->diff]);
  211. if (name) *name = dupstr(buf);
  212. *params = ret;
  213. return true;
  214. }
  215. static game_params *default_params(void)
  216. {
  217. game_params *ret;
  218. game_fetch_preset(DEFAULT_PRESET, NULL, &ret);
  219. return ret;
  220. }
  221. static void free_params(game_params *params)
  222. {
  223. sfree(params);
  224. }
  225. static game_params *dup_params(const game_params *params)
  226. {
  227. game_params *ret = snew(game_params);
  228. *ret = *params; /* structure copy */
  229. return ret;
  230. }
  231. static void decode_params(game_params *params, char const *string)
  232. {
  233. params->h = params->w = atoi(string);
  234. params->diff = DIFF_NORMAL;
  235. while (*string && isdigit((unsigned char)*string)) string++;
  236. if (*string == 'x') {
  237. string++;
  238. params->h = atoi(string);
  239. while (*string && isdigit((unsigned char)*string)) string++;
  240. }
  241. if (*string == 'd') {
  242. int i;
  243. string++;
  244. for (i = 0; i <= DIFF_UNREASONABLE; i++)
  245. if (*string == galaxies_diffchars[i])
  246. params->diff = i;
  247. if (*string) string++;
  248. }
  249. }
  250. static char *encode_params(const game_params *params, bool full)
  251. {
  252. char str[80];
  253. sprintf(str, "%dx%d", params->w, params->h);
  254. if (full)
  255. sprintf(str + strlen(str), "d%c", galaxies_diffchars[params->diff]);
  256. return dupstr(str);
  257. }
  258. static config_item *game_configure(const game_params *params)
  259. {
  260. config_item *ret;
  261. char buf[80];
  262. ret = snewn(4, config_item);
  263. ret[0].name = "Width";
  264. ret[0].type = C_STRING;
  265. sprintf(buf, "%d", params->w);
  266. ret[0].u.string.sval = dupstr(buf);
  267. ret[1].name = "Height";
  268. ret[1].type = C_STRING;
  269. sprintf(buf, "%d", params->h);
  270. ret[1].u.string.sval = dupstr(buf);
  271. ret[2].name = "Difficulty";
  272. ret[2].type = C_CHOICES;
  273. ret[2].u.choices.choicenames = DIFFCONFIG;
  274. ret[2].u.choices.selected = params->diff;
  275. ret[3].name = NULL;
  276. ret[3].type = C_END;
  277. return ret;
  278. }
  279. static game_params *custom_params(const config_item *cfg)
  280. {
  281. game_params *ret = snew(game_params);
  282. ret->w = atoi(cfg[0].u.string.sval);
  283. ret->h = atoi(cfg[1].u.string.sval);
  284. ret->diff = cfg[2].u.choices.selected;
  285. return ret;
  286. }
  287. static const char *validate_params(const game_params *params, bool full)
  288. {
  289. if (params->w < 3 || params->h < 3)
  290. return "Width and height must both be at least 3";
  291. if (params->w > INT_MAX / 2 || params->h > INT_MAX / 2 ||
  292. params->w > (INT_MAX - params->w*2 - params->h*2 - 1) / 4 / params->h)
  293. return "Width times height must not be unreasonably large";
  294. /*
  295. * This shouldn't be able to happen at all, since decode_params
  296. * and custom_params will never generate anything that isn't
  297. * within range.
  298. */
  299. assert(params->diff <= DIFF_UNREASONABLE);
  300. return NULL;
  301. }
  302. /* ----------------------------------------------------------
  303. * Game utility functions.
  304. */
  305. static void add_dot(space *space) {
  306. assert(!(space->flags & F_DOT));
  307. space->flags |= F_DOT;
  308. space->nassoc = 0;
  309. }
  310. static void remove_dot(space *space) {
  311. assert(space->flags & F_DOT);
  312. space->flags &= ~F_DOT;
  313. }
  314. static void remove_assoc(const game_state *state, space *tile) {
  315. if (tile->flags & F_TILE_ASSOC) {
  316. SPACE(state, tile->dotx, tile->doty).nassoc--;
  317. tile->flags &= ~F_TILE_ASSOC;
  318. tile->dotx = -1;
  319. tile->doty = -1;
  320. }
  321. }
  322. static void remove_assoc_with_opposite(game_state *state, space *tile) {
  323. space *opposite;
  324. if (!(tile->flags & F_TILE_ASSOC)) {
  325. return;
  326. }
  327. opposite = tile_opposite(state, tile);
  328. remove_assoc(state, tile);
  329. if (opposite != NULL && opposite != tile) {
  330. remove_assoc(state, opposite);
  331. }
  332. }
  333. static void add_assoc(const game_state *state, space *tile, space *dot) {
  334. remove_assoc(state, tile);
  335. #ifdef STANDALONE_PICTURE_GENERATOR
  336. if (picture)
  337. assert(!picture[(tile->y/2) * state->w + (tile->x/2)] ==
  338. !(dot->flags & F_DOT_BLACK));
  339. #endif
  340. tile->flags |= F_TILE_ASSOC;
  341. tile->dotx = dot->x;
  342. tile->doty = dot->y;
  343. dot->nassoc++;
  344. /*debug(("add_assoc sp %d %d --> dot %d,%d, new nassoc %d.\n",
  345. tile->x, tile->y, dot->x, dot->y, dot->nassoc));*/
  346. }
  347. static bool ok_to_add_assoc_with_opposite_internal(
  348. const game_state *state, space *tile, space *opposite)
  349. {
  350. int *colors;
  351. bool toret;
  352. if (tile->type != s_tile)
  353. return false;
  354. if (tile->flags & F_DOT)
  355. return false;
  356. if (opposite == NULL)
  357. return false;
  358. if (opposite->flags & F_DOT)
  359. return false;
  360. toret = true;
  361. colors = snewn(state->w * state->h, int);
  362. check_complete(state, NULL, colors);
  363. if (colors[(tile->y - 1)/2 * state->w + (tile->x - 1)/2])
  364. toret = false;
  365. if (colors[(opposite->y - 1)/2 * state->w + (opposite->x - 1)/2])
  366. toret = false;
  367. sfree(colors);
  368. return toret;
  369. }
  370. #ifndef EDITOR
  371. static bool ok_to_add_assoc_with_opposite(
  372. const game_state *state, space *tile, space *dot)
  373. {
  374. space *opposite = space_opposite_dot(state, tile, dot);
  375. return ok_to_add_assoc_with_opposite_internal(state, tile, opposite);
  376. }
  377. #endif
  378. static void add_assoc_with_opposite(game_state *state, space *tile, space *dot) {
  379. space *opposite = space_opposite_dot(state, tile, dot);
  380. if(opposite && ok_to_add_assoc_with_opposite_internal(
  381. state, tile, opposite))
  382. {
  383. remove_assoc_with_opposite(state, tile);
  384. add_assoc(state, tile, dot);
  385. remove_assoc_with_opposite(state, opposite);
  386. add_assoc(state, opposite, dot);
  387. }
  388. }
  389. #ifndef EDITOR
  390. static space *sp2dot(const game_state *state, int x, int y)
  391. {
  392. space *sp = &SPACE(state, x, y);
  393. if (!(sp->flags & F_TILE_ASSOC)) return NULL;
  394. return &SPACE(state, sp->dotx, sp->doty);
  395. }
  396. #endif
  397. #define IS_VERTICAL_EDGE(x) ((x % 2) == 0)
  398. static bool game_can_format_as_text_now(const game_params *params)
  399. {
  400. return true;
  401. }
  402. static char *encode_game(const game_state *state);
  403. static char *game_text_format(const game_state *state)
  404. {
  405. #ifdef EDITOR
  406. game_params par;
  407. char *params, *desc, *ret;
  408. par.w = state->w;
  409. par.h = state->h;
  410. par.diff = DIFF_MAX; /* shouldn't be used */
  411. params = encode_params(&par, false);
  412. desc = encode_game(state);
  413. ret = snewn(strlen(params) + strlen(desc) + 2, char);
  414. sprintf(ret, "%s:%s", params, desc);
  415. sfree(params);
  416. sfree(desc);
  417. return ret;
  418. #else
  419. int maxlen = (state->sx+1)*state->sy, x, y;
  420. char *ret, *p;
  421. space *sp;
  422. ret = snewn(maxlen+1, char);
  423. p = ret;
  424. for (y = 0; y < state->sy; y++) {
  425. for (x = 0; x < state->sx; x++) {
  426. sp = &SPACE(state, x, y);
  427. if (sp->flags & F_DOT)
  428. *p++ = 'o';
  429. #if 0
  430. else if (sp->flags & (F_REACHABLE|F_MULTIPLE|F_MARK))
  431. *p++ = (sp->flags & F_MULTIPLE) ? 'M' :
  432. (sp->flags & F_REACHABLE) ? 'R' : 'X';
  433. #endif
  434. else {
  435. switch (sp->type) {
  436. case s_tile:
  437. if (sp->flags & F_TILE_ASSOC) {
  438. space *dot = sp2dot(state, sp->x, sp->y);
  439. if (dot && dot->flags & F_DOT)
  440. *p++ = (dot->flags & F_DOT_BLACK) ? 'B' : 'W';
  441. else
  442. *p++ = '?'; /* association with not-a-dot. */
  443. } else
  444. *p++ = ' ';
  445. break;
  446. case s_vertex:
  447. *p++ = '+';
  448. break;
  449. case s_edge:
  450. if (sp->flags & F_EDGE_SET)
  451. *p++ = (IS_VERTICAL_EDGE(x)) ? '|' : '-';
  452. else
  453. *p++ = ' ';
  454. break;
  455. default:
  456. assert(!"shouldn't get here!");
  457. }
  458. }
  459. }
  460. *p++ = '\n';
  461. }
  462. assert(p - ret == maxlen);
  463. *p = '\0';
  464. return ret;
  465. #endif
  466. }
  467. static void dbg_state(const game_state *state)
  468. {
  469. #ifdef DEBUGGING
  470. char *temp = game_text_format(state);
  471. debug(("%s\n", temp));
  472. sfree(temp);
  473. #endif
  474. }
  475. /* Space-enumeration callbacks should all return 1 for 'progress made',
  476. * -1 for 'impossible', and 0 otherwise. */
  477. typedef int (*space_cb)(game_state *state, space *sp, void *ctx);
  478. #define IMPOSSIBLE_QUITS 1
  479. static int foreach_sub(game_state *state, space_cb cb, unsigned int f,
  480. void *ctx, int startx, int starty)
  481. {
  482. int x, y, ret;
  483. bool progress = false, impossible = false;
  484. space *sp;
  485. for (y = starty; y < state->sy; y += 2) {
  486. sp = &SPACE(state, startx, y);
  487. for (x = startx; x < state->sx; x += 2) {
  488. ret = cb(state, sp, ctx);
  489. if (ret == -1) {
  490. if (f & IMPOSSIBLE_QUITS) return -1;
  491. impossible = true;
  492. } else if (ret == 1) {
  493. progress = true;
  494. }
  495. sp += 2;
  496. }
  497. }
  498. return impossible ? -1 : progress ? 1 : 0;
  499. }
  500. static int foreach_tile(game_state *state, space_cb cb, unsigned int f,
  501. void *ctx)
  502. {
  503. return foreach_sub(state, cb, f, ctx, 1, 1);
  504. }
  505. static int foreach_edge(game_state *state, space_cb cb, unsigned int f,
  506. void *ctx)
  507. {
  508. int ret1, ret2;
  509. ret1 = foreach_sub(state, cb, f, ctx, 0, 1);
  510. ret2 = foreach_sub(state, cb, f, ctx, 1, 0);
  511. if (ret1 == -1 || ret2 == -1) return -1;
  512. return (ret1 || ret2) ? 1 : 0;
  513. }
  514. #if 0
  515. static int foreach_vertex(game_state *state, space_cb cb, unsigned int f,
  516. void *ctx)
  517. {
  518. return foreach_sub(state, cb, f, ctx, 0, 0);
  519. }
  520. #endif
  521. #if 0
  522. static int is_same_assoc(game_state *state,
  523. int x1, int y1, int x2, int y2)
  524. {
  525. space *s1, *s2;
  526. if (!INGRID(state, x1, y1) || !INGRID(state, x2, y2))
  527. return 0;
  528. s1 = &SPACE(state, x1, y1);
  529. s2 = &SPACE(state, x2, y2);
  530. assert(s1->type == s_tile && s2->type == s_tile);
  531. if ((s1->flags & F_TILE_ASSOC) && (s2->flags & F_TILE_ASSOC) &&
  532. s1->dotx == s2->dotx && s1->doty == s2->doty)
  533. return 1;
  534. return 0; /* 0 if not same or not both associated. */
  535. }
  536. #endif
  537. #if 0
  538. static int edges_into_vertex(game_state *state,
  539. int x, int y)
  540. {
  541. int dx, dy, nx, ny, count = 0;
  542. assert(SPACE(state, x, y).type == s_vertex);
  543. for (dx = -1; dx <= 1; dx++) {
  544. for (dy = -1; dy <= 1; dy++) {
  545. if (dx != 0 && dy != 0) continue;
  546. if (dx == 0 && dy == 0) continue;
  547. nx = x+dx; ny = y+dy;
  548. if (!INGRID(state, nx, ny)) continue;
  549. assert(SPACE(state, nx, ny).type == s_edge);
  550. if (SPACE(state, nx, ny).flags & F_EDGE_SET)
  551. count++;
  552. }
  553. }
  554. return count;
  555. }
  556. #endif
  557. static space *space_opposite_dot(const game_state *state, const space *sp,
  558. const space *dot)
  559. {
  560. int dx, dy, tx, ty;
  561. space *sp2;
  562. dx = sp->x - dot->x;
  563. dy = sp->y - dot->y;
  564. tx = dot->x - dx;
  565. ty = dot->y - dy;
  566. if (!INGRID(state, tx, ty)) return NULL;
  567. sp2 = &SPACE(state, tx, ty);
  568. assert(sp2->type == sp->type);
  569. return sp2;
  570. }
  571. static space *tile_opposite(const game_state *state, const space *sp)
  572. {
  573. space *dot;
  574. assert(sp->flags & F_TILE_ASSOC);
  575. dot = &SPACE(state, sp->dotx, sp->doty);
  576. return space_opposite_dot(state, sp, dot);
  577. }
  578. static bool dotfortile(game_state *state, space *tile, space *dot)
  579. {
  580. space *tile_opp = space_opposite_dot(state, tile, dot);
  581. if (!tile_opp) return false; /* opposite would be off grid */
  582. if (tile_opp->flags & F_TILE_ASSOC &&
  583. (tile_opp->dotx != dot->x || tile_opp->doty != dot->y))
  584. return false; /* opposite already associated with diff. dot */
  585. return true;
  586. }
  587. static void adjacencies(game_state *state, space *sp, space **a1s, space **a2s)
  588. {
  589. int dxs[4] = {-1, 1, 0, 0}, dys[4] = {0, 0, -1, 1};
  590. int n, x, y;
  591. /* this function needs optimising. */
  592. for (n = 0; n < 4; n++) {
  593. x = sp->x+dxs[n];
  594. y = sp->y+dys[n];
  595. if (INGRID(state, x, y)) {
  596. a1s[n] = &SPACE(state, x, y);
  597. x += dxs[n]; y += dys[n];
  598. if (INGRID(state, x, y))
  599. a2s[n] = &SPACE(state, x, y);
  600. else
  601. a2s[n] = NULL;
  602. } else {
  603. a1s[n] = a2s[n] = NULL;
  604. }
  605. }
  606. }
  607. static bool outline_tile_fordot(game_state *state, space *tile, bool mark)
  608. {
  609. space *tadj[4], *eadj[4];
  610. int i;
  611. bool didsth = false, edge, same;
  612. assert(tile->type == s_tile);
  613. adjacencies(state, tile, eadj, tadj);
  614. for (i = 0; i < 4; i++) {
  615. if (!eadj[i]) continue;
  616. edge = eadj[i]->flags & F_EDGE_SET;
  617. if (tadj[i]) {
  618. if (!(tile->flags & F_TILE_ASSOC))
  619. same = !(tadj[i]->flags & F_TILE_ASSOC);
  620. else
  621. same = ((tadj[i]->flags & F_TILE_ASSOC) &&
  622. tile->dotx == tadj[i]->dotx &&
  623. tile->doty == tadj[i]->doty);
  624. } else
  625. same = false;
  626. if (!edge && !same) {
  627. if (mark) eadj[i]->flags |= F_EDGE_SET;
  628. didsth = true;
  629. } else if (edge && same) {
  630. if (mark) eadj[i]->flags &= ~F_EDGE_SET;
  631. didsth = true;
  632. }
  633. }
  634. return didsth;
  635. }
  636. static void tiles_from_edge(game_state *state, space *sp, space **ts)
  637. {
  638. int xs[2], ys[2];
  639. if (IS_VERTICAL_EDGE(sp->x)) {
  640. xs[0] = sp->x-1; ys[0] = sp->y;
  641. xs[1] = sp->x+1; ys[1] = sp->y;
  642. } else {
  643. xs[0] = sp->x; ys[0] = sp->y-1;
  644. xs[1] = sp->x; ys[1] = sp->y+1;
  645. }
  646. ts[0] = INGRID(state, xs[0], ys[0]) ? &SPACE(state, xs[0], ys[0]) : NULL;
  647. ts[1] = INGRID(state, xs[1], ys[1]) ? &SPACE(state, xs[1], ys[1]) : NULL;
  648. }
  649. /* Returns a move string for use by 'solve', including the initial
  650. * 'S' if issolve is true. */
  651. static char *diff_game(const game_state *src, const game_state *dest,
  652. bool issolve, int set_cdiff)
  653. {
  654. int movelen = 0, movesize = 256, x, y, len;
  655. char *move = snewn(movesize, char), buf[80];
  656. const char *sep = "";
  657. char achar = issolve ? 'a' : 'A';
  658. space *sps, *spd;
  659. assert(src->sx == dest->sx && src->sy == dest->sy);
  660. if (issolve) {
  661. move[movelen++] = 'S';
  662. sep = ";";
  663. }
  664. #ifdef EDITOR
  665. if (set_cdiff >= 0) {
  666. switch (set_cdiff) {
  667. case DIFF_IMPOSSIBLE:
  668. movelen += sprintf(move+movelen, "%sII", sep);
  669. break;
  670. case DIFF_AMBIGUOUS:
  671. movelen += sprintf(move+movelen, "%sIA", sep);
  672. break;
  673. case DIFF_UNFINISHED:
  674. movelen += sprintf(move+movelen, "%sIU", sep);
  675. break;
  676. default:
  677. movelen += sprintf(move+movelen, "%si%c",
  678. sep, galaxies_diffchars[set_cdiff]);
  679. break;
  680. }
  681. sep = ";";
  682. }
  683. #endif
  684. move[movelen] = '\0';
  685. for (x = 0; x < src->sx; x++) {
  686. for (y = 0; y < src->sy; y++) {
  687. sps = &SPACE(src, x, y);
  688. spd = &SPACE(dest, x, y);
  689. assert(sps->type == spd->type);
  690. len = 0;
  691. if (sps->type == s_tile) {
  692. if ((sps->flags & F_TILE_ASSOC) &&
  693. (spd->flags & F_TILE_ASSOC)) {
  694. if (sps->dotx != spd->dotx ||
  695. sps->doty != spd->doty)
  696. /* Both associated; change association, if different */
  697. len = sprintf(buf, "%s%c%d,%d,%d,%d", sep,
  698. (int)achar, x, y, spd->dotx, spd->doty);
  699. } else if (sps->flags & F_TILE_ASSOC)
  700. /* Only src associated; remove. */
  701. len = sprintf(buf, "%sU%d,%d", sep, x, y);
  702. else if (spd->flags & F_TILE_ASSOC)
  703. /* Only dest associated; add. */
  704. len = sprintf(buf, "%s%c%d,%d,%d,%d", sep,
  705. (int)achar, x, y, spd->dotx, spd->doty);
  706. } else if (sps->type == s_edge) {
  707. if ((sps->flags & F_EDGE_SET) != (spd->flags & F_EDGE_SET))
  708. /* edge flags are different; flip them. */
  709. len = sprintf(buf, "%sE%d,%d", sep, x, y);
  710. }
  711. if (len) {
  712. if (movelen + len >= movesize) {
  713. movesize = movelen + len + 256;
  714. move = sresize(move, movesize, char);
  715. }
  716. strcpy(move + movelen, buf);
  717. movelen += len;
  718. sep = ";";
  719. }
  720. }
  721. }
  722. debug(("diff_game src then dest:\n"));
  723. dbg_state(src);
  724. dbg_state(dest);
  725. debug(("diff string %s\n", move));
  726. return move;
  727. }
  728. /* Returns true if a dot here would not be too close to any other dots
  729. * (and would avoid other game furniture). */
  730. static bool dot_is_possible(const game_state *state, space *sp,
  731. bool allow_assoc)
  732. {
  733. int bx = 0, by = 0, dx, dy;
  734. space *adj;
  735. #ifdef STANDALONE_PICTURE_GENERATOR
  736. int col = -1;
  737. #endif
  738. switch (sp->type) {
  739. case s_tile:
  740. bx = by = 1; break;
  741. case s_edge:
  742. if (IS_VERTICAL_EDGE(sp->x)) {
  743. bx = 2; by = 1;
  744. } else {
  745. bx = 1; by = 2;
  746. }
  747. break;
  748. case s_vertex:
  749. bx = by = 2; break;
  750. }
  751. for (dx = -bx; dx <= bx; dx++) {
  752. for (dy = -by; dy <= by; dy++) {
  753. if (!INGRID(state, sp->x+dx, sp->y+dy)) continue;
  754. adj = &SPACE(state, sp->x+dx, sp->y+dy);
  755. #ifdef STANDALONE_PICTURE_GENERATOR
  756. /*
  757. * Check that all the squares we're looking at have the
  758. * same colour.
  759. */
  760. if (picture) {
  761. if (adj->type == s_tile) {
  762. int c = picture[(adj->y / 2) * state->w + (adj->x / 2)];
  763. if (col < 0)
  764. col = c;
  765. if (c != col)
  766. return false; /* colour mismatch */
  767. }
  768. }
  769. #endif
  770. if (!allow_assoc && (adj->flags & F_TILE_ASSOC))
  771. return false;
  772. if (dx != 0 || dy != 0) {
  773. /* Other than our own square, no dots nearby. */
  774. if (adj->flags & (F_DOT))
  775. return false;
  776. }
  777. /* We don't want edges within our rectangle
  778. * (but don't care about edges on the edge) */
  779. if (abs(dx) < bx && abs(dy) < by &&
  780. adj->flags & F_EDGE_SET)
  781. return false;
  782. }
  783. }
  784. return true;
  785. }
  786. /* ----------------------------------------------------------
  787. * Game generation, structure creation, and descriptions.
  788. */
  789. static game_state *blank_game(int w, int h)
  790. {
  791. game_state *state = snew(game_state);
  792. int x, y;
  793. state->w = w;
  794. state->h = h;
  795. state->sx = (w*2)+1;
  796. state->sy = (h*2)+1;
  797. state->grid = snewn(state->sx * state->sy, space);
  798. state->completed = false;
  799. state->used_solve = false;
  800. for (x = 0; x < state->sx; x++) {
  801. for (y = 0; y < state->sy; y++) {
  802. space *sp = &SPACE(state, x, y);
  803. memset(sp, 0, sizeof(space));
  804. sp->x = x;
  805. sp->y = y;
  806. if ((x % 2) == 0 && (y % 2) == 0)
  807. sp->type = s_vertex;
  808. else if ((x % 2) == 0 || (y % 2) == 0) {
  809. sp->type = s_edge;
  810. if (x == 0 || y == 0 || x == state->sx-1 || y == state->sy-1)
  811. sp->flags |= F_EDGE_SET;
  812. } else
  813. sp->type = s_tile;
  814. }
  815. }
  816. state->ndots = 0;
  817. state->dots = NULL;
  818. state->me = NULL; /* filled in by new_game. */
  819. state->cdiff = -1;
  820. return state;
  821. }
  822. static void game_update_dots(game_state *state)
  823. {
  824. int i, n, sz = state->sx * state->sy;
  825. if (state->dots) sfree(state->dots);
  826. state->ndots = 0;
  827. for (i = 0; i < sz; i++) {
  828. if (state->grid[i].flags & F_DOT) state->ndots++;
  829. }
  830. state->dots = snewn(state->ndots, space *);
  831. n = 0;
  832. for (i = 0; i < sz; i++) {
  833. if (state->grid[i].flags & F_DOT)
  834. state->dots[n++] = &state->grid[i];
  835. }
  836. }
  837. static void clear_game(game_state *state, bool cleardots)
  838. {
  839. int x, y;
  840. /* don't erase edge flags around outline! */
  841. for (x = 1; x < state->sx-1; x++) {
  842. for (y = 1; y < state->sy-1; y++) {
  843. if (cleardots)
  844. SPACE(state, x, y).flags = 0;
  845. else
  846. SPACE(state, x, y).flags &= (F_DOT|F_DOT_BLACK);
  847. }
  848. }
  849. if (cleardots) game_update_dots(state);
  850. }
  851. static game_state *dup_game(const game_state *state)
  852. {
  853. game_state *ret = blank_game(state->w, state->h);
  854. ret->completed = state->completed;
  855. ret->used_solve = state->used_solve;
  856. memcpy(ret->grid, state->grid,
  857. ret->sx*ret->sy*sizeof(space));
  858. game_update_dots(ret);
  859. ret->me = state->me;
  860. ret->cdiff = state->cdiff;
  861. return ret;
  862. }
  863. static void free_game(game_state *state)
  864. {
  865. if (state->dots) sfree(state->dots);
  866. sfree(state->grid);
  867. sfree(state);
  868. }
  869. /* Game description is a sequence of letters representing the number
  870. * of spaces (a = 0, y = 24) before the next dot; a-y for a white dot,
  871. * and A-Y for a black dot. 'z' is 25 spaces (and no dot).
  872. *
  873. * I know it's a bitch to generate by hand, so we provide
  874. * an edit mode.
  875. */
  876. static char *encode_game(const game_state *state)
  877. {
  878. char *desc, *p;
  879. int run, x, y, area;
  880. unsigned int f;
  881. area = (state->sx-2) * (state->sy-2);
  882. desc = snewn(area, char);
  883. p = desc;
  884. run = 0;
  885. for (y = 1; y < state->sy-1; y++) {
  886. for (x = 1; x < state->sx-1; x++) {
  887. f = SPACE(state, x, y).flags;
  888. /* a/A is 0 spaces between, b/B is 1 space, ...
  889. * y/Y is 24 spaces, za/zA is 25 spaces, ...
  890. * It's easier to count from 0 because we then
  891. * don't have to special-case the top left-hand corner
  892. * (which could be a dot with 0 spaces before it). */
  893. if (!(f & F_DOT))
  894. run++;
  895. else {
  896. while (run > 24) {
  897. *p++ = 'z';
  898. run -= 25;
  899. }
  900. *p++ = ((f & F_DOT_BLACK) ? 'A' : 'a') + run;
  901. run = 0;
  902. }
  903. }
  904. }
  905. assert(p - desc < area);
  906. *p++ = '\0';
  907. desc = sresize(desc, p - desc, char);
  908. return desc;
  909. }
  910. struct movedot {
  911. int op;
  912. space *olddot, *newdot;
  913. };
  914. enum { MD_CHECK, MD_MOVE };
  915. static int movedot_cb(game_state *state, space *tile, void *vctx)
  916. {
  917. struct movedot *md = (struct movedot *)vctx;
  918. space *newopp = NULL;
  919. assert(tile->type == s_tile);
  920. assert(md->olddot && md->newdot);
  921. if (!(tile->flags & F_TILE_ASSOC)) return 0;
  922. if (tile->dotx != md->olddot->x || tile->doty != md->olddot->y)
  923. return 0;
  924. newopp = space_opposite_dot(state, tile, md->newdot);
  925. switch (md->op) {
  926. case MD_CHECK:
  927. /* If the tile is associated with the old dot, check its
  928. * opposite wrt the _new_ dot is empty or same assoc. */
  929. if (!newopp) return -1; /* no new opposite */
  930. if (newopp->flags & F_TILE_ASSOC) {
  931. if (newopp->dotx != md->olddot->x ||
  932. newopp->doty != md->olddot->y)
  933. return -1; /* associated, but wrong dot. */
  934. }
  935. #ifdef STANDALONE_PICTURE_GENERATOR
  936. if (picture) {
  937. /*
  938. * Reject if either tile and the dot don't match in colour.
  939. */
  940. if (!(picture[(tile->y/2) * state->w + (tile->x/2)]) ^
  941. !(md->newdot->flags & F_DOT_BLACK))
  942. return -1;
  943. if (!(picture[(newopp->y/2) * state->w + (newopp->x/2)]) ^
  944. !(md->newdot->flags & F_DOT_BLACK))
  945. return -1;
  946. }
  947. #endif
  948. break;
  949. case MD_MOVE:
  950. /* Move dot associations: anything that was associated
  951. * with the old dot, and its opposite wrt the new dot,
  952. * become associated with the new dot. */
  953. assert(newopp);
  954. debug(("Associating %d,%d and %d,%d with new dot %d,%d.\n",
  955. tile->x, tile->y, newopp->x, newopp->y,
  956. md->newdot->x, md->newdot->y));
  957. add_assoc(state, tile, md->newdot);
  958. add_assoc(state, newopp, md->newdot);
  959. return 1; /* we did something! */
  960. }
  961. return 0;
  962. }
  963. /* For the given dot, first see if we could expand it into all the given
  964. * extra spaces (by checking for empty spaces on the far side), and then
  965. * see if we can move the dot to shift the CoG to include the new spaces.
  966. */
  967. static bool dot_expand_or_move(game_state *state, space *dot,
  968. space **toadd, int nadd)
  969. {
  970. space *tileopp;
  971. int i, ret, nnew, cx, cy;
  972. struct movedot md;
  973. debug(("dot_expand_or_move: %d tiles for dot %d,%d\n",
  974. nadd, dot->x, dot->y));
  975. for (i = 0; i < nadd; i++)
  976. debug(("dot_expand_or_move: dot %d,%d\n",
  977. toadd[i]->x, toadd[i]->y));
  978. assert(dot->flags & F_DOT);
  979. #ifdef STANDALONE_PICTURE_GENERATOR
  980. if (picture) {
  981. /*
  982. * Reject the expansion totally if any of the new tiles are
  983. * the wrong colour.
  984. */
  985. for (i = 0; i < nadd; i++) {
  986. if (!(picture[(toadd[i]->y/2) * state->w + (toadd[i]->x/2)]) ^
  987. !(dot->flags & F_DOT_BLACK))
  988. return false;
  989. }
  990. }
  991. #endif
  992. /* First off, could we just expand the current dot's tile to cover
  993. * the space(s) passed in and their opposites? */
  994. for (i = 0; i < nadd; i++) {
  995. tileopp = space_opposite_dot(state, toadd[i], dot);
  996. if (!tileopp) goto noexpand;
  997. if (tileopp->flags & F_TILE_ASSOC) goto noexpand;
  998. #ifdef STANDALONE_PICTURE_GENERATOR
  999. if (picture) {
  1000. /*
  1001. * The opposite tiles have to be the right colour as well.
  1002. */
  1003. if (!(picture[(tileopp->y/2) * state->w + (tileopp->x/2)]) ^
  1004. !(dot->flags & F_DOT_BLACK))
  1005. goto noexpand;
  1006. }
  1007. #endif
  1008. }
  1009. /* OK, all spaces have valid empty opposites: associate spaces and
  1010. * opposites with our dot. */
  1011. for (i = 0; i < nadd; i++) {
  1012. tileopp = space_opposite_dot(state, toadd[i], dot);
  1013. add_assoc(state, toadd[i], dot);
  1014. add_assoc(state, tileopp, dot);
  1015. debug(("Added associations %d,%d and %d,%d --> %d,%d\n",
  1016. toadd[i]->x, toadd[i]->y,
  1017. tileopp->x, tileopp->y,
  1018. dot->x, dot->y));
  1019. dbg_state(state);
  1020. }
  1021. return true;
  1022. noexpand:
  1023. /* Otherwise, try to move dot so as to encompass given spaces: */
  1024. /* first, calculate the 'centre of gravity' of the new dot. */
  1025. nnew = dot->nassoc + nadd; /* number of tiles assoc. with new dot. */
  1026. cx = dot->x * dot->nassoc;
  1027. cy = dot->y * dot->nassoc;
  1028. for (i = 0; i < nadd; i++) {
  1029. cx += toadd[i]->x;
  1030. cy += toadd[i]->y;
  1031. }
  1032. /* If the CoG isn't a whole number, it's not possible. */
  1033. if ((cx % nnew) != 0 || (cy % nnew) != 0) {
  1034. debug(("Unable to move dot %d,%d, CoG not whole number.\n",
  1035. dot->x, dot->y));
  1036. return false;
  1037. }
  1038. cx /= nnew; cy /= nnew;
  1039. /* Check whether all spaces in the old tile would have a good
  1040. * opposite wrt the new dot. */
  1041. md.olddot = dot;
  1042. md.newdot = &SPACE(state, cx, cy);
  1043. md.op = MD_CHECK;
  1044. ret = foreach_tile(state, movedot_cb, IMPOSSIBLE_QUITS, &md);
  1045. if (ret == -1) {
  1046. debug(("Unable to move dot %d,%d, new dot not symmetrical.\n",
  1047. dot->x, dot->y));
  1048. return false;
  1049. }
  1050. /* Also check whether all spaces we're adding would have a good
  1051. * opposite wrt the new dot. */
  1052. for (i = 0; i < nadd; i++) {
  1053. tileopp = space_opposite_dot(state, toadd[i], md.newdot);
  1054. if (tileopp && (tileopp->flags & F_TILE_ASSOC) &&
  1055. (tileopp->dotx != dot->x || tileopp->doty != dot->y)) {
  1056. tileopp = NULL;
  1057. }
  1058. if (!tileopp) {
  1059. debug(("Unable to move dot %d,%d, new dot not symmetrical.\n",
  1060. dot->x, dot->y));
  1061. return false;
  1062. }
  1063. #ifdef STANDALONE_PICTURE_GENERATOR
  1064. if (picture) {
  1065. if (!(picture[(tileopp->y/2) * state->w + (tileopp->x/2)]) ^
  1066. !(dot->flags & F_DOT_BLACK))
  1067. return false;
  1068. }
  1069. #endif
  1070. }
  1071. /* If we've got here, we're ok. First, associate all of 'toadd'
  1072. * with the _old_ dot (so they'll get fixed up, with their opposites,
  1073. * in the next step). */
  1074. for (i = 0; i < nadd; i++) {
  1075. debug(("Associating to-add %d,%d with old dot %d,%d.\n",
  1076. toadd[i]->x, toadd[i]->y, dot->x, dot->y));
  1077. add_assoc(state, toadd[i], dot);
  1078. }
  1079. /* Finally, move the dot and fix up all the old associations. */
  1080. debug(("Moving dot at %d,%d to %d,%d\n",
  1081. dot->x, dot->y, md.newdot->x, md.newdot->y));
  1082. {
  1083. #ifdef STANDALONE_PICTURE_GENERATOR
  1084. int f = dot->flags & F_DOT_BLACK;
  1085. #endif
  1086. remove_dot(dot);
  1087. add_dot(md.newdot);
  1088. #ifdef STANDALONE_PICTURE_GENERATOR
  1089. md.newdot->flags |= f;
  1090. #endif
  1091. }
  1092. md.op = MD_MOVE;
  1093. ret = foreach_tile(state, movedot_cb, 0, &md);
  1094. assert(ret == 1);
  1095. dbg_state(state);
  1096. return true;
  1097. }
  1098. /* Hard-code to a max. of 2x2 squares, for speed (less malloc) */
  1099. #define MAX_TOADD 4
  1100. #define MAX_OUTSIDE 8
  1101. #define MAX_TILE_PERC 20
  1102. static bool generate_try_block(game_state *state, random_state *rs,
  1103. int x1, int y1, int x2, int y2)
  1104. {
  1105. int x, y, nadd = 0, nout = 0, i, maxsz;
  1106. space *sp, *toadd[MAX_TOADD], *outside[MAX_OUTSIDE], *dot;
  1107. if (!INGRID(state, x1, y1) || !INGRID(state, x2, y2)) return false;
  1108. /* We limit the maximum size of tiles to be ~2*sqrt(area); so,
  1109. * a 5x5 grid shouldn't have anything >10 tiles, a 20x20 grid
  1110. * nothing >40 tiles. */
  1111. maxsz = (int)sqrt((double)(state->w * state->h)) * 2;
  1112. debug(("generate_try_block, maxsz %d\n", maxsz));
  1113. /* Make a static list of the spaces; if any space is already
  1114. * associated then quit immediately. */
  1115. for (x = x1; x <= x2; x += 2) {
  1116. for (y = y1; y <= y2; y += 2) {
  1117. assert(nadd < MAX_TOADD);
  1118. sp = &SPACE(state, x, y);
  1119. assert(sp->type == s_tile);
  1120. if (sp->flags & F_TILE_ASSOC) return false;
  1121. toadd[nadd++] = sp;
  1122. }
  1123. }
  1124. /* Make a list of the spaces outside of our block, and shuffle it. */
  1125. #define OUTSIDE(x, y) do { \
  1126. if (INGRID(state, (x), (y))) { \
  1127. assert(nout < MAX_OUTSIDE); \
  1128. outside[nout++] = &SPACE(state, (x), (y)); \
  1129. } \
  1130. } while(0)
  1131. for (x = x1; x <= x2; x += 2) {
  1132. OUTSIDE(x, y1-2);
  1133. OUTSIDE(x, y2+2);
  1134. }
  1135. for (y = y1; y <= y2; y += 2) {
  1136. OUTSIDE(x1-2, y);
  1137. OUTSIDE(x2+2, y);
  1138. }
  1139. shuffle(outside, nout, sizeof(space *), rs);
  1140. for (i = 0; i < nout; i++) {
  1141. if (!(outside[i]->flags & F_TILE_ASSOC)) continue;
  1142. dot = &SPACE(state, outside[i]->dotx, outside[i]->doty);
  1143. if (dot->nassoc >= maxsz) {
  1144. debug(("Not adding to dot %d,%d, large enough (%d) already.\n",
  1145. dot->x, dot->y, dot->nassoc));
  1146. continue;
  1147. }
  1148. if (dot_expand_or_move(state, dot, toadd, nadd)) return true;
  1149. }
  1150. return false;
  1151. }
  1152. #ifdef STANDALONE_SOLVER
  1153. static bool one_try; /* override for soak testing */
  1154. #endif
  1155. #define GP_DOTS 1
  1156. static void generate_pass(game_state *state, random_state *rs, int *scratch,
  1157. int perc, unsigned int flags)
  1158. {
  1159. int sz = state->sx*state->sy, nspc, i, ret;
  1160. /* Random list of squares to try and process, one-by-one. */
  1161. for (i = 0; i < sz; i++) scratch[i] = i;
  1162. shuffle(scratch, sz, sizeof(int), rs);
  1163. /* This bug took me a, er, little while to track down. On PalmOS,
  1164. * which has 16-bit signed ints, puzzles over about 9x9 started
  1165. * failing to generate because the nspc calculation would start
  1166. * to overflow, causing the dots not to be filled in properly. */
  1167. nspc = (int)(((long)perc * (long)sz) / 100L);
  1168. debug(("generate_pass: %d%% (%d of %dx%d) squares, flags 0x%x\n",
  1169. perc, nspc, state->sx, state->sy, flags));
  1170. for (i = 0; i < nspc; i++) {
  1171. space *sp = &state->grid[scratch[i]];
  1172. int x1 = sp->x, y1 = sp->y, x2 = sp->x, y2 = sp->y;
  1173. if (sp->type == s_edge) {
  1174. if (IS_VERTICAL_EDGE(sp->x)) {
  1175. x1--; x2++;
  1176. } else {
  1177. y1--; y2++;
  1178. }
  1179. }
  1180. if (sp->type != s_vertex) {
  1181. /* heuristic; expanding from vertices tends to generate lots of
  1182. * too-big regions of tiles. */
  1183. if (generate_try_block(state, rs, x1, y1, x2, y2))
  1184. continue; /* we expanded successfully. */
  1185. }
  1186. if (!(flags & GP_DOTS)) continue;
  1187. if ((sp->type == s_edge) && (i % 2)) {
  1188. debug(("Omitting edge %d,%d as half-of.\n", sp->x, sp->y));
  1189. continue;
  1190. }
  1191. /* If we've got here we might want to put a dot down. Check
  1192. * if we can, and add one if so. */
  1193. if (dot_is_possible(state, sp, false)) {
  1194. add_dot(sp);
  1195. #ifdef STANDALONE_PICTURE_GENERATOR
  1196. if (picture) {
  1197. if (picture[(sp->y/2) * state->w + (sp->x/2)])
  1198. sp->flags |= F_DOT_BLACK;
  1199. }
  1200. #endif
  1201. ret = solver_obvious_dot(state, sp);
  1202. assert(ret != -1);
  1203. debug(("Added dot (and obvious associations) at %d,%d\n",
  1204. sp->x, sp->y));
  1205. dbg_state(state);
  1206. }
  1207. }
  1208. dbg_state(state);
  1209. }
  1210. /*
  1211. * We try several times to generate a grid at all, before even feeding
  1212. * it to the solver. Then we pick whichever of the resulting grids was
  1213. * the most 'wiggly', as measured by the number of inward corners in
  1214. * the shape of any region.
  1215. *
  1216. * Rationale: wiggly shapes are what make this puzzle fun, and it's
  1217. * disappointing to be served a game whose entire solution is a
  1218. * collection of rectangles. But we also don't want to introduce a
  1219. * _hard requirement_ of wiggliness, because a player who knew that
  1220. * was there would be able to use it as an extra clue. This way, we
  1221. * just probabilistically skew in favour of wiggliness.
  1222. */
  1223. #define GENERATE_TRIES 10
  1224. static bool is_wiggle(const game_state *state, int x, int y, int dx, int dy)
  1225. {
  1226. int x1 = x+2*dx, y1 = y+2*dy;
  1227. int x2 = x-2*dy, y2 = y+2*dx;
  1228. space *t, *t1, *t2;
  1229. if (!INGRID(state, x1, y1) || !INGRID(state, x2, y2))
  1230. return false;
  1231. t = &SPACE(state, x, y);
  1232. t1 = &SPACE(state, x1, y1);
  1233. t2 = &SPACE(state, x2, y2);
  1234. return ((t1->dotx == t2->dotx && t1->doty == t2->doty) &&
  1235. !(t1->dotx == t->dotx && t1->doty == t->doty));
  1236. }
  1237. static int measure_wiggliness(const game_state *state, int *scratch)
  1238. {
  1239. int sz = state->sx*state->sy;
  1240. int x, y, nwiggles = 0;
  1241. memset(scratch, 0, sz);
  1242. for (y = 1; y < state->sy; y += 2) {
  1243. for (x = 1; x < state->sx; x += 2) {
  1244. if (y+2 < state->sy) {
  1245. nwiggles += is_wiggle(state, x, y, 0, +1);
  1246. nwiggles += is_wiggle(state, x, y, 0, -1);
  1247. nwiggles += is_wiggle(state, x, y, +1, 0);
  1248. nwiggles += is_wiggle(state, x, y, -1, 0);
  1249. }
  1250. }
  1251. }
  1252. return nwiggles;
  1253. }
  1254. static char *new_game_desc(const game_params *params, random_state *rs,
  1255. char **aux, bool interactive)
  1256. {
  1257. game_state *state = blank_game(params->w, params->h), *copy;
  1258. char *desc;
  1259. int *scratch, sz = state->sx*state->sy, i;
  1260. int diff, best_wiggliness;
  1261. bool cc;
  1262. scratch = snewn(sz, int);
  1263. generate:
  1264. best_wiggliness = -1;
  1265. copy = NULL;
  1266. for (i = 0; i < GENERATE_TRIES; i++) {
  1267. int this_wiggliness;
  1268. do {
  1269. clear_game(state, true);
  1270. generate_pass(state, rs, scratch, 100, GP_DOTS);
  1271. game_update_dots(state);
  1272. } while (state->ndots == 1);
  1273. this_wiggliness = measure_wiggliness(state, scratch);
  1274. debug(("Grid gen #%d: wiggliness=%d", i, this_wiggliness));
  1275. if (this_wiggliness > best_wiggliness) {
  1276. best_wiggliness = this_wiggliness;
  1277. if (copy)
  1278. free_game(copy);
  1279. copy = dup_game(state);
  1280. debug((" new best"));
  1281. }
  1282. debug(("\n"));
  1283. }
  1284. assert(copy);
  1285. free_game(state);
  1286. state = copy;
  1287. #ifdef DEBUGGING
  1288. {
  1289. char *tmp = encode_game(state);
  1290. debug(("new_game_desc state %dx%d:%s\n", params->w, params->h, tmp));
  1291. sfree(tmp);
  1292. }
  1293. #endif
  1294. for (i = 0; i < state->sx*state->sy; i++)
  1295. if (state->grid[i].type == s_tile)
  1296. outline_tile_fordot(state, &state->grid[i], true);
  1297. cc = check_complete(state, NULL, NULL);
  1298. assert(cc);
  1299. copy = dup_game(state);
  1300. clear_game(copy, false);
  1301. dbg_state(copy);
  1302. diff = solver_state(copy, params->diff);
  1303. free_game(copy);
  1304. assert(diff != DIFF_IMPOSSIBLE);
  1305. if (diff != params->diff) {
  1306. /*
  1307. * If the puzzle was insoluble at this difficulty level (i.e.
  1308. * too hard), _or_ soluble at a lower level (too easy), go
  1309. * round again.
  1310. *
  1311. * An exception is in soak-testing mode, where we return the
  1312. * first puzzle we got regardless.
  1313. */
  1314. #ifdef STANDALONE_SOLVER
  1315. if (!one_try)
  1316. #endif
  1317. goto generate;
  1318. }
  1319. #ifdef STANDALONE_PICTURE_GENERATOR
  1320. /*
  1321. * Postprocessing pass to prevent excessive numbers of adjacent
  1322. * singletons. Iterate over all edges in random shuffled order;
  1323. * for each edge that separates two regions, investigate
  1324. * whether removing that edge and merging the regions would
  1325. * still yield a valid and soluble puzzle. (The two regions
  1326. * must also be the same colour, of course.) If so, do it.
  1327. *
  1328. * This postprocessing pass is slow (due to repeated solver
  1329. * invocations), and seems to be unnecessary during normal
  1330. * unconstrained game generation. However, when generating a
  1331. * game under colour constraints, excessive singletons seem to
  1332. * turn up more often, so it's worth doing this.
  1333. */
  1334. {
  1335. int *posns, nposns;
  1336. int i, j, newdiff;
  1337. game_state *copy2;
  1338. nposns = params->w * (params->h+1) + params->h * (params->w+1);
  1339. posns = snewn(nposns, int);
  1340. for (i = j = 0; i < state->sx*state->sy; i++)
  1341. if (state->grid[i].type == s_edge)
  1342. posns[j++] = i;
  1343. assert(j == nposns);
  1344. shuffle(posns, nposns, sizeof(*posns), rs);
  1345. for (i = 0; i < nposns; i++) {
  1346. int x, y, x0, y0, x1, y1, cx, cy, cn, cx0, cy0, cx1, cy1, tx, ty;
  1347. space *s0, *s1, *ts, *d0, *d1, *dn;
  1348. bool ok;
  1349. /* Coordinates of edge space */
  1350. x = posns[i] % state->sx;
  1351. y = posns[i] / state->sx;
  1352. /* Coordinates of square spaces on either side of edge */
  1353. x0 = ((x+1) & ~1) - 1; /* round down to next odd number */
  1354. y0 = ((y+1) & ~1) - 1;
  1355. x1 = 2*x-x0; /* and reflect about x to get x1 */
  1356. y1 = 2*y-y0;
  1357. if (!INGRID(state, x0, y0) || !INGRID(state, x1, y1))
  1358. continue; /* outermost edge of grid */
  1359. s0 = &SPACE(state, x0, y0);
  1360. s1 = &SPACE(state, x1, y1);
  1361. assert(s0->type == s_tile && s1->type == s_tile);
  1362. if (s0->dotx == s1->dotx && s0->doty == s1->doty)
  1363. continue; /* tiles _already_ owned by same dot */
  1364. d0 = &SPACE(state, s0->dotx, s0->doty);
  1365. d1 = &SPACE(state, s1->dotx, s1->doty);
  1366. if ((d0->flags ^ d1->flags) & F_DOT_BLACK)
  1367. continue; /* different colours: cannot merge */
  1368. /*
  1369. * Work out where the centre of gravity of the new
  1370. * region would be.
  1371. */
  1372. cx = d0->nassoc * d0->x + d1->nassoc * d1->x;
  1373. cy = d0->nassoc * d0->y + d1->nassoc * d1->y;
  1374. cn = d0->nassoc + d1->nassoc;
  1375. if (cx % cn || cy % cn)
  1376. continue; /* CoG not at integer coordinates */
  1377. cx /= cn;
  1378. cy /= cn;
  1379. assert(INUI(state, cx, cy));
  1380. /*
  1381. * Ensure that the CoG would actually be _in_ the new
  1382. * region, by verifying that all its surrounding tiles
  1383. * belong to one or other of our two dots.
  1384. */
  1385. cx0 = ((cx+1) & ~1) - 1; /* round down to next odd number */
  1386. cy0 = ((cy+1) & ~1) - 1;
  1387. cx1 = 2*cx-cx0; /* and reflect about cx to get cx1 */
  1388. cy1 = 2*cy-cy0;
  1389. ok = true;
  1390. for (ty = cy0; ty <= cy1; ty += 2)
  1391. for (tx = cx0; tx <= cx1; tx += 2) {
  1392. ts = &SPACE(state, tx, ty);
  1393. assert(ts->type == s_tile);
  1394. if ((ts->dotx != d0->x || ts->doty != d0->y) &&
  1395. (ts->dotx != d1->x || ts->doty != d1->y))
  1396. ok = false;
  1397. }
  1398. if (!ok)
  1399. continue;
  1400. /*
  1401. * Verify that for every tile in either source region,
  1402. * that tile's image in the new CoG is also in one of
  1403. * the two source regions.
  1404. */
  1405. for (ty = 1; ty < state->sy; ty += 2) {
  1406. for (tx = 1; tx < state->sx; tx += 2) {
  1407. int tx1, ty1;
  1408. ts = &SPACE(state, tx, ty);
  1409. assert(ts->type == s_tile);
  1410. if ((ts->dotx != d0->x || ts->doty != d0->y) &&
  1411. (ts->dotx != d1->x || ts->doty != d1->y))
  1412. continue; /* not part of these tiles anyway */
  1413. tx1 = 2*cx-tx;
  1414. ty1 = 2*cy-ty;
  1415. if (!INGRID(state, tx1, ty1)) {
  1416. ok = false;
  1417. break;
  1418. }
  1419. ts = &SPACE(state, cx+cx-tx, cy+cy-ty);
  1420. if ((ts->dotx != d0->x || ts->doty != d0->y) &&
  1421. (ts->dotx != d1->x || ts->doty != d1->y)) {
  1422. ok = false;
  1423. break;
  1424. }
  1425. }
  1426. if (!ok)
  1427. break;
  1428. }
  1429. if (!ok)
  1430. continue;
  1431. /*
  1432. * Now we're clear to attempt the merge. We take a copy
  1433. * of the game state first, so we can revert it easily
  1434. * if the resulting puzzle turns out to have become
  1435. * insoluble.
  1436. */
  1437. copy2 = dup_game(state);
  1438. remove_dot(d0);
  1439. remove_dot(d1);
  1440. dn = &SPACE(state, cx, cy);
  1441. add_dot(dn);
  1442. dn->flags |= (d0->flags & F_DOT_BLACK);
  1443. for (ty = 1; ty < state->sy; ty += 2) {
  1444. for (tx = 1; tx < state->sx; tx += 2) {
  1445. ts = &SPACE(state, tx, ty);
  1446. assert(ts->type == s_tile);
  1447. if ((ts->dotx != d0->x || ts->doty != d0->y) &&
  1448. (ts->dotx != d1->x || ts->doty != d1->y))
  1449. continue; /* not part of these tiles anyway */
  1450. add_assoc(state, ts, dn);
  1451. }
  1452. }
  1453. copy = dup_game(state);
  1454. clear_game(copy, false);
  1455. dbg_state(copy);
  1456. newdiff = solver_state(copy, params->diff);
  1457. free_game(copy);
  1458. if (diff == newdiff) {
  1459. /* Still just as soluble. Let the merge stand. */
  1460. free_game(copy2);
  1461. } else {
  1462. /* Became insoluble. Revert. */
  1463. free_game(state);
  1464. state = copy2;
  1465. }
  1466. }
  1467. sfree(posns);
  1468. }
  1469. #endif
  1470. desc = encode_game(state);
  1471. #ifndef STANDALONE_SOLVER
  1472. debug(("new_game_desc generated: \n"));
  1473. dbg_state(state);
  1474. #endif
  1475. game_state *blank = blank_game(params->w, params->h);
  1476. *aux = diff_game(blank, state, true, -1);
  1477. free_game(blank);
  1478. free_game(state);
  1479. sfree(scratch);
  1480. return desc;
  1481. }
  1482. static bool dots_too_close(game_state *state)
  1483. {
  1484. /* Quick-and-dirty check, using half the solver:
  1485. * solver_obvious will only fail if the dots are
  1486. * too close together, so dot-proximity associations
  1487. * overlap. */
  1488. game_state *tmp = dup_game(state);
  1489. int ret = solver_obvious(tmp);
  1490. free_game(tmp);
  1491. return ret == -1;
  1492. }
  1493. static game_state *load_game(const game_params *params, const char *desc,
  1494. const char **why_r)
  1495. {
  1496. game_state *state = blank_game(params->w, params->h);
  1497. const char *why = NULL;
  1498. int i, x, y, n;
  1499. unsigned int df;
  1500. i = 0;
  1501. while (*desc) {
  1502. n = *desc++;
  1503. if (n == 'z') {
  1504. i += 25;
  1505. continue;
  1506. }
  1507. if (n >= 'a' && n <= 'y') {
  1508. i += n - 'a';
  1509. df = 0;
  1510. } else if (n >= 'A' && n <= 'Y') {
  1511. i += n - 'A';
  1512. df = F_DOT_BLACK;
  1513. } else {
  1514. why = "Invalid characters in game description"; goto fail;
  1515. }
  1516. /* if we got here we incremented i and have a dot to add. */
  1517. y = (i / (state->sx-2)) + 1;
  1518. x = (i % (state->sx-2)) + 1;
  1519. if (!INUI(state, x, y)) {
  1520. why = "Too much data to fit in grid"; goto fail;
  1521. }
  1522. add_dot(&SPACE(state, x, y));
  1523. SPACE(state, x, y).flags |= df;
  1524. i++;
  1525. }
  1526. game_update_dots(state);
  1527. if (dots_too_close(state)) {
  1528. why = "Dots too close together"; goto fail;
  1529. }
  1530. return state;
  1531. fail:
  1532. free_game(state);
  1533. if (why_r) *why_r = why;
  1534. return NULL;
  1535. }
  1536. static const char *validate_desc(const game_params *params, const char *desc)
  1537. {
  1538. const char *why = NULL;
  1539. game_state *dummy = load_game(params, desc, &why);
  1540. if (dummy) {
  1541. free_game(dummy);
  1542. assert(!why);
  1543. } else
  1544. assert(why);
  1545. return why;
  1546. }
  1547. static game_state *new_game(midend *me, const game_params *params,
  1548. const char *desc)
  1549. {
  1550. game_state *state = load_game(params, desc, NULL);
  1551. if (!state) {
  1552. assert("Unable to load ?validated game.");
  1553. return NULL;
  1554. }
  1555. #ifdef EDITOR
  1556. state->me = me;
  1557. #endif
  1558. return state;
  1559. }
  1560. /* ----------------------------------------------------------
  1561. * Solver and all its little wizards.
  1562. */
  1563. #if defined DEBUGGING || defined STANDALONE_SOLVER
  1564. static int solver_recurse_depth;
  1565. #define STATIC_RECURSION_DEPTH
  1566. #endif
  1567. typedef struct solver_ctx {
  1568. game_state *state;
  1569. int sz; /* state->sx * state->sy */
  1570. space **scratch; /* size sz */
  1571. DSF *dsf; /* size sz */
  1572. int *iscratch; /* size sz */
  1573. } solver_ctx;
  1574. static solver_ctx *new_solver(game_state *state)
  1575. {
  1576. solver_ctx *sctx = snew(solver_ctx);
  1577. sctx->state = state;
  1578. sctx->sz = state->sx*state->sy;
  1579. sctx->scratch = snewn(sctx->sz, space *);
  1580. sctx->dsf = dsf_new(sctx->sz);
  1581. sctx->iscratch = snewn(sctx->sz, int);
  1582. return sctx;
  1583. }
  1584. static void free_solver(solver_ctx *sctx)
  1585. {
  1586. sfree(sctx->scratch);
  1587. dsf_free(sctx->dsf);
  1588. sfree(sctx->iscratch);
  1589. sfree(sctx);
  1590. }
  1591. /* Solver ideas so far:
  1592. *
  1593. * For any empty space, work out how many dots it could associate
  1594. * with:
  1595. * it needs line-of-sight
  1596. * it needs an empty space on the far side
  1597. * any adjacent lines need corresponding line possibilities.
  1598. */
  1599. /* The solver_ctx should keep a list of dot positions, for quicker looping.
  1600. *
  1601. * Solver techniques, in order of difficulty:
  1602. * obvious adjacency to dots
  1603. * transferring tiles to opposite side
  1604. * transferring lines to opposite side
  1605. * one possible dot for a given tile based on opposite availability
  1606. * tile with 3 definite edges next to an associated tile must associate
  1607. with same dot.
  1608. *
  1609. * one possible dot for a given tile based on line-of-sight
  1610. */
  1611. static int solver_add_assoc(game_state *state, space *tile, int dx, int dy,
  1612. const char *why)
  1613. {
  1614. space *dot, *tile_opp;
  1615. dot = &SPACE(state, dx, dy);
  1616. tile_opp = space_opposite_dot(state, tile, dot);
  1617. assert(tile->type == s_tile);
  1618. if (tile->flags & F_TILE_ASSOC) {
  1619. if ((tile->dotx != dx) || (tile->doty != dy)) {
  1620. solvep(("%*sSet %d,%d --> %d,%d (%s) impossible; "
  1621. "already --> %d,%d.\n",
  1622. solver_recurse_depth*4, "",
  1623. tile->x, tile->y, dx, dy, why,
  1624. tile->dotx, tile->doty));
  1625. return -1;
  1626. }
  1627. return 0; /* no-op */
  1628. }
  1629. if (!tile_opp) {
  1630. solvep(("%*s%d,%d --> %d,%d impossible, no opposite tile.\n",
  1631. solver_recurse_depth*4, "", tile->x, tile->y, dx, dy));
  1632. return -1;
  1633. }
  1634. if (tile_opp->flags & F_TILE_ASSOC &&
  1635. (tile_opp->dotx != dx || tile_opp->doty != dy)) {
  1636. solvep(("%*sSet %d,%d --> %d,%d (%s) impossible; "
  1637. "opposite already --> %d,%d.\n",
  1638. solver_recurse_depth*4, "",
  1639. tile->x, tile->y, dx, dy, why,
  1640. tile_opp->dotx, tile_opp->doty));
  1641. return -1;
  1642. }
  1643. add_assoc(state, tile, dot);
  1644. add_assoc(state, tile_opp, dot);
  1645. solvep(("%*sSetting %d,%d --> %d,%d (%s).\n",
  1646. solver_recurse_depth*4, "",
  1647. tile->x, tile->y,dx, dy, why));
  1648. solvep(("%*sSetting %d,%d --> %d,%d (%s, opposite).\n",
  1649. solver_recurse_depth*4, "",
  1650. tile_opp->x, tile_opp->y, dx, dy, why));
  1651. return 1;
  1652. }
  1653. static int solver_obvious_dot(game_state *state, space *dot)
  1654. {
  1655. int dx, dy, ret, didsth = 0;
  1656. space *tile;
  1657. debug(("%*ssolver_obvious_dot for %d,%d.\n",
  1658. solver_recurse_depth*4, "", dot->x, dot->y));
  1659. assert(dot->flags & F_DOT);
  1660. for (dx = -1; dx <= 1; dx++) {
  1661. for (dy = -1; dy <= 1; dy++) {
  1662. if (!INGRID(state, dot->x+dx, dot->y+dy)) continue;
  1663. tile = &SPACE(state, dot->x+dx, dot->y+dy);
  1664. if (tile->type == s_tile) {
  1665. ret = solver_add_assoc(state, tile, dot->x, dot->y,
  1666. "next to dot");
  1667. if (ret < 0) return -1;
  1668. if (ret > 0) didsth = 1;
  1669. }
  1670. }
  1671. }
  1672. return didsth;
  1673. }
  1674. static int solver_obvious(game_state *state)
  1675. {
  1676. int i, didsth = 0, ret;
  1677. debug(("%*ssolver_obvious.\n", solver_recurse_depth*4, ""));
  1678. for (i = 0; i < state->ndots; i++) {
  1679. ret = solver_obvious_dot(state, state->dots[i]);
  1680. if (ret < 0) return -1;
  1681. if (ret > 0) didsth = 1;
  1682. }
  1683. return didsth;
  1684. }
  1685. static int solver_lines_opposite_cb(game_state *state, space *edge, void *ctx)
  1686. {
  1687. int didsth = 0, n, dx, dy;
  1688. space *tiles[2], *tile_opp, *edge_opp;
  1689. assert(edge->type == s_edge);
  1690. tiles_from_edge(state, edge, tiles);
  1691. /* if tiles[0] && tiles[1] && they're both associated
  1692. * and they're both associated with different dots,
  1693. * ensure the line is set. */
  1694. if (!(edge->flags & F_EDGE_SET) &&
  1695. tiles[0] && tiles[1] &&
  1696. (tiles[0]->flags & F_TILE_ASSOC) &&
  1697. (tiles[1]->flags & F_TILE_ASSOC) &&
  1698. (tiles[0]->dotx != tiles[1]->dotx ||
  1699. tiles[0]->doty != tiles[1]->doty)) {
  1700. /* No edge, but the two adjacent tiles are both
  1701. * associated with different dots; add the edge. */
  1702. solvep(("%*sSetting edge %d,%d - tiles different dots.\n",
  1703. solver_recurse_depth*4, "", edge->x, edge->y));
  1704. edge->flags |= F_EDGE_SET;
  1705. didsth = 1;
  1706. }
  1707. if (!(edge->flags & F_EDGE_SET)) return didsth;
  1708. for (n = 0; n < 2; n++) {
  1709. if (!tiles[n]) continue;
  1710. assert(tiles[n]->type == s_tile);
  1711. if (!(tiles[n]->flags & F_TILE_ASSOC)) continue;
  1712. tile_opp = tile_opposite(state, tiles[n]);
  1713. if (!tile_opp) {
  1714. solvep(("%*simpossible: edge %d,%d has assoc. tile %d,%d"
  1715. " with no opposite.\n",
  1716. solver_recurse_depth*4, "",
  1717. edge->x, edge->y, tiles[n]->x, tiles[n]->y));
  1718. /* edge of tile has no opposite edge (off grid?);
  1719. * this is impossible. */
  1720. return -1;
  1721. }
  1722. dx = tiles[n]->x - edge->x;
  1723. dy = tiles[n]->y - edge->y;
  1724. assert(INGRID(state, tile_opp->x+dx, tile_opp->y+dy));
  1725. edge_opp = &SPACE(state, tile_opp->x+dx, tile_opp->y+dy);
  1726. if (!(edge_opp->flags & F_EDGE_SET)) {
  1727. solvep(("%*sSetting edge %d,%d as opposite %d,%d\n",
  1728. solver_recurse_depth*4, "",
  1729. tile_opp->x+dx, tile_opp->y+dy, edge->x, edge->y));
  1730. edge_opp->flags |= F_EDGE_SET;
  1731. didsth = 1;
  1732. }
  1733. }
  1734. return didsth;
  1735. }
  1736. static int solver_spaces_oneposs_cb(game_state *state, space *tile, void *ctx)
  1737. {
  1738. int n, eset, ret;
  1739. space *edgeadj[4], *tileadj[4];
  1740. int dotx, doty;
  1741. assert(tile->type == s_tile);
  1742. if (tile->flags & F_TILE_ASSOC) return 0;
  1743. adjacencies(state, tile, edgeadj, tileadj);
  1744. /* Empty tile. If each edge is either set, or associated with
  1745. * the same dot, we must also associate with dot. */
  1746. eset = 0; dotx = -1; doty = -1;
  1747. for (n = 0; n < 4; n++) {
  1748. assert(edgeadj[n]);
  1749. assert(edgeadj[n]->type == s_edge);
  1750. if (edgeadj[n]->flags & F_EDGE_SET) {
  1751. eset++;
  1752. } else {
  1753. assert(tileadj[n]);
  1754. assert(tileadj[n]->type == s_tile);
  1755. /* If an adjacent tile is empty we can't make any deductions.*/
  1756. if (!(tileadj[n]->flags & F_TILE_ASSOC))
  1757. return 0;
  1758. /* If an adjacent tile is assoc. with a different dot
  1759. * we can't make any deductions. */
  1760. if (dotx != -1 && doty != -1 &&
  1761. (tileadj[n]->dotx != dotx ||
  1762. tileadj[n]->doty != doty))
  1763. return 0;
  1764. dotx = tileadj[n]->dotx;
  1765. doty = tileadj[n]->doty;
  1766. }
  1767. }
  1768. if (eset == 4) {
  1769. solvep(("%*simpossible: empty tile %d,%d has 4 edges\n",
  1770. solver_recurse_depth*4, "",
  1771. tile->x, tile->y));
  1772. return -1;
  1773. }
  1774. assert(dotx != -1 && doty != -1);
  1775. ret = solver_add_assoc(state, tile, dotx, doty, "rest are edges");
  1776. if (ret == -1) return -1;
  1777. assert(ret != 0); /* really should have done something. */
  1778. return 1;
  1779. }
  1780. /* Improved algorithm for tracking line-of-sight from dots, and not spaces.
  1781. *
  1782. * The solver_ctx already stores a list of dots: the algorithm proceeds by
  1783. * expanding outwards from each dot in turn, expanding first to the boundary
  1784. * of its currently-connected tile and then to all empty tiles that could see
  1785. * it. Empty tiles will be flagged with a 'can see dot <x,y>' sticker.
  1786. *
  1787. * Expansion will happen by (symmetrically opposite) pairs of squares; if
  1788. * a square hasn't an opposite number there's no point trying to expand through
  1789. * it. Empty tiles will therefore also be tagged in pairs.
  1790. *
  1791. * If an empty tile already has a 'can see dot <x,y>' tag from a previous dot,
  1792. * it (and its partner) gets untagged (or, rather, a 'can see two dots' tag)
  1793. * because we're looking for single-dot possibilities.
  1794. *
  1795. * Once we've gone through all the dots, any which still have a 'can see dot'
  1796. * tag get associated with that dot (because it must have been the only one);
  1797. * any without any tag (i.e. that could see _no_ dots) cause an impossibility
  1798. * marked.
  1799. *
  1800. * The expansion will happen each time with a stored list of (space *) pairs,
  1801. * rather than a mark-and-sweep idea; that's horrifically inefficient.
  1802. *
  1803. * expansion algorithm:
  1804. *
  1805. * * allocate list of (space *) the size of s->sx*s->sy.
  1806. * * allocate second grid for (flags, dotx, doty) size of sx*sy.
  1807. *
  1808. * clear second grid (flags = 0, all dotx and doty = 0)
  1809. * flags: F_REACHABLE, F_MULTIPLE
  1810. *
  1811. *
  1812. * * for each dot, start with one pair of tiles that are associated with it --
  1813. * * vertex --> (dx+1, dy+1), (dx-1, dy-1)
  1814. * * edge --> (adj1, adj2)
  1815. * * tile --> (tile, tile) ???
  1816. * * mark that pair of tiles with F_MARK, clear all other F_MARKs.
  1817. * * add two tiles to start of list.
  1818. *
  1819. * set start = 0, end = next = 2
  1820. *
  1821. * from (start to end-1, step 2) {
  1822. * * we have two tiles (t1, t2), opposites wrt our dot.
  1823. * * for each (at1) sensible adjacent tile to t1 (i.e. not past an edge):
  1824. * * work out at2 as the opposite to at1
  1825. * * assert at1 and at2 have the same F_MARK values.
  1826. * * if at1 & F_MARK ignore it (we've been there on a previous sweep)
  1827. * * if either are associated with a different dot
  1828. * * mark both with F_MARK (so we ignore them later)
  1829. * * otherwise (assoc. with our dot, or empty):
  1830. * * mark both with F_MARK
  1831. * * add their space * values to the end of the list, set next += 2.
  1832. * }
  1833. *
  1834. * if (end == next)
  1835. * * we didn't add any new squares; exit the loop.
  1836. * else
  1837. * * set start = next+1, end = next. go round again
  1838. *
  1839. * We've finished expanding from the dot. Now, for each square we have
  1840. * in our list (--> each square with F_MARK):
  1841. * * if the tile is empty:
  1842. * * if F_REACHABLE was already set
  1843. * * set F_MULTIPLE
  1844. * * otherwise
  1845. * * set F_REACHABLE, set dotx and doty to our dot.
  1846. *
  1847. * Then, continue the whole thing for each dot in turn.
  1848. *
  1849. * Once we've done for each dot, go through the entire grid looking for
  1850. * empty tiles: for each empty tile:
  1851. * if F_REACHABLE and not F_MULTIPLE, set that dot (and its double)
  1852. * if !F_REACHABLE, return as impossible.
  1853. *
  1854. */
  1855. /* Returns true if this tile is either already associated with this dot,
  1856. * or blank. */
  1857. static bool solver_expand_checkdot(space *tile, space *dot)
  1858. {
  1859. if (!(tile->flags & F_TILE_ASSOC)) return true;
  1860. if (tile->dotx == dot->x && tile->doty == dot->y) return true;
  1861. return false;
  1862. }
  1863. static void solver_expand_fromdot(game_state *state, space *dot, solver_ctx *sctx)
  1864. {
  1865. int i, j, x, y, start, end, next;
  1866. space *sp;
  1867. /* Clear the grid of the (space) flags we'll use. */
  1868. /* This is well optimised; analysis showed that:
  1869. for (i = 0; i < sctx->sz; i++) state->grid[i].flags &= ~F_MARK;
  1870. took up ~85% of the total function time! */
  1871. for (y = 1; y < state->sy; y += 2) {
  1872. sp = &SPACE(state, 1, y);
  1873. for (x = 1; x < state->sx; x += 2, sp += 2)
  1874. sp->flags &= ~F_MARK;
  1875. }
  1876. /* Seed the list of marked squares with two that must be associated
  1877. * with our dot (possibly the same space) */
  1878. if (dot->type == s_tile) {
  1879. sctx->scratch[0] = sctx->scratch[1] = dot;
  1880. } else if (dot->type == s_edge) {
  1881. tiles_from_edge(state, dot, sctx->scratch);
  1882. } else if (dot->type == s_vertex) {
  1883. /* pick two of the opposite ones arbitrarily. */
  1884. sctx->scratch[0] = &SPACE(state, dot->x-1, dot->y-1);
  1885. sctx->scratch[1] = &SPACE(state, dot->x+1, dot->y+1);
  1886. }
  1887. assert(sctx->scratch[0]->flags & F_TILE_ASSOC);
  1888. assert(sctx->scratch[1]->flags & F_TILE_ASSOC);
  1889. sctx->scratch[0]->flags |= F_MARK;
  1890. sctx->scratch[1]->flags |= F_MARK;
  1891. debug(("%*sexpand from dot %d,%d seeded with %d,%d and %d,%d.\n",
  1892. solver_recurse_depth*4, "", dot->x, dot->y,
  1893. sctx->scratch[0]->x, sctx->scratch[0]->y,
  1894. sctx->scratch[1]->x, sctx->scratch[1]->y));
  1895. start = 0; end = 2; next = 2;
  1896. expand:
  1897. debug(("%*sexpand: start %d, end %d, next %d\n",
  1898. solver_recurse_depth*4, "", start, end, next));
  1899. for (i = start; i < end; i += 2) {
  1900. space *t1 = sctx->scratch[i]/*, *t2 = sctx->scratch[i+1]*/;
  1901. space *edges[4], *tileadj[4], *tileadj2;
  1902. adjacencies(state, t1, edges, tileadj);
  1903. for (j = 0; j < 4; j++) {
  1904. assert(edges[j]);
  1905. if (edges[j]->flags & F_EDGE_SET) continue;
  1906. assert(tileadj[j]);
  1907. if (tileadj[j]->flags & F_MARK) continue; /* seen before. */
  1908. /* We have a tile adjacent to t1; find its opposite. */
  1909. tileadj2 = space_opposite_dot(state, tileadj[j], dot);
  1910. if (!tileadj2) {
  1911. debug(("%*sMarking %d,%d, no opposite.\n",
  1912. solver_recurse_depth*4, "",
  1913. tileadj[j]->x, tileadj[j]->y));
  1914. tileadj[j]->flags |= F_MARK;
  1915. continue; /* no opposite, so mark for next time. */
  1916. }
  1917. /* If the tile had an opposite we should have either seen both of
  1918. * these, or neither of these, before. */
  1919. assert(!(tileadj2->flags & F_MARK));
  1920. if (solver_expand_checkdot(tileadj[j], dot) &&
  1921. solver_expand_checkdot(tileadj2, dot)) {
  1922. /* Both tiles could associate with this dot; add them to
  1923. * our list. */
  1924. debug(("%*sAdding %d,%d and %d,%d to possibles list.\n",
  1925. solver_recurse_depth*4, "",
  1926. tileadj[j]->x, tileadj[j]->y, tileadj2->x, tileadj2->y));
  1927. sctx->scratch[next++] = tileadj[j];
  1928. sctx->scratch[next++] = tileadj2;
  1929. }
  1930. /* Either way, we've seen these tiles already so mark them. */
  1931. debug(("%*sMarking %d,%d and %d,%d.\n",
  1932. solver_recurse_depth*4, "",
  1933. tileadj[j]->x, tileadj[j]->y, tileadj2->x, tileadj2->y));
  1934. tileadj[j]->flags |= F_MARK;
  1935. tileadj2->flags |= F_MARK;
  1936. }
  1937. }
  1938. if (next > end) {
  1939. /* We added more squares; go back and try again. */
  1940. start = end; end = next; goto expand;
  1941. }
  1942. /* We've expanded as far as we can go. Now we update the main flags
  1943. * on all tiles we've expanded into -- if they were empty, we have
  1944. * found possible associations for this dot. */
  1945. for (i = 0; i < end; i++) {
  1946. if (sctx->scratch[i]->flags & F_TILE_ASSOC) continue;
  1947. if (sctx->scratch[i]->flags & F_REACHABLE) {
  1948. /* This is (at least) the second dot this tile could
  1949. * associate with. */
  1950. debug(("%*sempty tile %d,%d could assoc. other dot %d,%d\n",
  1951. solver_recurse_depth*4, "",
  1952. sctx->scratch[i]->x, sctx->scratch[i]->y, dot->x, dot->y));
  1953. sctx->scratch[i]->flags |= F_MULTIPLE;
  1954. } else {
  1955. /* This is the first (possibly only) dot. */
  1956. debug(("%*sempty tile %d,%d could assoc. 1st dot %d,%d\n",
  1957. solver_recurse_depth*4, "",
  1958. sctx->scratch[i]->x, sctx->scratch[i]->y, dot->x, dot->y));
  1959. sctx->scratch[i]->flags |= F_REACHABLE;
  1960. sctx->scratch[i]->dotx = dot->x;
  1961. sctx->scratch[i]->doty = dot->y;
  1962. }
  1963. }
  1964. dbg_state(state);
  1965. }
  1966. static int solver_expand_postcb(game_state *state, space *tile, void *ctx)
  1967. {
  1968. assert(tile->type == s_tile);
  1969. if (tile->flags & F_TILE_ASSOC) return 0;
  1970. if (!(tile->flags & F_REACHABLE)) {
  1971. solvep(("%*simpossible: space (%d,%d) can reach no dots.\n",
  1972. solver_recurse_depth*4, "", tile->x, tile->y));
  1973. return -1;
  1974. }
  1975. if (tile->flags & F_MULTIPLE) return 0;
  1976. return solver_add_assoc(state, tile, tile->dotx, tile->doty,
  1977. "single possible dot after expansion");
  1978. }
  1979. static int solver_expand_dots(game_state *state, solver_ctx *sctx)
  1980. {
  1981. int i;
  1982. for (i = 0; i < sctx->sz; i++)
  1983. state->grid[i].flags &= ~(F_REACHABLE|F_MULTIPLE);
  1984. for (i = 0; i < state->ndots; i++)
  1985. solver_expand_fromdot(state, state->dots[i], sctx);
  1986. return foreach_tile(state, solver_expand_postcb, IMPOSSIBLE_QUITS, sctx);
  1987. }
  1988. static int solver_extend_exclaves(game_state *state, solver_ctx *sctx)
  1989. {
  1990. int x, y, done_something = 0;
  1991. /*
  1992. * Make a dsf by unifying any two adjacent tiles associated with
  1993. * the same dot. This will identify separate connected components
  1994. * of the tiles belonging to a given dot. Any such component that
  1995. * doesn't contain its own dot is an 'exclave', and will need some
  1996. * kind of path of tiles to connect it back to the dot.
  1997. */
  1998. dsf_reinit(sctx->dsf);
  1999. for (x = 1; x < state->sx; x += 2) {
  2000. for (y = 1; y < state->sy; y += 2) {
  2001. int dotx, doty;
  2002. space *tile, *othertile;
  2003. tile = &SPACE(state, x, y);
  2004. if (!(tile->flags & F_TILE_ASSOC))
  2005. continue; /* not associated with any dot */
  2006. dotx = tile->dotx;
  2007. doty = tile->doty;
  2008. if (INGRID(state, x+2, y)) {
  2009. othertile = &SPACE(state, x+2, y);
  2010. if ((othertile->flags & F_TILE_ASSOC) &&
  2011. othertile->dotx == dotx && othertile->doty == doty)
  2012. dsf_merge(sctx->dsf, y*state->sx+x, y*state->sx+(x+2));
  2013. }
  2014. if (INGRID(state, x, y+2)) {
  2015. othertile = &SPACE(state, x, y+2);
  2016. if ((othertile->flags & F_TILE_ASSOC) &&
  2017. othertile->dotx == dotx && othertile->doty == doty)
  2018. dsf_merge(sctx->dsf, y*state->sx+x, (y+2)*state->sx+x);
  2019. }
  2020. }
  2021. }
  2022. /*
  2023. * Go through the grid again, and count the 'liberties' of each
  2024. * connected component, in the Go sense, i.e. the number of
  2025. * currently unassociated squares adjacent to the component. The
  2026. * idea is that if an exclave has just one liberty, then that
  2027. * square _must_ extend the exclave, or else it will be completely
  2028. * cut off from connecting back to its home dot.
  2029. *
  2030. * We need to count each adjacent square just once, even if it
  2031. * borders the component on multiple edges. So we'll go through
  2032. * each unassociated square, check all four of its neighbours, and
  2033. * de-duplicate them.
  2034. *
  2035. * We'll store the count of liberties in the entry of iscratch
  2036. * corresponding to the square centre (i.e. with odd coordinates).
  2037. * Every time we find a liberty, we store its index in the square
  2038. * to the left of that, so that when a component has exactly one
  2039. * liberty we can remember what it was.
  2040. *
  2041. * Square centres that are not the canonical dsf element of a
  2042. * connected component will get their liberty count set to -1,
  2043. * which will allow us to identify them in the later loop (after
  2044. * we start making changes and need to spot that an associated
  2045. * square _now_ was not associated when the dsf was built).
  2046. */
  2047. /* Initialise iscratch */
  2048. for (x = 1; x < state->sx; x += 2) {
  2049. for (y = 1; y < state->sy; y += 2) {
  2050. int index = y * state->sx + x;
  2051. if (!(SPACE(state, x, y).flags & F_TILE_ASSOC) ||
  2052. dsf_canonify(sctx->dsf, index) != index) {
  2053. sctx->iscratch[index] = -1; /* mark as not a component */
  2054. } else {
  2055. sctx->iscratch[index] = 0; /* zero liberty count */
  2056. sctx->iscratch[index-1] = 0; /* initialise neighbour id */
  2057. }
  2058. }
  2059. }
  2060. /* Find each unassociated square and see what it's a liberty of */
  2061. for (x = 1; x < state->sx; x += 2) {
  2062. for (y = 1; y < state->sy; y += 2) {
  2063. int dx, dy, ni[4], nn, i;
  2064. if ((SPACE(state, x, y).flags & F_TILE_ASSOC))
  2065. continue; /* not an unassociated square */
  2066. /* Find distinct indices of adjacent components */
  2067. nn = 0;
  2068. for (dx = -1; dx <= 1; dx++) {
  2069. for (dy = -1; dy <= 1; dy++) {
  2070. if (dx != 0 && dy != 0) continue;
  2071. if (dx == 0 && dy == 0) continue;
  2072. if (INGRID(state, x+2*dx, y+2*dy) &&
  2073. (SPACE(state, x+2*dx, y+2*dy).flags & F_TILE_ASSOC)) {
  2074. /* Find id of the component adjacent to x,y */
  2075. int nindex = (y+2*dy) * state->sx + (x+2*dx);
  2076. nindex = dsf_canonify(sctx->dsf, nindex);
  2077. /* See if we've seen it before in another direction */
  2078. for (i = 0; i < nn; i++)
  2079. if (ni[i] == nindex)
  2080. break;
  2081. if (i == nn) {
  2082. /* No, it's new. Mark x,y as a liberty of it */
  2083. sctx->iscratch[nindex]++;
  2084. assert(nindex > 0);
  2085. sctx->iscratch[nindex-1] = y * state->sx + x;
  2086. /* And record this component as having been seen */
  2087. ni[nn++] = nindex;
  2088. }
  2089. }
  2090. }
  2091. }
  2092. }
  2093. }
  2094. /*
  2095. * Now we have all the data we need to find exclaves with exactly
  2096. * one liberty. In each case, associate the unique liberty square
  2097. * with the same dot.
  2098. */
  2099. for (x = 1; x < state->sx; x += 2) {
  2100. for (y = 1; y < state->sy; y += 2) {
  2101. int index, dotx, doty, ex, ey, added;
  2102. space *tile;
  2103. index = y*state->sx+x;
  2104. if (sctx->iscratch[index] == -1)
  2105. continue; /* wasn't canonical when dsf was built */
  2106. tile = &SPACE(state, x, y);
  2107. if (!(tile->flags & F_TILE_ASSOC))
  2108. continue; /* not associated with any dot */
  2109. dotx = tile->dotx;
  2110. doty = tile->doty;
  2111. if (index == dsf_canonify(
  2112. sctx->dsf, (doty | 1) * state->sx + (dotx | 1)))
  2113. continue; /* not an exclave - contains its own dot */
  2114. if (sctx->iscratch[index] == 0) {
  2115. solvep(("%*sExclave at %d,%d has no liberties!\n",
  2116. solver_recurse_depth*4, "", x, y));
  2117. return -1;
  2118. }
  2119. if (sctx->iscratch[index] != 1)
  2120. continue; /* more than one liberty, can't be sure which */
  2121. assert(sctx->iscratch[index-1] != 0);
  2122. ex = sctx->iscratch[index-1] % state->sx;
  2123. ey = sctx->iscratch[index-1] / state->sx;
  2124. tile = &SPACE(state, ex, ey);
  2125. if (tile->flags & F_TILE_ASSOC)
  2126. continue; /* already done by earlier iteration of this loop */
  2127. added = solver_add_assoc(state, tile, dotx, doty,
  2128. "to connect exclave");
  2129. if (added < 0)
  2130. return -1;
  2131. if (added > 0)
  2132. done_something = 1;
  2133. }
  2134. }
  2135. return done_something;
  2136. }
  2137. struct recurse_ctx {
  2138. space *best;
  2139. int bestn;
  2140. };
  2141. static int solver_recurse_cb(game_state *state, space *tile, void *ctx)
  2142. {
  2143. struct recurse_ctx *rctx = (struct recurse_ctx *)ctx;
  2144. int i, n = 0;
  2145. assert(tile->type == s_tile);
  2146. if (tile->flags & F_TILE_ASSOC) return 0;
  2147. /* We're unassociated: count up all the dots we could associate with. */
  2148. for (i = 0; i < state->ndots; i++) {
  2149. if (dotfortile(state, tile, state->dots[i]))
  2150. n++;
  2151. }
  2152. if (n > rctx->bestn) {
  2153. rctx->bestn = n;
  2154. rctx->best = tile;
  2155. }
  2156. return 0;
  2157. }
  2158. #define MAXRECURSE 5
  2159. static int solver_recurse(game_state *state, int maxdiff, int depth)
  2160. {
  2161. int diff = DIFF_IMPOSSIBLE, ret, n, gsz = state->sx * state->sy;
  2162. space *ingrid, *outgrid = NULL, *bestopp;
  2163. struct recurse_ctx rctx;
  2164. if (depth >= MAXRECURSE) {
  2165. solvep(("Limiting recursion to %d, returning.\n", MAXRECURSE));
  2166. return DIFF_UNFINISHED;
  2167. }
  2168. /* Work out the cell to recurse on; go through all unassociated tiles
  2169. * and find which one has the most possible dots it could associate
  2170. * with. */
  2171. rctx.best = NULL;
  2172. rctx.bestn = 0;
  2173. foreach_tile(state, solver_recurse_cb, 0, &rctx);
  2174. if (rctx.bestn == 0) return DIFF_IMPOSSIBLE; /* or assert? */
  2175. assert(rctx.best);
  2176. solvep(("%*sRecursing around %d,%d, with %d possible dots.\n",
  2177. solver_recurse_depth*4, "",
  2178. rctx.best->x, rctx.best->y, rctx.bestn));
  2179. ingrid = snewn(gsz, space);
  2180. memcpy(ingrid, state->grid, gsz * sizeof(space));
  2181. for (n = 0; n < state->ndots; n++) {
  2182. memcpy(state->grid, ingrid, gsz * sizeof(space));
  2183. if (!dotfortile(state, rctx.best, state->dots[n])) continue;
  2184. /* set cell (temporarily) pointing to that dot. */
  2185. solver_add_assoc(state, rctx.best,
  2186. state->dots[n]->x, state->dots[n]->y,
  2187. "Attempting for recursion");
  2188. ret = solver_state_inner(state, maxdiff, depth + 1);
  2189. #ifdef STATIC_RECURSION_DEPTH
  2190. solver_recurse_depth = depth; /* restore after recursion returns */
  2191. #endif
  2192. if (diff == DIFF_IMPOSSIBLE && ret != DIFF_IMPOSSIBLE) {
  2193. /* we found our first solved grid; copy it away. */
  2194. assert(!outgrid);
  2195. outgrid = snewn(gsz, space);
  2196. memcpy(outgrid, state->grid, gsz * sizeof(space));
  2197. }
  2198. /* reset cell back to unassociated. */
  2199. bestopp = tile_opposite(state, rctx.best);
  2200. assert(bestopp && bestopp->flags & F_TILE_ASSOC);
  2201. remove_assoc(state, rctx.best);
  2202. remove_assoc(state, bestopp);
  2203. if (ret == DIFF_AMBIGUOUS || ret == DIFF_UNFINISHED)
  2204. diff = ret;
  2205. else if (ret == DIFF_IMPOSSIBLE)
  2206. /* no change */;
  2207. else {
  2208. /* precisely one solution */
  2209. if (diff == DIFF_IMPOSSIBLE)
  2210. diff = DIFF_UNREASONABLE;
  2211. else
  2212. diff = DIFF_AMBIGUOUS;
  2213. }
  2214. /* if we've found >1 solution, or ran out of recursion,
  2215. * give up immediately. */
  2216. if (diff == DIFF_AMBIGUOUS || diff == DIFF_UNFINISHED)
  2217. break;
  2218. }
  2219. if (outgrid) {
  2220. /* we found (at least one) soln; copy it back to state */
  2221. memcpy(state->grid, outgrid, gsz * sizeof(space));
  2222. sfree(outgrid);
  2223. }
  2224. sfree(ingrid);
  2225. return diff;
  2226. }
  2227. static int solver_state_inner(game_state *state, int maxdiff, int depth)
  2228. {
  2229. solver_ctx *sctx = new_solver(state);
  2230. int ret, diff = DIFF_NORMAL;
  2231. #ifdef STANDALONE_PICTURE_GENERATOR
  2232. /* hack, hack: set picture to NULL during solving so that add_assoc
  2233. * won't complain when we attempt recursive guessing and guess wrong */
  2234. int *savepic = picture;
  2235. picture = NULL;
  2236. #endif
  2237. #ifdef STATIC_RECURSION_DEPTH
  2238. solver_recurse_depth = depth;
  2239. #endif
  2240. ret = solver_obvious(state);
  2241. if (ret < 0) {
  2242. diff = DIFF_IMPOSSIBLE;
  2243. goto got_result;
  2244. }
  2245. #define CHECKRET(d) do { \
  2246. if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } \
  2247. if (ret > 0) { diff = max(diff, (d)); goto cont; } \
  2248. } while(0)
  2249. while (1) {
  2250. cont:
  2251. ret = foreach_edge(state, solver_lines_opposite_cb,
  2252. IMPOSSIBLE_QUITS, sctx);
  2253. CHECKRET(DIFF_NORMAL);
  2254. ret = foreach_tile(state, solver_spaces_oneposs_cb,
  2255. IMPOSSIBLE_QUITS, sctx);
  2256. CHECKRET(DIFF_NORMAL);
  2257. ret = solver_expand_dots(state, sctx);
  2258. CHECKRET(DIFF_NORMAL);
  2259. ret = solver_extend_exclaves(state, sctx);
  2260. CHECKRET(DIFF_NORMAL);
  2261. if (maxdiff <= DIFF_NORMAL)
  2262. break;
  2263. /* harder still? */
  2264. /* if we reach here, we've made no deductions, so we terminate. */
  2265. break;
  2266. }
  2267. if (check_complete(state, NULL, NULL)) goto got_result;
  2268. diff = (maxdiff >= DIFF_UNREASONABLE) ?
  2269. solver_recurse(state, maxdiff, depth) : DIFF_UNFINISHED;
  2270. got_result:
  2271. free_solver(sctx);
  2272. #ifndef STANDALONE_SOLVER
  2273. debug(("solver_state ends, diff %s:\n", galaxies_diffnames[diff]));
  2274. dbg_state(state);
  2275. #endif
  2276. #ifdef STANDALONE_PICTURE_GENERATOR
  2277. picture = savepic;
  2278. #endif
  2279. return diff;
  2280. }
  2281. static int solver_state(game_state *state, int maxdiff)
  2282. {
  2283. return solver_state_inner(state, maxdiff, 0);
  2284. }
  2285. #ifndef EDITOR
  2286. static char *solve_game(const game_state *state, const game_state *currstate,
  2287. const char *aux, const char **error)
  2288. {
  2289. game_state *tosolve;
  2290. char *ret;
  2291. int i;
  2292. int diff;
  2293. if (aux) {
  2294. tosolve = execute_move(state, aux);
  2295. goto solved;
  2296. } else {
  2297. tosolve = dup_game(currstate);
  2298. diff = solver_state(tosolve, DIFF_UNREASONABLE);
  2299. if (diff != DIFF_UNFINISHED && diff != DIFF_IMPOSSIBLE) {
  2300. debug(("solve_game solved with current state.\n"));
  2301. goto solved;
  2302. }
  2303. free_game(tosolve);
  2304. tosolve = dup_game(state);
  2305. diff = solver_state(tosolve, DIFF_UNREASONABLE);
  2306. if (diff != DIFF_UNFINISHED && diff != DIFF_IMPOSSIBLE) {
  2307. debug(("solve_game solved with original state.\n"));
  2308. goto solved;
  2309. }
  2310. free_game(tosolve);
  2311. }
  2312. return NULL;
  2313. solved:
  2314. /*
  2315. * Clear tile associations: the solution will only include the
  2316. * edges.
  2317. */
  2318. for (i = 0; i < tosolve->sx*tosolve->sy; i++)
  2319. tosolve->grid[i].flags &= ~F_TILE_ASSOC;
  2320. ret = diff_game(currstate, tosolve, true, -1);
  2321. free_game(tosolve);
  2322. return ret;
  2323. }
  2324. #endif
  2325. /* ----------------------------------------------------------
  2326. * User interface.
  2327. */
  2328. struct game_ui {
  2329. bool dragging;
  2330. int dx, dy; /* pixel coords of drag pos. */
  2331. int dotx, doty; /* grid coords of dot we're dragging from. */
  2332. int srcx, srcy; /* grid coords of drag start */
  2333. int cur_x, cur_y;
  2334. bool cur_visible;
  2335. };
  2336. static game_ui *new_ui(const game_state *state)
  2337. {
  2338. game_ui *ui = snew(game_ui);
  2339. ui->dragging = false;
  2340. ui->cur_x = ui->cur_y = 1;
  2341. ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
  2342. return ui;
  2343. }
  2344. static void free_ui(game_ui *ui)
  2345. {
  2346. sfree(ui);
  2347. }
  2348. static void game_changed_state(game_ui *ui, const game_state *oldstate,
  2349. const game_state *newstate)
  2350. {
  2351. }
  2352. #define FLASH_TIME 0.15F
  2353. #define PREFERRED_TILE_SIZE 32
  2354. #define TILE_SIZE (ds->tilesize)
  2355. #define DOT_SIZE (TILE_SIZE / 4)
  2356. #define EDGE_THICKNESS (max(TILE_SIZE / 16, 2))
  2357. #define BORDER TILE_SIZE
  2358. #define COORD(x) ( (x) * TILE_SIZE + BORDER )
  2359. #define SCOORD(x) ( ((x) * TILE_SIZE)/2 + BORDER )
  2360. #define FROMCOORD(x) ( ((x) - BORDER) / TILE_SIZE )
  2361. #define DRAW_WIDTH (BORDER * 2 + ds->w * TILE_SIZE)
  2362. #define DRAW_HEIGHT (BORDER * 2 + ds->h * TILE_SIZE)
  2363. #define CURSOR_SIZE DOT_SIZE
  2364. struct game_drawstate {
  2365. bool started;
  2366. int w, h;
  2367. int tilesize;
  2368. unsigned long *grid;
  2369. int *dx, *dy;
  2370. blitter *bl;
  2371. blitter *blmirror;
  2372. bool dragging;
  2373. int dragx, dragy, oppx, oppy;
  2374. int *colour_scratch;
  2375. int cx, cy;
  2376. bool cur_visible;
  2377. blitter *cur_bl;
  2378. };
  2379. #define CORNER_TOLERANCE 0.15F
  2380. #define CENTRE_TOLERANCE 0.15F
  2381. /*
  2382. * Round FP coordinates to the centre of the nearest edge.
  2383. */
  2384. #ifndef EDITOR
  2385. static void coord_round_to_edge(float x, float y, int *xr, int *yr)
  2386. {
  2387. float xs, ys, xv, yv, dx, dy;
  2388. /*
  2389. * Find the nearest square-centre.
  2390. */
  2391. xs = (float)floor(x) + 0.5F;
  2392. ys = (float)floor(y) + 0.5F;
  2393. /*
  2394. * Find the nearest grid vertex.
  2395. */
  2396. xv = (float)floor(x + 0.5F);
  2397. yv = (float)floor(y + 0.5F);
  2398. /*
  2399. * Determine whether the horizontal or vertical edge from that
  2400. * vertex alongside that square is closer to us, by comparing
  2401. * distances from the square cente.
  2402. */
  2403. dx = (float)fabs(x - xs);
  2404. dy = (float)fabs(y - ys);
  2405. if (dx > dy) {
  2406. /* Vertical edge: x-coord of corner,
  2407. * y-coord of square centre. */
  2408. *xr = 2 * (int)xv;
  2409. *yr = 1 + 2 * (int)floor(ys);
  2410. } else {
  2411. /* Horizontal edge: x-coord of square centre,
  2412. * y-coord of corner. */
  2413. *xr = 1 + 2 * (int)floor(xs);
  2414. *yr = 2 * (int)yv;
  2415. }
  2416. }
  2417. #endif
  2418. #ifdef EDITOR
  2419. static char *interpret_move(const game_state *state, game_ui *ui,
  2420. const game_drawstate *ds,
  2421. int x, int y, int button)
  2422. {
  2423. char buf[80];
  2424. int px, py;
  2425. space *sp;
  2426. px = 2*FROMCOORD((float)x) + 0.5F;
  2427. py = 2*FROMCOORD((float)y) + 0.5F;
  2428. if (button == 'C' || button == 'c') return dupstr("C");
  2429. if (button == 'S' || button == 's') {
  2430. char *ret;
  2431. game_state *tmp = dup_game(state);
  2432. int cdiff = solver_state(tmp, DIFF_UNREASONABLE-1);
  2433. ret = diff_game(state, tmp, 0, cdiff);
  2434. free_game(tmp);
  2435. return ret;
  2436. }
  2437. if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
  2438. if (!INUI(state, px, py)) return MOVE_UNUSED;
  2439. sp = &SPACE(state, px, py);
  2440. if (!dot_is_possible(state, sp, 1)) return MOVE_NO_EFFECT;
  2441. sprintf(buf, "%c%d,%d",
  2442. (char)((button == LEFT_BUTTON) ? 'D' : 'd'), px, py);
  2443. return dupstr(buf);
  2444. }
  2445. return MOVE_UNUSED;
  2446. }
  2447. #else
  2448. static bool edge_placement_legal(const game_state *state, int x, int y)
  2449. {
  2450. space *sp = &SPACE(state, x, y);
  2451. if (sp->type != s_edge)
  2452. return false; /* this is a face-centre or a grid vertex */
  2453. /* Check this line doesn't actually intersect a dot */
  2454. unsigned int flags = (GRID(state, grid, x, y).flags |
  2455. GRID(state, grid, x & ~1U, y & ~1U).flags |
  2456. GRID(state, grid, (x+1) & ~1U, (y+1) & ~1U).flags);
  2457. if (flags & F_DOT)
  2458. return false;
  2459. return true;
  2460. }
  2461. static const char *current_key_label(const game_ui *ui,
  2462. const game_state *state, int button)
  2463. {
  2464. space *sp;
  2465. if (IS_CURSOR_SELECT(button) && ui->cur_visible) {
  2466. sp = &SPACE(state, ui->cur_x, ui->cur_y);
  2467. if (ui->dragging) {
  2468. if (ui->cur_x == ui->srcx && ui->cur_y == ui->srcy)
  2469. return "Cancel";
  2470. if (ok_to_add_assoc_with_opposite(
  2471. state, &SPACE(state, ui->cur_x, ui->cur_y),
  2472. &SPACE(state, ui->dotx, ui->doty)))
  2473. return "Place";
  2474. return (ui->srcx == ui->dotx && ui->srcy == ui->doty) ?
  2475. "Cancel" : "Remove";
  2476. } else if (sp->flags & F_DOT)
  2477. return "New arrow";
  2478. else if (sp->flags & F_TILE_ASSOC)
  2479. return "Move arrow";
  2480. else if (sp->type == s_edge &&
  2481. edge_placement_legal(state, ui->cur_x, ui->cur_y))
  2482. return (sp->flags & F_EDGE_SET) ? "Clear" : "Edge";
  2483. }
  2484. return "";
  2485. }
  2486. static char *interpret_move(const game_state *state, game_ui *ui,
  2487. const game_drawstate *ds,
  2488. int x, int y, int button)
  2489. {
  2490. /* UI operations (play mode):
  2491. *
  2492. * Toggle edge (set/unset) (left-click on edge)
  2493. * Associate space with dot (left-drag from dot)
  2494. * Unassociate space (left-drag from space off grid)
  2495. * Autofill lines around shape? (right-click?)
  2496. *
  2497. * (edit mode; will clear all lines/associations)
  2498. *
  2499. * Add or remove dot (left-click)
  2500. */
  2501. char buf[80];
  2502. const char *sep = "";
  2503. int px, py;
  2504. space *sp, *dot;
  2505. buf[0] = '\0';
  2506. if (button == 'H' || button == 'h') {
  2507. char *ret;
  2508. game_state *tmp = dup_game(state);
  2509. solver_obvious(tmp);
  2510. ret = diff_game(state, tmp, false, -1);
  2511. free_game(tmp);
  2512. return ret;
  2513. }
  2514. if (button == LEFT_BUTTON) {
  2515. ui->cur_visible = false;
  2516. coord_round_to_edge(FROMCOORD((float)x), FROMCOORD((float)y),
  2517. &px, &py);
  2518. if (!INUI(state, px, py)) return MOVE_UNUSED;
  2519. if (!edge_placement_legal(state, px, py))
  2520. return MOVE_NO_EFFECT;
  2521. sprintf(buf, "E%d,%d", px, py);
  2522. return dupstr(buf);
  2523. } else if (button == RIGHT_BUTTON) {
  2524. int px1, py1;
  2525. ui->cur_visible = false;
  2526. px = (int)(2*FROMCOORD((float)x) + 0.5F);
  2527. py = (int)(2*FROMCOORD((float)y) + 0.5F);
  2528. dot = NULL;
  2529. /*
  2530. * If there's a dot anywhere nearby, we pick up an arrow
  2531. * pointing at that dot.
  2532. */
  2533. for (py1 = py-1; py1 <= py+1; py1++)
  2534. for (px1 = px-1; px1 <= px+1; px1++) {
  2535. if (px1 >= 0 && px1 < state->sx &&
  2536. py1 >= 0 && py1 < state->sy &&
  2537. x >= SCOORD(px1-1) && x < SCOORD(px1+1) &&
  2538. y >= SCOORD(py1-1) && y < SCOORD(py1+1) &&
  2539. SPACE(state, px1, py1).flags & F_DOT) {
  2540. /*
  2541. * Found a dot. Begin a drag from it.
  2542. */
  2543. dot = &SPACE(state, px1, py1);
  2544. ui->srcx = px1;
  2545. ui->srcy = py1;
  2546. goto done; /* multi-level break */
  2547. }
  2548. }
  2549. /*
  2550. * Otherwise, find the nearest _square_, and pick up the
  2551. * same arrow as it's got on it, if any.
  2552. */
  2553. if (!dot) {
  2554. px = 2*FROMCOORD(x+TILE_SIZE) - 1;
  2555. py = 2*FROMCOORD(y+TILE_SIZE) - 1;
  2556. if (px >= 0 && px < state->sx && py >= 0 && py < state->sy) {
  2557. sp = &SPACE(state, px, py);
  2558. if (sp->flags & F_TILE_ASSOC) {
  2559. dot = &SPACE(state, sp->dotx, sp->doty);
  2560. ui->srcx = px;
  2561. ui->srcy = py;
  2562. }
  2563. }
  2564. }
  2565. done:
  2566. /*
  2567. * Now, if we've managed to find a dot, begin a drag.
  2568. */
  2569. if (dot) {
  2570. ui->dragging = true;
  2571. ui->dx = x;
  2572. ui->dy = y;
  2573. ui->dotx = dot->x;
  2574. ui->doty = dot->y;
  2575. return MOVE_UI_UPDATE;
  2576. }
  2577. return MOVE_NO_EFFECT;
  2578. } else if (button == RIGHT_DRAG && ui->dragging) {
  2579. /* just move the drag coords. */
  2580. ui->dx = x;
  2581. ui->dy = y;
  2582. return MOVE_UI_UPDATE;
  2583. } else if (button == RIGHT_RELEASE && ui->dragging) {
  2584. /*
  2585. * Drags are always targeted at a single square.
  2586. */
  2587. px = 2*FROMCOORD(x+TILE_SIZE) - 1;
  2588. py = 2*FROMCOORD(y+TILE_SIZE) - 1;
  2589. dropped: /* We arrive here from the end of a keyboard drag. */
  2590. ui->dragging = false;
  2591. /*
  2592. * Dragging an arrow on to the same square it started from
  2593. * is a null move; just update the ui and finish.
  2594. */
  2595. if (px == ui->srcx && py == ui->srcy)
  2596. return MOVE_UI_UPDATE;
  2597. /*
  2598. * Otherwise, we remove the arrow from its starting
  2599. * square if we didn't start from a dot...
  2600. */
  2601. if ((ui->srcx != ui->dotx || ui->srcy != ui->doty) &&
  2602. SPACE(state, ui->srcx, ui->srcy).flags & F_TILE_ASSOC) {
  2603. sprintf(buf + strlen(buf), "%sU%d,%d", sep, ui->srcx, ui->srcy);
  2604. sep = ";";
  2605. }
  2606. /*
  2607. * ... and if the square we're moving it _to_ is valid, we
  2608. * add one there instead.
  2609. */
  2610. if (INUI(state, px, py)) {
  2611. sp = &SPACE(state, px, py);
  2612. dot = &SPACE(state, ui->dotx, ui->doty);
  2613. /*
  2614. * Exception: if it's not actually legal to add an arrow
  2615. * and its opposite at this position, we don't try,
  2616. * because otherwise we'd append an empty entry to the
  2617. * undo chain.
  2618. */
  2619. if (ok_to_add_assoc_with_opposite(state, sp, dot))
  2620. sprintf(buf + strlen(buf), "%sA%d,%d,%d,%d",
  2621. sep, px, py, ui->dotx, ui->doty);
  2622. }
  2623. if (buf[0])
  2624. return dupstr(buf);
  2625. else
  2626. return MOVE_UI_UPDATE;
  2627. } else if (IS_CURSOR_MOVE(button)) {
  2628. move_cursor(button, &ui->cur_x, &ui->cur_y, state->sx-1, state->sy-1, false);
  2629. if (ui->cur_x < 1) ui->cur_x = 1;
  2630. if (ui->cur_y < 1) ui->cur_y = 1;
  2631. ui->cur_visible = true;
  2632. if (ui->dragging) {
  2633. ui->dx = SCOORD(ui->cur_x);
  2634. ui->dy = SCOORD(ui->cur_y);
  2635. }
  2636. return MOVE_UI_UPDATE;
  2637. } else if (IS_CURSOR_SELECT(button)) {
  2638. if (!ui->cur_visible) {
  2639. ui->cur_visible = true;
  2640. return MOVE_UI_UPDATE;
  2641. }
  2642. sp = &SPACE(state, ui->cur_x, ui->cur_y);
  2643. if (ui->dragging) {
  2644. px = ui->cur_x; py = ui->cur_y;
  2645. goto dropped;
  2646. } else if (sp->flags & F_DOT) {
  2647. ui->dragging = true;
  2648. ui->dx = SCOORD(ui->cur_x);
  2649. ui->dy = SCOORD(ui->cur_y);
  2650. ui->dotx = ui->srcx = ui->cur_x;
  2651. ui->doty = ui->srcy = ui->cur_y;
  2652. return MOVE_UI_UPDATE;
  2653. } else if (sp->flags & F_TILE_ASSOC) {
  2654. assert(sp->type == s_tile);
  2655. ui->dragging = true;
  2656. ui->dx = SCOORD(ui->cur_x);
  2657. ui->dy = SCOORD(ui->cur_y);
  2658. ui->dotx = sp->dotx;
  2659. ui->doty = sp->doty;
  2660. ui->srcx = ui->cur_x;
  2661. ui->srcy = ui->cur_y;
  2662. return MOVE_UI_UPDATE;
  2663. } else if (sp->type == s_edge &&
  2664. edge_placement_legal(state, ui->cur_x, ui->cur_y)) {
  2665. sprintf(buf, "E%d,%d", ui->cur_x, ui->cur_y);
  2666. return dupstr(buf);
  2667. }
  2668. }
  2669. return MOVE_UNUSED;
  2670. }
  2671. #endif
  2672. static bool check_complete(const game_state *state, DSF *dsf, int *colours)
  2673. {
  2674. int w = state->w, h = state->h;
  2675. int x, y, i;
  2676. bool ret;
  2677. bool free_dsf;
  2678. struct sqdata {
  2679. int minx, miny, maxx, maxy;
  2680. int cx, cy;
  2681. bool valid;
  2682. int colour;
  2683. } *sqdata;
  2684. if (!dsf) {
  2685. dsf = dsf_new(w*h);
  2686. free_dsf = true;
  2687. } else {
  2688. dsf_reinit(dsf);
  2689. free_dsf = false;
  2690. }
  2691. /*
  2692. * During actual game play, completion checking is done on the
  2693. * basis of the edges rather than the square associations. So
  2694. * first we must go through the grid figuring out the connected
  2695. * components into which the edges divide it.
  2696. */
  2697. for (y = 0; y < h; y++)
  2698. for (x = 0; x < w; x++) {
  2699. if (y+1 < h && !(SPACE(state, 2*x+1, 2*y+2).flags & F_EDGE_SET))
  2700. dsf_merge(dsf, y*w+x, (y+1)*w+x);
  2701. if (x+1 < w && !(SPACE(state, 2*x+2, 2*y+1).flags & F_EDGE_SET))
  2702. dsf_merge(dsf, y*w+x, y*w+(x+1));
  2703. }
  2704. /*
  2705. * That gives us our connected components. Now, for each
  2706. * component, decide whether it's _valid_. A valid component is
  2707. * one which:
  2708. *
  2709. * - is 180-degree rotationally symmetric
  2710. * - has a dot at its centre of symmetry
  2711. * - has no other dots anywhere within it (including on its
  2712. * boundary)
  2713. * - contains no internal edges (i.e. edges separating two
  2714. * squares which are both part of the component).
  2715. */
  2716. /*
  2717. * First, go through the grid finding the bounding box of each
  2718. * component.
  2719. */
  2720. sqdata = snewn(w*h, struct sqdata);
  2721. for (i = 0; i < w*h; i++) {
  2722. sqdata[i].minx = w+1;
  2723. sqdata[i].miny = h+1;
  2724. sqdata[i].maxx = sqdata[i].maxy = -1;
  2725. sqdata[i].valid = false;
  2726. }
  2727. for (y = 0; y < h; y++)
  2728. for (x = 0; x < w; x++) {
  2729. i = dsf_canonify(dsf, y*w+x);
  2730. if (sqdata[i].minx > x)
  2731. sqdata[i].minx = x;
  2732. if (sqdata[i].maxx < x)
  2733. sqdata[i].maxx = x;
  2734. if (sqdata[i].miny > y)
  2735. sqdata[i].miny = y;
  2736. if (sqdata[i].maxy < y)
  2737. sqdata[i].maxy = y;
  2738. sqdata[i].valid = true;
  2739. }
  2740. /*
  2741. * Now we're in a position to loop over each actual component
  2742. * and figure out where its centre of symmetry has to be if
  2743. * it's anywhere.
  2744. */
  2745. for (i = 0; i < w*h; i++)
  2746. if (sqdata[i].valid) {
  2747. int cx, cy;
  2748. cx = sqdata[i].cx = sqdata[i].minx + sqdata[i].maxx + 1;
  2749. cy = sqdata[i].cy = sqdata[i].miny + sqdata[i].maxy + 1;
  2750. if (!(SPACE(state, sqdata[i].cx, sqdata[i].cy).flags & F_DOT))
  2751. sqdata[i].valid = false; /* no dot at centre of symmetry */
  2752. if (dsf_canonify(dsf, (cy-1)/2*w+(cx-1)/2) != i ||
  2753. dsf_canonify(dsf, (cy)/2*w+(cx-1)/2) != i ||
  2754. dsf_canonify(dsf, (cy-1)/2*w+(cx)/2) != i ||
  2755. dsf_canonify(dsf, (cy)/2*w+(cx)/2) != i)
  2756. sqdata[i].valid = false; /* dot at cx,cy isn't ours */
  2757. if (SPACE(state, sqdata[i].cx, sqdata[i].cy).flags & F_DOT_BLACK)
  2758. sqdata[i].colour = 2;
  2759. else
  2760. sqdata[i].colour = 1;
  2761. }
  2762. /*
  2763. * Now we loop over the whole grid again, this time finding
  2764. * extraneous dots (any dot which wholly or partially overlaps
  2765. * a square and is not at the centre of symmetry of that
  2766. * square's component disqualifies the component from validity)
  2767. * and extraneous edges (any edge separating two squares
  2768. * belonging to the same component also disqualifies that
  2769. * component).
  2770. */
  2771. for (y = 1; y < state->sy-1; y++)
  2772. for (x = 1; x < state->sx-1; x++) {
  2773. space *sp = &SPACE(state, x, y);
  2774. if (sp->flags & F_DOT) {
  2775. /*
  2776. * There's a dot here. Use it to disqualify any
  2777. * component which deserves it.
  2778. */
  2779. int cx, cy;
  2780. for (cy = (y-1) >> 1; cy <= y >> 1; cy++)
  2781. for (cx = (x-1) >> 1; cx <= x >> 1; cx++) {
  2782. i = dsf_canonify(dsf, cy*w+cx);
  2783. if (x != sqdata[i].cx || y != sqdata[i].cy)
  2784. sqdata[i].valid = false;
  2785. }
  2786. }
  2787. if (sp->flags & F_EDGE_SET) {
  2788. /*
  2789. * There's an edge here. Use it to disqualify a
  2790. * component if necessary.
  2791. */
  2792. int cx1 = (x-1) >> 1, cx2 = x >> 1;
  2793. int cy1 = (y-1) >> 1, cy2 = y >> 1;
  2794. assert((cx1==cx2) ^ (cy1==cy2));
  2795. i = dsf_canonify(dsf, cy1*w+cx1);
  2796. if (i == dsf_canonify(dsf, cy2*w+cx2))
  2797. sqdata[i].valid = false;
  2798. }
  2799. }
  2800. /*
  2801. * And finally we test rotational symmetry: for each square in
  2802. * the grid, find which component it's in, test that that
  2803. * component also has a square in the symmetric position, and
  2804. * disqualify it if it doesn't.
  2805. */
  2806. for (y = 0; y < h; y++)
  2807. for (x = 0; x < w; x++) {
  2808. int x2, y2;
  2809. i = dsf_canonify(dsf, y*w+x);
  2810. x2 = sqdata[i].cx - 1 - x;
  2811. y2 = sqdata[i].cy - 1 - y;
  2812. if (i != dsf_canonify(dsf, y2*w+x2))
  2813. sqdata[i].valid = false;
  2814. }
  2815. /*
  2816. * That's it. We now have all the connected components marked
  2817. * as valid or not valid. So now we return a `colours' array if
  2818. * we were asked for one, and also we return an overall
  2819. * true/false value depending on whether _every_ square in the
  2820. * grid is part of a valid component.
  2821. */
  2822. ret = true;
  2823. for (i = 0; i < w*h; i++) {
  2824. int ci = dsf_canonify(dsf, i);
  2825. bool thisok = sqdata[ci].valid;
  2826. if (colours)
  2827. colours[i] = thisok ? sqdata[ci].colour : 0;
  2828. ret = ret && thisok;
  2829. }
  2830. sfree(sqdata);
  2831. if (free_dsf)
  2832. dsf_free(dsf);
  2833. return ret;
  2834. }
  2835. static game_state *execute_move(const game_state *state, const char *move)
  2836. {
  2837. int x, y, ax, ay, n, dx, dy;
  2838. game_state *ret = dup_game(state);
  2839. space *sp, *dot;
  2840. bool currently_solving = false;
  2841. debug(("%s\n", move));
  2842. while (*move) {
  2843. char c = *move;
  2844. if (c == 'E' || c == 'U' || c == 'M'
  2845. #ifdef EDITOR
  2846. || c == 'D' || c == 'd'
  2847. #endif
  2848. ) {
  2849. move++;
  2850. if (sscanf(move, "%d,%d%n", &x, &y, &n) != 2 ||
  2851. !INUI(ret, x, y))
  2852. goto badmove;
  2853. sp = &SPACE(ret, x, y);
  2854. #ifdef EDITOR
  2855. if (c == 'D' || c == 'd') {
  2856. unsigned int currf, newf, maskf;
  2857. if (!dot_is_possible(ret, sp, 1)) goto badmove;
  2858. newf = F_DOT | (c == 'd' ? F_DOT_BLACK : 0);
  2859. currf = GRID(ret, grid, x, y).flags;
  2860. maskf = F_DOT | F_DOT_BLACK;
  2861. /* if we clicked 'white dot':
  2862. * white --> empty, empty --> white, black --> white.
  2863. * if we clicked 'black dot':
  2864. * black --> empty, empty --> black, white --> black.
  2865. */
  2866. if (currf & maskf) {
  2867. sp->flags &= ~maskf;
  2868. if ((currf & maskf) != newf)
  2869. sp->flags |= newf;
  2870. } else
  2871. sp->flags |= newf;
  2872. sp->nassoc = 0; /* edit-mode disallows associations. */
  2873. game_update_dots(ret);
  2874. } else
  2875. #endif
  2876. if (c == 'E') {
  2877. if (sp->type != s_edge) goto badmove;
  2878. sp->flags ^= F_EDGE_SET;
  2879. } else if (c == 'U') {
  2880. if (sp->type != s_tile || !(sp->flags & F_TILE_ASSOC))
  2881. goto badmove;
  2882. /* The solver doesn't assume we'll mirror things */
  2883. if (currently_solving)
  2884. remove_assoc(ret, sp);
  2885. else
  2886. remove_assoc_with_opposite(ret, sp);
  2887. } else if (c == 'M') {
  2888. if (!(sp->flags & F_DOT)) goto badmove;
  2889. sp->flags ^= F_DOT_HOLD;
  2890. }
  2891. move += n;
  2892. } else if (c == 'A' || c == 'a') {
  2893. move++;
  2894. if (sscanf(move, "%d,%d,%d,%d%n", &x, &y, &ax, &ay, &n) != 4 ||
  2895. x < 1 || y < 1 || x >= (ret->sx-1) || y >= (ret->sy-1) ||
  2896. ax < 1 || ay < 1 || ax >= (ret->sx-1) || ay >= (ret->sy-1))
  2897. goto badmove;
  2898. dot = &GRID(ret, grid, ax, ay);
  2899. if (!(dot->flags & F_DOT))goto badmove;
  2900. if (dot->flags & F_DOT_HOLD) goto badmove;
  2901. for (dx = -1; dx <= 1; dx++) {
  2902. for (dy = -1; dy <= 1; dy++) {
  2903. sp = &GRID(ret, grid, x+dx, y+dy);
  2904. if (sp->type != s_tile) continue;
  2905. if (sp->flags & F_TILE_ASSOC) {
  2906. space *dot = &SPACE(ret, sp->dotx, sp->doty);
  2907. if (dot->flags & F_DOT_HOLD) continue;
  2908. }
  2909. /* The solver doesn't assume we'll mirror things */
  2910. if (currently_solving)
  2911. add_assoc(ret, sp, dot);
  2912. else
  2913. add_assoc_with_opposite(ret, sp, dot);
  2914. }
  2915. }
  2916. move += n;
  2917. #ifdef EDITOR
  2918. } else if (c == 'C') {
  2919. move++;
  2920. clear_game(ret, true);
  2921. } else if (c == 'i') {
  2922. int diff;
  2923. move++;
  2924. for (diff = 0; diff <= DIFF_UNREASONABLE; diff++)
  2925. if (*move == galaxies_diffchars[diff])
  2926. break;
  2927. if (diff > DIFF_UNREASONABLE)
  2928. goto badmove;
  2929. ret->cdiff = diff;
  2930. move++;
  2931. } else if (c == 'I') {
  2932. int diff;
  2933. move++;
  2934. switch (*move) {
  2935. case 'A':
  2936. diff = DIFF_AMBIGUOUS;
  2937. break;
  2938. case 'I':
  2939. diff = DIFF_IMPOSSIBLE;
  2940. break;
  2941. case 'U':
  2942. diff = DIFF_UNFINISHED;
  2943. break;
  2944. default:
  2945. goto badmove;
  2946. }
  2947. ret->cdiff = diff;
  2948. move++;
  2949. #endif
  2950. } else if (c == 'S') {
  2951. move++;
  2952. ret->used_solve = true;
  2953. currently_solving = true;
  2954. } else
  2955. goto badmove;
  2956. if (*move == ';')
  2957. move++;
  2958. else if (*move)
  2959. goto badmove;
  2960. }
  2961. if (check_complete(ret, NULL, NULL))
  2962. ret->completed = true;
  2963. return ret;
  2964. badmove:
  2965. free_game(ret);
  2966. return NULL;
  2967. }
  2968. /* ----------------------------------------------------------------------
  2969. * Drawing routines.
  2970. */
  2971. /* Lines will be much smaller size than squares; say, 1/8 the size?
  2972. *
  2973. * Need a 'top-left corner of location XxY' to take this into account;
  2974. * alternaticaly, that could give the middle of that location, and the
  2975. * drawing code would just know the expected dimensions.
  2976. *
  2977. * We also need something to take a click and work out what it was
  2978. * we were interested in. Clicking on vertices is required because
  2979. * we may want to drag from them, for example.
  2980. */
  2981. static void game_compute_size(const game_params *params, int sz,
  2982. const game_ui *ui, int *x, int *y)
  2983. {
  2984. struct { int tilesize, w, h; } ads, *ds = &ads;
  2985. ds->tilesize = sz;
  2986. ds->w = params->w;
  2987. ds->h = params->h;
  2988. *x = DRAW_WIDTH;
  2989. *y = DRAW_HEIGHT;
  2990. }
  2991. static void game_set_size(drawing *dr, game_drawstate *ds,
  2992. const game_params *params, int sz)
  2993. {
  2994. ds->tilesize = sz;
  2995. assert(TILE_SIZE > 0);
  2996. assert(!ds->bl);
  2997. ds->bl = blitter_new(dr, TILE_SIZE, TILE_SIZE);
  2998. assert(!ds->blmirror);
  2999. ds->blmirror = blitter_new(dr, TILE_SIZE, TILE_SIZE);
  3000. assert(!ds->cur_bl);
  3001. ds->cur_bl = blitter_new(dr, TILE_SIZE, TILE_SIZE);
  3002. }
  3003. static float *game_colours(frontend *fe, int *ncolours)
  3004. {
  3005. float *ret = snewn(3 * NCOLOURS, float);
  3006. int i;
  3007. /*
  3008. * We call game_mkhighlight to ensure the background colour
  3009. * isn't completely white. We don't actually use the high- and
  3010. * lowlight colours it generates.
  3011. */
  3012. game_mkhighlight(fe, ret, COL_BACKGROUND, COL_WHITEBG, COL_BLACKBG);
  3013. for (i = 0; i < 3; i++) {
  3014. /*
  3015. * Currently, white dots and white-background squares are
  3016. * both pure white.
  3017. */
  3018. ret[COL_WHITEDOT * 3 + i] = 1.0F;
  3019. ret[COL_WHITEBG * 3 + i] = 1.0F;
  3020. /*
  3021. * But black-background squares are a dark grey, whereas
  3022. * black dots are really black.
  3023. */
  3024. ret[COL_BLACKDOT * 3 + i] = 0.0F;
  3025. ret[COL_BLACKBG * 3 + i] = ret[COL_BACKGROUND * 3 + i] * 0.3F;
  3026. /*
  3027. * In unfilled squares, we draw a faint gridwork.
  3028. */
  3029. ret[COL_GRID * 3 + i] = ret[COL_BACKGROUND * 3 + i] * 0.8F;
  3030. /*
  3031. * Edges and arrows are filled in in pure black.
  3032. */
  3033. ret[COL_EDGE * 3 + i] = 0.0F;
  3034. ret[COL_ARROW * 3 + i] = 0.0F;
  3035. }
  3036. #ifdef EDITOR
  3037. /* tinge the edit background to bluey */
  3038. ret[COL_BACKGROUND * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.8F;
  3039. ret[COL_BACKGROUND * 3 + 1] = ret[COL_BACKGROUND * 3 + 0] * 0.8F;
  3040. ret[COL_BACKGROUND * 3 + 2] = min(ret[COL_BACKGROUND * 3 + 0] * 1.4F, 1.0F);
  3041. #endif
  3042. ret[COL_CURSOR * 3 + 0] = min(ret[COL_BACKGROUND * 3 + 0] * 1.4F, 1.0F);
  3043. ret[COL_CURSOR * 3 + 1] = ret[COL_BACKGROUND * 3 + 0] * 0.8F;
  3044. ret[COL_CURSOR * 3 + 2] = ret[COL_BACKGROUND * 3 + 0] * 0.8F;
  3045. *ncolours = NCOLOURS;
  3046. return ret;
  3047. }
  3048. static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
  3049. {
  3050. struct game_drawstate *ds = snew(struct game_drawstate);
  3051. int i;
  3052. ds->started = false;
  3053. ds->w = state->w;
  3054. ds->h = state->h;
  3055. ds->grid = snewn(ds->w*ds->h, unsigned long);
  3056. for (i = 0; i < ds->w*ds->h; i++)
  3057. ds->grid[i] = 0xFFFFFFFFUL;
  3058. ds->dx = snewn(ds->w*ds->h, int);
  3059. ds->dy = snewn(ds->w*ds->h, int);
  3060. ds->bl = NULL;
  3061. ds->blmirror = NULL;
  3062. ds->dragging = false;
  3063. ds->dragx = ds->dragy = ds->oppx = ds->oppy = 0;
  3064. ds->colour_scratch = snewn(ds->w * ds->h, int);
  3065. ds->cur_bl = NULL;
  3066. ds->cx = ds->cy = 0;
  3067. ds->cur_visible = false;
  3068. return ds;
  3069. }
  3070. static void game_free_drawstate(drawing *dr, game_drawstate *ds)
  3071. {
  3072. if (ds->cur_bl) blitter_free(dr, ds->cur_bl);
  3073. sfree(ds->colour_scratch);
  3074. if (ds->blmirror) blitter_free(dr, ds->blmirror);
  3075. if (ds->bl) blitter_free(dr, ds->bl);
  3076. sfree(ds->dx);
  3077. sfree(ds->dy);
  3078. sfree(ds->grid);
  3079. sfree(ds);
  3080. }
  3081. #define DRAW_EDGE_L 0x0001
  3082. #define DRAW_EDGE_R 0x0002
  3083. #define DRAW_EDGE_U 0x0004
  3084. #define DRAW_EDGE_D 0x0008
  3085. #define DRAW_CORNER_UL 0x0010
  3086. #define DRAW_CORNER_UR 0x0020
  3087. #define DRAW_CORNER_DL 0x0040
  3088. #define DRAW_CORNER_DR 0x0080
  3089. #define DRAW_WHITE 0x0100
  3090. #define DRAW_BLACK 0x0200
  3091. #define DRAW_ARROW 0x0400
  3092. #define DRAW_CURSOR 0x0800
  3093. #define DOT_SHIFT_C 12
  3094. #define DOT_SHIFT_M 2
  3095. #define DOT_WHITE 1UL
  3096. #define DOT_BLACK 2UL
  3097. /*
  3098. * Draw an arrow centred on (cx,cy), pointing in the direction
  3099. * (ddx,ddy). (I.e. pointing at the point (cx+ddx, cy+ddy).
  3100. */
  3101. static void draw_arrow(drawing *dr, game_drawstate *ds,
  3102. int cx, int cy, int ddx, int ddy, int col)
  3103. {
  3104. int sqdist = ddx*ddx+ddy*ddy;
  3105. if (sqdist == 0)
  3106. return; /* avoid division by zero */
  3107. float vlen = (float)sqrt(sqdist);
  3108. float xdx = ddx/vlen, xdy = ddy/vlen;
  3109. float ydx = -xdy, ydy = xdx;
  3110. int e1x = cx + (int)(xdx*TILE_SIZE/3), e1y = cy + (int)(xdy*TILE_SIZE/3);
  3111. int e2x = cx - (int)(xdx*TILE_SIZE/3), e2y = cy - (int)(xdy*TILE_SIZE/3);
  3112. int adx = (int)((ydx-xdx)*TILE_SIZE/8), ady = (int)((ydy-xdy)*TILE_SIZE/8);
  3113. int adx2 = (int)((-ydx-xdx)*TILE_SIZE/8), ady2 = (int)((-ydy-xdy)*TILE_SIZE/8);
  3114. draw_line(dr, e1x, e1y, e2x, e2y, col);
  3115. draw_line(dr, e1x, e1y, e1x+adx, e1y+ady, col);
  3116. draw_line(dr, e1x, e1y, e1x+adx2, e1y+ady2, col);
  3117. }
  3118. static void draw_square(drawing *dr, game_drawstate *ds, int x, int y,
  3119. unsigned long flags, int ddx, int ddy)
  3120. {
  3121. int lx = COORD(x), ly = COORD(y);
  3122. int dx, dy;
  3123. int gridcol;
  3124. clip(dr, lx, ly, TILE_SIZE, TILE_SIZE);
  3125. /*
  3126. * Draw the tile background.
  3127. */
  3128. draw_rect(dr, lx, ly, TILE_SIZE, TILE_SIZE,
  3129. (flags & DRAW_WHITE ? COL_WHITEBG :
  3130. flags & DRAW_BLACK ? COL_BLACKBG : COL_BACKGROUND));
  3131. /*
  3132. * Draw the grid.
  3133. */
  3134. gridcol = (flags & DRAW_BLACK ? COL_BLACKDOT : COL_GRID);
  3135. draw_rect(dr, lx, ly, 1, TILE_SIZE, gridcol);
  3136. draw_rect(dr, lx, ly, TILE_SIZE, 1, gridcol);
  3137. /*
  3138. * Draw the arrow, if present, or the cursor, if here.
  3139. */
  3140. if (flags & DRAW_ARROW)
  3141. draw_arrow(dr, ds, lx + TILE_SIZE/2, ly + TILE_SIZE/2, ddx, ddy,
  3142. (flags & DRAW_CURSOR) ? COL_CURSOR : COL_ARROW);
  3143. else if (flags & DRAW_CURSOR)
  3144. draw_rect_outline(dr,
  3145. lx + TILE_SIZE/2 - CURSOR_SIZE,
  3146. ly + TILE_SIZE/2 - CURSOR_SIZE,
  3147. 2*CURSOR_SIZE+1, 2*CURSOR_SIZE+1,
  3148. COL_CURSOR);
  3149. /*
  3150. * Draw the edges.
  3151. */
  3152. if (flags & DRAW_EDGE_L)
  3153. draw_rect(dr, lx, ly, EDGE_THICKNESS, TILE_SIZE, COL_EDGE);
  3154. if (flags & DRAW_EDGE_R)
  3155. draw_rect(dr, lx + TILE_SIZE - EDGE_THICKNESS + 1, ly,
  3156. EDGE_THICKNESS - 1, TILE_SIZE, COL_EDGE);
  3157. if (flags & DRAW_EDGE_U)
  3158. draw_rect(dr, lx, ly, TILE_SIZE, EDGE_THICKNESS, COL_EDGE);
  3159. if (flags & DRAW_EDGE_D)
  3160. draw_rect(dr, lx, ly + TILE_SIZE - EDGE_THICKNESS + 1,
  3161. TILE_SIZE, EDGE_THICKNESS - 1, COL_EDGE);
  3162. if (flags & DRAW_CORNER_UL)
  3163. draw_rect(dr, lx, ly, EDGE_THICKNESS, EDGE_THICKNESS, COL_EDGE);
  3164. if (flags & DRAW_CORNER_UR)
  3165. draw_rect(dr, lx + TILE_SIZE - EDGE_THICKNESS + 1, ly,
  3166. EDGE_THICKNESS - 1, EDGE_THICKNESS, COL_EDGE);
  3167. if (flags & DRAW_CORNER_DL)
  3168. draw_rect(dr, lx, ly + TILE_SIZE - EDGE_THICKNESS + 1,
  3169. EDGE_THICKNESS, EDGE_THICKNESS - 1, COL_EDGE);
  3170. if (flags & DRAW_CORNER_DR)
  3171. draw_rect(dr, lx + TILE_SIZE - EDGE_THICKNESS + 1,
  3172. ly + TILE_SIZE - EDGE_THICKNESS + 1,
  3173. EDGE_THICKNESS - 1, EDGE_THICKNESS - 1, COL_EDGE);
  3174. /*
  3175. * Draw the dots.
  3176. */
  3177. for (dy = 0; dy < 3; dy++)
  3178. for (dx = 0; dx < 3; dx++) {
  3179. int dotval = (flags >> (DOT_SHIFT_C + DOT_SHIFT_M*(dy*3+dx)));
  3180. dotval &= (1 << DOT_SHIFT_M)-1;
  3181. if (dotval)
  3182. draw_circle(dr, lx+dx*TILE_SIZE/2, ly+dy*TILE_SIZE/2,
  3183. DOT_SIZE,
  3184. (dotval == 1 ? COL_WHITEDOT : COL_BLACKDOT),
  3185. COL_BLACKDOT);
  3186. }
  3187. unclip(dr);
  3188. draw_update(dr, lx, ly, TILE_SIZE, TILE_SIZE);
  3189. }
  3190. static void calculate_opposite_point(const game_ui *ui,
  3191. const game_drawstate *ds, const int x,
  3192. const int y, int *oppositex,
  3193. int *oppositey)
  3194. {
  3195. /* oppositex - dotx = dotx - x <=> oppositex = 2 * dotx - x */
  3196. *oppositex = 2 * SCOORD(ui->dotx) - x;
  3197. *oppositey = 2 * SCOORD(ui->doty) - y;
  3198. }
  3199. static void game_redraw(drawing *dr, game_drawstate *ds,
  3200. const game_state *oldstate, const game_state *state,
  3201. int dir, const game_ui *ui,
  3202. float animtime, float flashtime)
  3203. {
  3204. int w = ds->w, h = ds->h;
  3205. int x, y;
  3206. bool flashing = false;
  3207. if (flashtime > 0) {
  3208. int frame = (int)(flashtime / FLASH_TIME);
  3209. flashing = (frame % 2 == 0);
  3210. }
  3211. if (ds->dragging) {
  3212. assert(ds->bl);
  3213. assert(ds->blmirror);
  3214. blitter_load(dr, ds->blmirror, ds->oppx, ds->oppy);
  3215. draw_update(dr, ds->oppx, ds->oppy, TILE_SIZE, TILE_SIZE);
  3216. blitter_load(dr, ds->bl, ds->dragx, ds->dragy);
  3217. draw_update(dr, ds->dragx, ds->dragy, TILE_SIZE, TILE_SIZE);
  3218. ds->dragging = false;
  3219. }
  3220. if (ds->cur_visible) {
  3221. assert(ds->cur_bl);
  3222. blitter_load(dr, ds->cur_bl, ds->cx, ds->cy);
  3223. draw_update(dr, ds->cx, ds->cy, CURSOR_SIZE*2+1, CURSOR_SIZE*2+1);
  3224. ds->cur_visible = false;
  3225. }
  3226. if (!ds->started) {
  3227. draw_rect(dr, BORDER - EDGE_THICKNESS + 1, BORDER - EDGE_THICKNESS + 1,
  3228. w*TILE_SIZE + EDGE_THICKNESS*2 - 1,
  3229. h*TILE_SIZE + EDGE_THICKNESS*2 - 1, COL_EDGE);
  3230. draw_update(dr, 0, 0, DRAW_WIDTH, DRAW_HEIGHT);
  3231. ds->started = true;
  3232. }
  3233. check_complete(state, NULL, ds->colour_scratch);
  3234. for (y = 0; y < h; y++)
  3235. for (x = 0; x < w; x++) {
  3236. unsigned long flags = 0;
  3237. int ddx = 0, ddy = 0;
  3238. space *sp, *opp;
  3239. int dx, dy;
  3240. /*
  3241. * Set up the flags for this square. Firstly, see if we
  3242. * have edges.
  3243. */
  3244. if (SPACE(state, x*2, y*2+1).flags & F_EDGE_SET)
  3245. flags |= DRAW_EDGE_L;
  3246. if (SPACE(state, x*2+2, y*2+1).flags & F_EDGE_SET)
  3247. flags |= DRAW_EDGE_R;
  3248. if (SPACE(state, x*2+1, y*2).flags & F_EDGE_SET)
  3249. flags |= DRAW_EDGE_U;
  3250. if (SPACE(state, x*2+1, y*2+2).flags & F_EDGE_SET)
  3251. flags |= DRAW_EDGE_D;
  3252. /*
  3253. * Also, mark corners of neighbouring edges.
  3254. */
  3255. if ((x > 0 && SPACE(state, x*2-1, y*2).flags & F_EDGE_SET) ||
  3256. (y > 0 && SPACE(state, x*2, y*2-1).flags & F_EDGE_SET))
  3257. flags |= DRAW_CORNER_UL;
  3258. if ((x+1 < w && SPACE(state, x*2+3, y*2).flags & F_EDGE_SET) ||
  3259. (y > 0 && SPACE(state, x*2+2, y*2-1).flags & F_EDGE_SET))
  3260. flags |= DRAW_CORNER_UR;
  3261. if ((x > 0 && SPACE(state, x*2-1, y*2+2).flags & F_EDGE_SET) ||
  3262. (y+1 < h && SPACE(state, x*2, y*2+3).flags & F_EDGE_SET))
  3263. flags |= DRAW_CORNER_DL;
  3264. if ((x+1 < w && SPACE(state, x*2+3, y*2+2).flags & F_EDGE_SET) ||
  3265. (y+1 < h && SPACE(state, x*2+2, y*2+3).flags & F_EDGE_SET))
  3266. flags |= DRAW_CORNER_DR;
  3267. /*
  3268. * If this square is part of a valid region, paint it
  3269. * that region's colour. Exception: if we're flashing,
  3270. * everything goes briefly back to background colour.
  3271. */
  3272. sp = &SPACE(state, x*2+1, y*2+1);
  3273. if (sp->flags & F_TILE_ASSOC) {
  3274. opp = tile_opposite(state, sp);
  3275. } else {
  3276. opp = NULL;
  3277. }
  3278. if (ds->colour_scratch[y*w+x] && !flashing) {
  3279. flags |= (ds->colour_scratch[y*w+x] == 2 ?
  3280. DRAW_BLACK : DRAW_WHITE);
  3281. }
  3282. /*
  3283. * If this square is associated with a dot but it isn't
  3284. * part of a valid region, draw an arrow in it pointing
  3285. * in the direction of that dot.
  3286. *
  3287. * Exception: if this is the source point of an active
  3288. * drag, we don't draw the arrow.
  3289. */
  3290. if ((sp->flags & F_TILE_ASSOC) && !ds->colour_scratch[y*w+x]) {
  3291. if (ui->dragging && ui->srcx == x*2+1 && ui->srcy == y*2+1) {
  3292. /* tile is the source, don't do it */
  3293. } else if (ui->dragging && opp && ui->srcx == opp->x && ui->srcy == opp->y) {
  3294. /* opposite tile is the source, don't do it */
  3295. } else if (sp->doty != y*2+1 || sp->dotx != x*2+1) {
  3296. flags |= DRAW_ARROW;
  3297. ddy = sp->doty - (y*2+1);
  3298. ddx = sp->dotx - (x*2+1);
  3299. }
  3300. }
  3301. /*
  3302. * Now go through the nine possible places we could
  3303. * have dots.
  3304. */
  3305. for (dy = 0; dy < 3; dy++)
  3306. for (dx = 0; dx < 3; dx++) {
  3307. sp = &SPACE(state, x*2+dx, y*2+dy);
  3308. if (sp->flags & F_DOT) {
  3309. unsigned long dotval = (sp->flags & F_DOT_BLACK ?
  3310. DOT_BLACK : DOT_WHITE);
  3311. flags |= dotval << (DOT_SHIFT_C +
  3312. DOT_SHIFT_M*(dy*3+dx));
  3313. }
  3314. }
  3315. /*
  3316. * Now work out if we have to draw a cursor for this square;
  3317. * cursors-on-lines are taken care of below.
  3318. */
  3319. if (ui->cur_visible &&
  3320. ui->cur_x == x*2+1 && ui->cur_y == y*2+1 &&
  3321. !(SPACE(state, x*2+1, y*2+1).flags & F_DOT))
  3322. flags |= DRAW_CURSOR;
  3323. /*
  3324. * Now we have everything we're going to need. Draw the
  3325. * square.
  3326. */
  3327. if (ds->grid[y*w+x] != flags ||
  3328. ds->dx[y*w+x] != ddx ||
  3329. ds->dy[y*w+x] != ddy) {
  3330. draw_square(dr, ds, x, y, flags, ddx, ddy);
  3331. ds->grid[y*w+x] = flags;
  3332. ds->dx[y*w+x] = ddx;
  3333. ds->dy[y*w+x] = ddy;
  3334. }
  3335. }
  3336. /*
  3337. * Draw a cursor. This secondary blitter is much less invasive than trying
  3338. * to fix up all of the rest of the code with sufficient flags to be able to
  3339. * display this sensibly.
  3340. */
  3341. if (ui->cur_visible) {
  3342. space *sp = &SPACE(state, ui->cur_x, ui->cur_y);
  3343. ds->cur_visible = true;
  3344. ds->cx = SCOORD(ui->cur_x) - CURSOR_SIZE;
  3345. ds->cy = SCOORD(ui->cur_y) - CURSOR_SIZE;
  3346. blitter_save(dr, ds->cur_bl, ds->cx, ds->cy);
  3347. if (sp->flags & F_DOT) {
  3348. /* draw a red dot (over the top of whatever would be there already) */
  3349. draw_circle(dr, SCOORD(ui->cur_x), SCOORD(ui->cur_y), DOT_SIZE,
  3350. COL_CURSOR, COL_BLACKDOT);
  3351. } else if (sp->type != s_tile) {
  3352. /* draw an edge/vertex square; tile cursors are dealt with above. */
  3353. int dx = (ui->cur_x % 2) ? CURSOR_SIZE : CURSOR_SIZE/3;
  3354. int dy = (ui->cur_y % 2) ? CURSOR_SIZE : CURSOR_SIZE/3;
  3355. int x1 = SCOORD(ui->cur_x)-dx, y1 = SCOORD(ui->cur_y)-dy;
  3356. int xs = dx*2+1, ys = dy*2+1;
  3357. draw_rect(dr, x1, y1, xs, ys, COL_CURSOR);
  3358. }
  3359. draw_update(dr, ds->cx, ds->cy, CURSOR_SIZE*2+1, CURSOR_SIZE*2+1);
  3360. }
  3361. if (ui->dragging) {
  3362. int oppx, oppy;
  3363. ds->dragging = true;
  3364. ds->dragx = ui->dx - TILE_SIZE/2;
  3365. ds->dragy = ui->dy - TILE_SIZE/2;
  3366. calculate_opposite_point(ui, ds, ui->dx, ui->dy, &oppx, &oppy);
  3367. ds->oppx = oppx - TILE_SIZE/2;
  3368. ds->oppy = oppy - TILE_SIZE/2;
  3369. blitter_save(dr, ds->bl, ds->dragx, ds->dragy);
  3370. clip(dr, ds->dragx, ds->dragy, TILE_SIZE, TILE_SIZE);
  3371. draw_arrow(dr, ds, ui->dx, ui->dy, SCOORD(ui->dotx) - ui->dx,
  3372. SCOORD(ui->doty) - ui->dy, COL_ARROW);
  3373. unclip(dr);
  3374. draw_update(dr, ds->dragx, ds->dragy, TILE_SIZE, TILE_SIZE);
  3375. blitter_save(dr, ds->blmirror, ds->oppx, ds->oppy);
  3376. clip(dr, ds->oppx, ds->oppy, TILE_SIZE, TILE_SIZE);
  3377. draw_arrow(dr, ds, oppx, oppy, SCOORD(ui->dotx) - oppx,
  3378. SCOORD(ui->doty) - oppy, COL_ARROW);
  3379. unclip(dr);
  3380. draw_update(dr, ds->oppx, ds->oppy, TILE_SIZE, TILE_SIZE);
  3381. }
  3382. #ifdef EDITOR
  3383. {
  3384. char buf[256];
  3385. if (state->cdiff != -1)
  3386. sprintf(buf, "Puzzle is %s.", galaxies_diffnames[state->cdiff]);
  3387. else
  3388. buf[0] = '\0';
  3389. status_bar(dr, buf);
  3390. }
  3391. #endif
  3392. }
  3393. static float game_anim_length(const game_state *oldstate,
  3394. const game_state *newstate, int dir, game_ui *ui)
  3395. {
  3396. return 0.0F;
  3397. }
  3398. static float game_flash_length(const game_state *oldstate,
  3399. const game_state *newstate, int dir, game_ui *ui)
  3400. {
  3401. if ((!oldstate->completed && newstate->completed) &&
  3402. !(newstate->used_solve))
  3403. return 3 * FLASH_TIME;
  3404. else
  3405. return 0.0F;
  3406. }
  3407. static void game_get_cursor_location(const game_ui *ui,
  3408. const game_drawstate *ds,
  3409. const game_state *state,
  3410. const game_params *params,
  3411. int *x, int *y, int *w, int *h)
  3412. {
  3413. if(ui->cur_visible) {
  3414. space *sp = &SPACE(state, ui->cur_x, ui->cur_y);
  3415. if(sp->flags & F_DOT) {
  3416. *x = SCOORD(ui->cur_x) - DOT_SIZE;
  3417. *y = SCOORD(ui->cur_y) - DOT_SIZE;
  3418. *w = *h = 2 * DOT_SIZE + 1;
  3419. } else if(sp->type != s_tile) {
  3420. int dx = (ui->cur_x % 2) ? CURSOR_SIZE : CURSOR_SIZE/3;
  3421. int dy = (ui->cur_y % 2) ? CURSOR_SIZE : CURSOR_SIZE/3;
  3422. int x1 = SCOORD(ui->cur_x)-dx, y1 = SCOORD(ui->cur_y)-dy;
  3423. int xs = dx*2+1, ys = dy*2+1;
  3424. *x = x1;
  3425. *y = y1;
  3426. *w = xs;
  3427. *h = ys;
  3428. } else {
  3429. *x = SCOORD(ui->cur_x) - CURSOR_SIZE;
  3430. *y = SCOORD(ui->cur_y) - CURSOR_SIZE;
  3431. *w = *h = 2 * CURSOR_SIZE + 1;
  3432. }
  3433. }
  3434. }
  3435. static int game_status(const game_state *state)
  3436. {
  3437. return state->completed ? +1 : 0;
  3438. }
  3439. #ifndef EDITOR
  3440. static void game_print_size(const game_params *params, const game_ui *ui,
  3441. float *x, float *y)
  3442. {
  3443. int pw, ph;
  3444. /*
  3445. * 8mm squares by default. (There isn't all that much detail
  3446. * that needs to go in each square.)
  3447. */
  3448. game_compute_size(params, 800, ui, &pw, &ph);
  3449. *x = pw / 100.0F;
  3450. *y = ph / 100.0F;
  3451. }
  3452. static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
  3453. int sz)
  3454. {
  3455. int w = state->w, h = state->h;
  3456. int white, black, blackish;
  3457. int x, y, i, j;
  3458. int *colours;
  3459. DSF *dsf;
  3460. int *coords = NULL;
  3461. int ncoords = 0, coordsize = 0;
  3462. /* Ick: fake up `ds->tilesize' for macro expansion purposes */
  3463. game_drawstate ads, *ds = &ads;
  3464. ds->tilesize = sz;
  3465. white = print_mono_colour(dr, 1);
  3466. black = print_mono_colour(dr, 0);
  3467. blackish = print_hatched_colour(dr, HATCH_X);
  3468. /*
  3469. * Get the completion information.
  3470. */
  3471. dsf = dsf_new(w * h);
  3472. colours = snewn(w * h, int);
  3473. check_complete(state, dsf, colours);
  3474. /*
  3475. * Draw the grid.
  3476. */
  3477. print_line_width(dr, TILE_SIZE / 64);
  3478. for (x = 1; x < w; x++)
  3479. draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), black);
  3480. for (y = 1; y < h; y++)
  3481. draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), black);
  3482. /*
  3483. * Shade the completed regions. Just in case any particular
  3484. * printing platform deals badly with adjacent
  3485. * similarly-hatched regions, we'll fill each one as a single
  3486. * polygon.
  3487. */
  3488. for (i = 0; i < w*h; i++) {
  3489. j = dsf_canonify(dsf, i);
  3490. if (colours[j] != 0) {
  3491. int dx, dy, t;
  3492. /*
  3493. * This is the first square we've run into belonging to
  3494. * this polyomino, which means an edge of the polyomino
  3495. * is certain to be to our left. (After we finish
  3496. * tracing round it, we'll set the colours[] entry to
  3497. * zero to prevent accidentally doing it again.)
  3498. */
  3499. x = i % w;
  3500. y = i / w;
  3501. dx = -1;
  3502. dy = 0;
  3503. ncoords = 0;
  3504. while (1) {
  3505. /*
  3506. * We are currently sitting on square (x,y), which
  3507. * we know to be in our polyomino, and we also know
  3508. * that (x+dx,y+dy) is not. The way I visualise
  3509. * this is that we're standing to the right of a
  3510. * boundary line, stretching our left arm out to
  3511. * point to the exterior square on the far side.
  3512. */
  3513. /*
  3514. * First, check if we've gone round the entire
  3515. * polyomino.
  3516. */
  3517. if (ncoords > 0 &&
  3518. (x == i%w && y == i/w && dx == -1 && dy == 0))
  3519. break;
  3520. /*
  3521. * Add to our coordinate list the coordinate
  3522. * backwards and to the left of where we are.
  3523. */
  3524. if (ncoords + 2 > coordsize) {
  3525. coordsize = (ncoords * 3 / 2) + 64;
  3526. coords = sresize(coords, coordsize, int);
  3527. }
  3528. coords[ncoords++] = COORD((2*x+1 + dx + dy) / 2);
  3529. coords[ncoords++] = COORD((2*y+1 + dy - dx) / 2);
  3530. /*
  3531. * Follow the edge round. If the square directly in
  3532. * front of us is not part of the polyomino, we
  3533. * turn right; if it is and so is the square in
  3534. * front of (x+dx,y+dy), we turn left; otherwise we
  3535. * go straight on.
  3536. */
  3537. if (x-dy < 0 || x-dy >= w || y+dx < 0 || y+dx >= h ||
  3538. dsf_canonify(dsf, (y+dx)*w+(x-dy)) != j) {
  3539. /* Turn right. */
  3540. t = dx;
  3541. dx = -dy;
  3542. dy = t;
  3543. } else if (x+dx-dy >= 0 && x+dx-dy < w &&
  3544. y+dy+dx >= 0 && y+dy+dx < h &&
  3545. dsf_canonify(dsf, (y+dy+dx)*w+(x+dx-dy)) == j) {
  3546. /* Turn left. */
  3547. x += dx;
  3548. y += dy;
  3549. t = dx;
  3550. dx = dy;
  3551. dy = -t;
  3552. x -= dx;
  3553. y -= dy;
  3554. } else {
  3555. /* Straight on. */
  3556. x -= dy;
  3557. y += dx;
  3558. }
  3559. }
  3560. /*
  3561. * Now we have our polygon complete, so fill it.
  3562. */
  3563. draw_polygon(dr, coords, ncoords/2,
  3564. colours[j] == 2 ? blackish : -1, black);
  3565. /*
  3566. * And mark this polyomino as done.
  3567. */
  3568. colours[j] = 0;
  3569. }
  3570. }
  3571. /*
  3572. * Draw the edges.
  3573. */
  3574. for (y = 0; y <= h; y++)
  3575. for (x = 0; x <= w; x++) {
  3576. if (x < w && SPACE(state, x*2+1, y*2).flags & F_EDGE_SET)
  3577. draw_rect(dr, COORD(x)-EDGE_THICKNESS, COORD(y)-EDGE_THICKNESS,
  3578. EDGE_THICKNESS * 2 + TILE_SIZE, EDGE_THICKNESS * 2,
  3579. black);
  3580. if (y < h && SPACE(state, x*2, y*2+1).flags & F_EDGE_SET)
  3581. draw_rect(dr, COORD(x)-EDGE_THICKNESS, COORD(y)-EDGE_THICKNESS,
  3582. EDGE_THICKNESS * 2, EDGE_THICKNESS * 2 + TILE_SIZE,
  3583. black);
  3584. }
  3585. /*
  3586. * Draw the dots.
  3587. */
  3588. for (y = 0; y <= 2*h; y++)
  3589. for (x = 0; x <= 2*w; x++)
  3590. if (SPACE(state, x, y).flags & F_DOT) {
  3591. draw_circle(dr, (int)COORD(x/2.0), (int)COORD(y/2.0), DOT_SIZE,
  3592. (SPACE(state, x, y).flags & F_DOT_BLACK ?
  3593. black : white), black);
  3594. }
  3595. dsf_free(dsf);
  3596. sfree(colours);
  3597. sfree(coords);
  3598. }
  3599. #endif
  3600. #ifdef COMBINED
  3601. #define thegame galaxies
  3602. #endif
  3603. const struct game thegame = {
  3604. "Galaxies", "games.galaxies", "galaxies",
  3605. default_params,
  3606. game_fetch_preset, NULL,
  3607. decode_params,
  3608. encode_params,
  3609. free_params,
  3610. dup_params,
  3611. true, game_configure, custom_params,
  3612. validate_params,
  3613. new_game_desc,
  3614. validate_desc,
  3615. new_game,
  3616. dup_game,
  3617. free_game,
  3618. #ifdef EDITOR
  3619. false, NULL,
  3620. #else
  3621. true, solve_game,
  3622. #endif
  3623. true, game_can_format_as_text_now, game_text_format,
  3624. NULL, NULL, /* get_prefs, set_prefs */
  3625. new_ui,
  3626. free_ui,
  3627. NULL, /* encode_ui */
  3628. NULL, /* decode_ui */
  3629. NULL, /* game_request_keys */
  3630. game_changed_state,
  3631. #ifdef EDITOR
  3632. NULL,
  3633. #else
  3634. current_key_label,
  3635. #endif
  3636. interpret_move,
  3637. execute_move,
  3638. PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
  3639. game_colours,
  3640. game_new_drawstate,
  3641. game_free_drawstate,
  3642. game_redraw,
  3643. game_anim_length,
  3644. game_flash_length,
  3645. game_get_cursor_location,
  3646. game_status,
  3647. #ifdef EDITOR
  3648. false, false, NULL, NULL,
  3649. true, /* wants_statusbar */
  3650. #else
  3651. true, false, game_print_size, game_print,
  3652. false, /* wants_statusbar */
  3653. #endif
  3654. false, NULL, /* timing_state */
  3655. REQUIRE_RBUTTON, /* flags */
  3656. };
  3657. #ifdef STANDALONE_SOLVER
  3658. static const char *quis;
  3659. #include <time.h>
  3660. static void usage_exit(const char *msg)
  3661. {
  3662. if (msg)
  3663. fprintf(stderr, "%s: %s\n", quis, msg);
  3664. fprintf(stderr, "Usage: %s [--seed SEED] --soak <params> | [game_id [game_id ...]]\n", quis);
  3665. exit(1);
  3666. }
  3667. static void dump_state(game_state *state)
  3668. {
  3669. char *temp = game_text_format(state);
  3670. printf("%s\n", temp);
  3671. sfree(temp);
  3672. }
  3673. static int gen(game_params *p, random_state *rs, bool debug)
  3674. {
  3675. char *desc;
  3676. int diff;
  3677. game_state *state;
  3678. #ifndef DEBUGGING
  3679. solver_show_working = debug;
  3680. #endif
  3681. printf("Generating a %dx%d %s puzzle.\n",
  3682. p->w, p->h, galaxies_diffnames[p->diff]);
  3683. desc = new_game_desc(p, rs, NULL, false);
  3684. state = new_game(NULL, p, desc);
  3685. dump_state(state);
  3686. diff = solver_state(state, DIFF_UNREASONABLE);
  3687. printf("Generated %s game %dx%d:%s\n",
  3688. galaxies_diffnames[diff], p->w, p->h, desc);
  3689. dump_state(state);
  3690. free_game(state);
  3691. sfree(desc);
  3692. return diff;
  3693. }
  3694. static void soak(game_params *p, random_state *rs)
  3695. {
  3696. time_t tt_start, tt_now, tt_last;
  3697. char *desc;
  3698. game_state *st;
  3699. int diff, n = 0, i, diffs[DIFF_MAX], ndots = 0, nspaces = 0;
  3700. #ifndef DEBUGGING
  3701. solver_show_working = false;
  3702. #endif
  3703. tt_start = tt_now = time(NULL);
  3704. for (i = 0; i < DIFF_MAX; i++) diffs[i] = 0;
  3705. one_try = true;
  3706. printf("Soak-generating a %dx%d grid, max. diff %s.\n",
  3707. p->w, p->h, galaxies_diffnames[p->diff]);
  3708. printf(" [");
  3709. for (i = 0; i < DIFF_MAX; i++)
  3710. printf("%s%s", (i == 0) ? "" : ", ", galaxies_diffnames[i]);
  3711. printf("]\n");
  3712. while (1) {
  3713. char *aux;
  3714. desc = new_game_desc(p, rs, &aux, false);
  3715. sfree(aux);
  3716. st = new_game(NULL, p, desc);
  3717. diff = solver_state(st, p->diff);
  3718. nspaces += st->w*st->h;
  3719. for (i = 0; i < st->sx*st->sy; i++)
  3720. if (st->grid[i].flags & F_DOT) ndots++;
  3721. free_game(st);
  3722. sfree(desc);
  3723. diffs[diff]++;
  3724. n++;
  3725. tt_last = time(NULL);
  3726. if (tt_last > tt_now) {
  3727. tt_now = tt_last;
  3728. printf("%d total, %3.1f/s, [",
  3729. n, (double)n / ((double)tt_now - tt_start));
  3730. for (i = 0; i < DIFF_MAX; i++)
  3731. printf("%s%.1f%%", (i == 0) ? "" : ", ",
  3732. 100.0 * ((double)diffs[i] / (double)n));
  3733. printf("], %.1f%% dots\n",
  3734. 100.0 * ((double)ndots / (double)nspaces));
  3735. }
  3736. }
  3737. }
  3738. int main(int argc, char **argv)
  3739. {
  3740. game_params *p;
  3741. char *id = NULL, *desc;
  3742. const char *err;
  3743. game_state *s;
  3744. int diff;
  3745. bool do_soak = false, verbose = false;
  3746. random_state *rs;
  3747. time_t seed = time(NULL);
  3748. quis = argv[0];
  3749. while (--argc > 0) {
  3750. char *p = *++argv;
  3751. if (!strcmp(p, "-v")) {
  3752. verbose = true;
  3753. } else if (!strcmp(p, "--seed")) {
  3754. if (argc == 0) usage_exit("--seed needs an argument");
  3755. seed = (time_t)atoi(*++argv);
  3756. argc--;
  3757. } else if (!strcmp(p, "--soak")) {
  3758. do_soak = true;
  3759. } else if (*p == '-') {
  3760. usage_exit("unrecognised option");
  3761. } else {
  3762. id = p;
  3763. }
  3764. }
  3765. p = default_params();
  3766. rs = random_new((void*)&seed, sizeof(time_t));
  3767. if (do_soak) {
  3768. if (!id) usage_exit("need one argument for --soak");
  3769. decode_params(p, *argv);
  3770. soak(p, rs);
  3771. return 0;
  3772. }
  3773. if (!id) {
  3774. while (1) {
  3775. p->w = random_upto(rs, 15) + 3;
  3776. p->h = random_upto(rs, 15) + 3;
  3777. p->diff = random_upto(rs, DIFF_UNREASONABLE);
  3778. diff = gen(p, rs, false);
  3779. }
  3780. return 0;
  3781. }
  3782. desc = strchr(id, ':');
  3783. if (!desc) {
  3784. decode_params(p, id);
  3785. gen(p, rs, verbose);
  3786. } else {
  3787. #ifndef DEBUGGING
  3788. solver_show_working = true;
  3789. #endif
  3790. *desc++ = '\0';
  3791. decode_params(p, id);
  3792. err = validate_desc(p, desc);
  3793. if (err) {
  3794. fprintf(stderr, "%s: %s\n", argv[0], err);
  3795. exit(1);
  3796. }
  3797. s = new_game(NULL, p, desc);
  3798. diff = solver_state(s, DIFF_UNREASONABLE);
  3799. dump_state(s);
  3800. printf("Puzzle is %s.\n", galaxies_diffnames[diff]);
  3801. free_game(s);
  3802. }
  3803. free_params(p);
  3804. return 0;
  3805. }
  3806. #endif
  3807. #ifdef STANDALONE_PICTURE_GENERATOR
  3808. /*
  3809. * Main program for the standalone picture generator. To use it,
  3810. * simply provide it with an XBM-format bitmap file (note XBM, not
  3811. * XPM) on standard input, and it will output a game ID in return.
  3812. * For example:
  3813. *
  3814. * $ ./galaxiespicture < badly-drawn-cat.xbm
  3815. * 11x11:eloMBLzFeEzLNMWifhaWYdDbixCymBbBMLoDdewGg
  3816. *
  3817. * If you want a puzzle with a non-standard difficulty level, pass
  3818. * a partial parameters string as a command-line argument (e.g.
  3819. * `./galaxiespicture du < foo.xbm', where `du' is the same suffix
  3820. * which if it appeared in a random-seed game ID would set the
  3821. * difficulty level to Unreasonable). However, be aware that if the
  3822. * generator fails to produce an adequately difficult puzzle too
  3823. * many times then it will give up and return an easier one (just
  3824. * as it does during normal GUI play). To be sure you really have
  3825. * the difficulty you asked for, use galaxiessolver to
  3826. * double-check.
  3827. *
  3828. * (Perhaps I ought to include an option to make this standalone
  3829. * generator carry on looping until it really does get the right
  3830. * difficulty. Hmmm.)
  3831. */
  3832. #include <time.h>
  3833. int main(int argc, char **argv)
  3834. {
  3835. game_params *par;
  3836. char *params, *desc;
  3837. random_state *rs;
  3838. time_t seed = time(NULL);
  3839. char buf[4096];
  3840. int i;
  3841. int x, y;
  3842. par = default_params();
  3843. if (argc > 1)
  3844. decode_params(par, argv[1]); /* get difficulty */
  3845. par->w = par->h = -1;
  3846. /*
  3847. * Now read an XBM file from standard input. This is simple and
  3848. * hacky and will do very little error detection, so don't feed
  3849. * it bogus data.
  3850. */
  3851. picture = NULL;
  3852. x = y = 0;
  3853. while (fgets(buf, sizeof(buf), stdin)) {
  3854. buf[strcspn(buf, "\r\n")] = '\0';
  3855. if (!strncmp(buf, "#define", 7)) {
  3856. /*
  3857. * Lines starting `#define' give the width and height.
  3858. */
  3859. char *num = buf + strlen(buf);
  3860. char *symend;
  3861. while (num > buf && isdigit((unsigned char)num[-1]))
  3862. num--;
  3863. symend = num;
  3864. while (symend > buf && isspace((unsigned char)symend[-1]))
  3865. symend--;
  3866. if (symend-5 >= buf && !strncmp(symend-5, "width", 5))
  3867. par->w = atoi(num);
  3868. else if (symend-6 >= buf && !strncmp(symend-6, "height", 6))
  3869. par->h = atoi(num);
  3870. } else {
  3871. /*
  3872. * Otherwise, break the string up into words and take
  3873. * any word of the form `0x' plus hex digits to be a
  3874. * byte.
  3875. */
  3876. char *p, *wordstart;
  3877. if (!picture) {
  3878. if (par->w < 0 || par->h < 0) {
  3879. printf("failed to read width and height\n");
  3880. return 1;
  3881. }
  3882. picture = snewn(par->w * par->h, int);
  3883. for (i = 0; i < par->w * par->h; i++)
  3884. picture[i] = -1;
  3885. }
  3886. p = buf;
  3887. while (*p) {
  3888. while (*p && (*p == ',' || isspace((unsigned char)*p)))
  3889. p++;
  3890. wordstart = p;
  3891. while (*p && !(*p == ',' || *p == '}' ||
  3892. isspace((unsigned char)*p)))
  3893. p++;
  3894. if (*p)
  3895. *p++ = '\0';
  3896. if (wordstart[0] == '0' &&
  3897. (wordstart[1] == 'x' || wordstart[1] == 'X') &&
  3898. !wordstart[2 + strspn(wordstart+2,
  3899. "0123456789abcdefABCDEF")]) {
  3900. unsigned long byte = strtoul(wordstart+2, NULL, 16);
  3901. for (i = 0; i < 8; i++) {
  3902. int bit = (byte >> i) & 1;
  3903. if (y < par->h && x < par->w)
  3904. picture[y * par->w + x] = bit;
  3905. x++;
  3906. }
  3907. if (x >= par->w) {
  3908. x = 0;
  3909. y++;
  3910. }
  3911. }
  3912. }
  3913. }
  3914. }
  3915. for (i = 0; i < par->w * par->h; i++)
  3916. if (picture[i] < 0) {
  3917. fprintf(stderr, "failed to read enough bitmap data\n");
  3918. return 1;
  3919. }
  3920. rs = random_new((void*)&seed, sizeof(time_t));
  3921. desc = new_game_desc(par, rs, NULL, false);
  3922. params = encode_params(par, false);
  3923. printf("%s:%s\n", params, desc);
  3924. sfree(desc);
  3925. sfree(params);
  3926. free_params(par);
  3927. random_free(rs);
  3928. return 0;
  3929. }
  3930. #endif
  3931. /* vim: set shiftwidth=4 tabstop=8: */