aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAge
...
* Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in GalaxiesBen Harris2023-06-26
| | | | | | | | The boundary between them for mouse clicks probably wants to be revisited because at the moment it's slightly inside the edge of the grid. I tried using INUI() instead of INGRID() but that just gives a different wrong answer, so I may need to actually understand what's going on here.
* Pearl: slightly better handling of clicks outside the gridBen Harris2023-06-26
| | | | | | | | | | | | | | | In Pearl, a mouse-down outside the grid sets ui->ndragcoords to -1. The intended effect of this is to make sure that future drags are ignored, so you can't try to draw a line starting off the grid. However, this also has the effect of clearing any in-progress drag. This can happen if there's a keyboard "drag" in progress at the time. This is arguably wrong, but much more wrong was that interpret_move returned MOVE_UNUSED (and previously NULL) in this case. That meant that the display didn't get updated to show the abandonment of the drag, or the removal of the keyboard cursor that also happened. This commit changes MOVE_UNUSED to MOVE_UI_UPDATE so that at least the effect is correctly visible.
* Keen: fix another misuse of dsf_canonify.Simon Tatham2023-06-25
| | | | | | | | | | Chris Boyle points out that outline_block_structure has a comment saying that we're supposed to have picked a square with a boundary to its left. dsf_canonify no longer guarantees that, but dsf_minimal does. Switch to using that throughout the function. 'keen --generate 10#12345 --print 5x2' failed an assertion before this fix, and now doesn't.
* Reduce the set of keys from which we generate control charactersBen Harris2023-06-25
| | | | | | | | | | | | | | | | | | | | | midend_process_key() has some generic code for converting MOD_CTRL along with a printing character into a control character. This is derived from the Emscripten front-end because browsers don't do this themselves. Most other front ends seem to depend on the platform for this mapping. The mapping was applied to all printable ASCII characters, but this meant that Ctrl+-, which is commonly used by browsers to mean "zoom out" got converted into CR and then CURSOR_SELECT. That was confusing to say the least. So now, the CTRL mapping is only applied to characters in the roughly alphabetic range (0x40 to 0x7f), and MOD_CTRL applied to a character in the range 0x20 to 0x3f gets a return of PKR_UNUSED instead. That means that Ctrl+- in browsers now works properly. I don't think this will affect other front-ends because they're generally a lot less generous about passing MOD_CTRL to the mid-end. I've tested the GTK port nonetheless and not found any problems.
* Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in FlipBen Harris2023-06-24
|
* Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in FillingBen Harris2023-06-24
|
* Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in DominosaBen Harris2023-06-24
| | | | | | | | | The only tricky bit is whether clicking precisely on the diagonal of a square (which never has any effect on the game) is MOVE_UNUSED or MOVE_NO_EFFECT. I decided that having single-pixel lines in the middle of the grid causing events to be passed back to the environment would be very confusing, so they're MOVE_NO_EFFECT. Clicking entirely outside the grid, on the other hand, returns MOVE_UNUSED.
* Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in PegsBen Harris2023-06-23
| | | | | | | | Slightly more complicated than usual, because Pegs has irregularly shaped grids so detecting whether a click is inside requires more than just a range check. Also fixed a typo in a nearby comment.
* Blackbox: correct FROMDRAW() macro for C division semanticsBen Harris2023-06-22
| | | | | | | | | | | Integer division in C rounds towards zero, so if you want it to consistently round down you need to ensure that the arguments are positive. FROMDRAW() didn't do that, so clicks off the top and left corners of the grid got treated as being in the top row or left column (row and column 0) rather than ignored. This commit fixes the macro so that it offsets its argument upward before the division and compensates afterwards.
* spectre-test: support raster-mode tiling generation.Simon Tatham2023-06-18
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This is the most efficient way to apply the combinatorial coordinate system. As described in my original article (and mentioned again in the followup one), you can walk along a horizontal or vertical line of the tiling, identifying which edge of each tile the line will leave it by, and computing the location and coordinates of the next tile beyond that edge, so that you visit every tile intersected by the edge. By doing one iteration, say vertically up the left of your target area, and using the tiles you find as starting points for a series of perpendicular sub-iterations spaced closely enough not to miss any tiles, you can arrange to visit every tile intersecting your target region, without having ever had to store a large BFS queue of tiles left to visit. You only have to keep a small bounded number of coordinate variables for the whole run, so you can generate a very large patch of tiling with minimal memory and CPU time. You can even arrange not to emit any duplicates, without having to actually store the tiles you've already visited, by checking whether the y-coordinate of the previous horizontal iteration will have visited the same tile already. For Spectres, an extra wrinkle (almost literally) is that they're not convex, so a horizontal line can visit the same one twice, with another tile in between. So another part of de-duplication is noticing _that_: is the edge through which we've just entered this tile the first one we would have seen while traversing our line? If not, then trust that it's been emitted already. As a proof of concept (since I claimed it would work in my writeup article), and in case anyone wants larger tilings than actual Loopy will conveniently give you, I've implemented that algorithm in spectre-test. However, the actual grid generation for Loopy still uses the more memory-intensive breadth-first search: because that's what I implemented first (it's more likely to detect its own errors); because if I changed it now it would invalidate game descriptions (from all of two days' worth of live play, but even so); and because the linear space requirement isn't an important cost for Loopy, which is actually going to _store_ the whole grid after it's generated, so it needed linear space _anyway_.
* spectre_adjacent: optionally report dst_edge.Simon Tatham2023-06-18
| | | | | | | | Previously, you'd ask this function 'What lies on the other side of edge #i of this Spectre tile?' and it would tell you the identity of another Spectre. Now it will also tell you which _edge_ of that Spectre adjoins the specified edge of the input one. This will be used in the extra spectre-test mode I'm about to add.
* spectre.c: expose a couple more internal functions.Simon Tatham2023-06-18
| | | | spectre-test will want to use these for an additional generation mode.
* Spectre tiling: add a comment with some reference URLs.Simon Tatham2023-06-17
| | | | | I meant to fold this into yesterday's main commit, but there's always something that gets forgotten.
* Loopy / grid.c: support the new Spectre monotiling.Simon Tatham2023-06-16
| | | | | | | | | | | | | | This uses a tile shape very similar to the hat, but the tiling _structure_ is totally changed so that there aren't any reflected copies of the tile. I'm not sure how much difference this makes to gameplay: the two tilings are very similar for Loopy purposes. But the code was fun to write, and I think the Spectre shape is noticeably prettier, so I'm adding this to the collection anyway. The test programs also generate a pile of SVG images used in the companion article on my website.
* Fix some unused-variable warnings.Simon Tatham2023-06-16
| | | | | | | | | A test-build with a modern clang points out a number of 'set but not used' variables, which clang seems to have got better at recently. In cases where there's conditioned-out or commented-out code using the variable, I've left it in and added a warning-suppressing cast to void. Otherwise I've just deleted the variables.
* Add a 'core' library alongside 'common'.Simon Tatham2023-06-16
| | | | | | | | | | | | | | | | | The 'core' library contains almost all the same objects as 'common', but leaves out hat.c. And the auxiliary program 'hatgen' now links against that slightly reduced core library instead of 'common'. This avoids a dependency loop: one of hatgen's jobs is to generate hat-tables.h, but hat-tables.h is a dependency of it. Of course, the generated hat-tables.h is already committed, so this doesn't present a bootstrapping problem in a normal build. But if someone modifies hatgen.c in order to regenerate hat-tables.h, and does so in a way that makes it uncompilable, they can't rebuild hatgen and try again! Of course you can always revert changes with git, but it's annoying to have to. Better to keep the dependencies non-cyclic in the first place.
* hat-test: support SVG output.Simon Tatham2023-06-16
| | | | I want to generate an SVG diagram for an upcoming article.
* Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in PearlBen Harris2023-06-16
|
* Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in CubeBen Harris2023-06-15
|
* Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in FifteenBen Harris2023-06-15
|
* Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in BridgesBen Harris2023-06-11
|
* Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in SlantBen Harris2023-06-11
|
* Expose the NO_EFFECT/UNUSED distinction through midend_process_key()Ben Harris2023-06-11
| | | | | | | | | | | | | | | | | | | | | | This removed the "handled" pointer and instead extends the existing boolean return value (quit or don't quit) into an enumeration. One of the values still quits the program, but now there are different values for keys that had an effect, had no effect, and are not used by the puzzle at all. The mapping from interpret_move results to process_key results is roughly: move string -> PKR_SOME_EFFECT MOVE_UI_UPDATE -> PKR_SOME_EFFECT MOVE_NO_EFFECT -> PKR_NO_EFFECT MOVE_UNUSED -> PKR_UNUSED The mid-end can also generate results internally, and is the only place that PKR_QUIT can arise. For compatibility, PKR_QUIT is zero, so anything expecting a false return value to mean quit will be unsurprised. The other values are ordered so that lower values indicate a greater amount of handling of the key.
* Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in MinesBen Harris2023-06-11
|
* Add MOVE_NO_EFFECT and MOVE_UNUSED return values from interpret_move()Ben Harris2023-06-11
| | | | | | | | These allow for distinguishing the case where a puzzle doesn't have a use for a key from the case where it just happens to have no effect in the current state of the puzzle. These were both represented by NULL, but that now represents the case where a puzzle hasn't been updated to make the distinction yet.
* Rename UI_UPDATE as MOVE_UI_UPDATEBen Harris2023-06-11
| | | | | | | | All the other constants named UI_* are special key names that can be passed to midend_process_key(), but UI_UPDATE is a special return value from the back-end interpret_move() function instead. This renaming makes the distinction clear and provides a naming convention for future special return values from interpret_move().
* Update a comment in Mines to reflect that we have user prefs nowBen Harris2023-06-11
|
* Fix a few minor memory leaks.Simon Tatham2023-06-06
| | | | Thanks to Jeremy Stephens for reporting them.
* Add preferences for existing UI style controlsBen Harris2023-05-30
| | | | | | | | | | | | Some puzzles have keys that make changes to the display style in ways that would probably have been user preferences if they had existed. I've added a user preference for each of these. The keys still work, and unlike the preferences can be changed without saving any state. The affected settings are: * Labelling colours with numbers in Guess ("L" key) * Labelling regions with numbers in Map ("L" key) * Whether monsters are shown as letters or pictures in Undead ("A" key)
* js: pass preferences file from JS to C on the heap, not the stackBen Harris2023-05-30
| | | | | | | | | | | | | | | | The C stack used by Emscripten is quite small, so passing more than a few klilobytes of data on it tends to cause an overflow. Current versions of puzzles will only generate tiny preferences files, but this might change in future and in any case Puzzles shouldn't crash just because the preferences in local storage have got corrupted. To fix this, we now have JavaScript allocate a suitable amount of C heap memory using malloc() and stick the preferences file in there. This could plausibly fail if the preferences file were really big, but that's unlikely since browsers generally limit an origin to about 5 MB of local storage. In any case, if malloc() does fail, we'll just ignore the preferences file, which is probably the right thing to do.
* js: handle exceptions when accessing localStorageBen Harris2023-05-30
| | | | | | | | | | | | | | | | | Trying to access window.localStorage will generate an exception if the local storage is for some reason inaccessible. This can be demonstrated in Firefox by configuring it to block a site from using site data. Writing to local storage might also cause an exception if, for instance, the quota of data for a site is exceeded. If an exception is raised while loading preferences we log the fact but don't make any report to the user, behaving as if no preferences were found. This avoids annoying the user on every visit to a puzzle page if they're not trying to use preferences. If something goes wrong when saving, we do currently report that to the user in an alert box. This seems reasonable since it's in response to an explicit user action.
* Emscripten: fix edge case of js_canvas_find_font_midpoint.Simon Tatham2023-05-26
| | | | | | | | | | | | | | | | | | | | If the puzzle canvas is at a ludicrously small size, so that you attempt to use a zero-height font, then obviously nothing sensible will appear in the way of text, but you'd at least like to avoid a crash. But currently, js_canvas_find_font_midpoint will make a canvas, print some height-0 text into it, and try to retrieve the image pixels to see what the actual font height was - and this will involve asking getImageData for a zero-sized rectangle of pixels, which is an error. Of course, there's only one possible return value from this function if the font height is 0, so we can just return it without going via getImageData at all. (This crash can be provoked by trying to resize the puzzle canvas to Far Too Small, or by interleaving canvas resizes with browser-tab zooming. I've had one report that it also occurs in less silly situations, which I haven't been able to reproduce. However, this seems like a general improvement anyway.)
* Loopy: fix redraw issue due to enlarged dots.Simon Tatham2023-05-07
| | | | | | | | | | | | | dot_bbox() wasn't taking into account the new size of the dots, so sometimes a rectangle of the grid would be redrawn without a partial dot it should have contained, because nothing had noticed that that dot overlapped that rectangle. Actually I'm not sure why this bug wasn't happening _before_ I enlarged the dots, because the previous code seemed to think dots had a fixed size in pixels regardless of tile size, which wasn't even true _before_ my recent commit 4de9836bc8c36cd. Perhaps it did occur, just never while I was watching.
* Isolate icons build from the running user's preferences.Simon Tatham2023-05-05
| | | | | | | Preferences that adjust the display, such as Pearl graphics style or Light Up lit-blobs toggling, shouldn't affect the official icons, even if a ~/.config/sgt-puzzles exists in the account that builds the puzzles.
* Windows: reorganise menu ids.Simon Tatham2023-05-03
| | | | | | | | | | | | | | | | | | | A user pointed out today that IDM_PREFS overlaps the second preset, because I forgot that IDM_PRESETS was not a single id but the base for an open-ended series. Looking more closely, there are several other problems with the IDM_* constants. IDM_GAMES (used in COMBINED mode) shouldn't be at an arbitrary distance _above_ IDM_PRESETS, because that risks a collision; instead, the games' and presets' ids should interleave. Also, the ids above IDM_GAMES were going up in steps of 1, which should have been 0x10, for the usual reason that the bottom four bits of the id aren't guaranteed. And IDM_KEYEMUL was completely unused (I suspect it was part of the discarded WinCE support). Now the #defines that are the bases of series are labelled as IDM_FOO_BASE; they interleave as they should; and there's a clear comment.
* midend_apply_prefs: apply prefs to the right ui.Simon Tatham2023-05-02
| | | | | The function takes a game_ui pointer as an argument, and then ignores it and unconditionally applies the midend's saved preferences to me->ui.
* Untangle: add a 'snap to grid' user preference.Simon Tatham2023-05-01
| | | | | | | | | | | | | | | | | | | Requested by a user who otherwise found themself spending too much time struggling to get lines nicely horizontal or vertical. The implementation is easy, but the question is what size of grid is appropriate. Untangle's own generated games are constructed by making a planar graph drawn on an extremely coarse grid - but snapping to _that_ grid would give away information about the puzzle solution, and also, Untangle wouldn't know any similar information about graphs generated by any other method. So a better approach is to choose a size of grid that guarantees that _any_ graph with n vertices can be drawn on it with nonintersecting straight edges. That sounds like a tricky maths problem - but happily, the solution is given in a book I already had a copy of. References in a comment (plus a proof of a pedantic followup detail about multiple planar embeddings).
* Untangle: replace manual int64 bodging with int64_t.Simon Tatham2023-05-01
| | | | | | Where possible, that is. If our compilation environment has provided int64_t, we can just make our int64 type be that, and not have to mess around with multi-word arithmetic at all.
* Replace check of __STDC_VERSION__ with HAVE_STDINT_H.Simon Tatham2023-05-01
| | | | | | Just spotted this in puzzles.h. We don't need to guess any more from the C standards version whether stdint.h is available: we've actually checked _precisely that_ in cmake, so it's better to use the answer.
* Loopy: slightly increase the size of dots.Simon Tatham2023-04-29
| | | | | | | | | | | In the Hats tiling, each tile has two consecutive edges collinear. When both edges are turned on, i.e. drawn in black just like the dot, it becomes _just slightly_ tricky to spot the dot in the middle of that straight line, which is important if you're counting edges around the face to check a clue. Increasing the radius from 2/32 to 3/32 of tile size is far too big. 2.5/32 seems reasonable, though.
* hat-test: fix memory leaks.Simon Tatham2023-04-29
| | | | I ran this again today with Leak Sanitiser on, which complained.
* Pattern: Reduce row clue spacing if there are lots of themBen Harris2023-04-24
| | | | | | | | Normally, we put two spaces between row clues, but if there are a lot then even with a smaller font size they might overflow the left edge of the window. To compensate, go down to one space between clues instead of two if there are a lot of them. On my laptop the GTK build demonstrates overflow with "13x1:1//1//1//1//1//1//1/1.1.1.1.1.1.1".
* Pattern: switch to small font when there are many row cluesBen Harris2023-04-24
| | | | | | | | | | | | | | | | | | | | If you have a particularly large number of clues in a row, they can end up falling off the left edge of the window. This used not to be a problem because the rendering code would squash them closer together if necessary. But then I switched to drawing them all as a single string (so that two-digit row clues would get enough space with a large font) and that broke the old mechanism. Now we detect if there are enough clues that our conservative guess at the string length looks like overflowing in the big font, and switch to the small one if necessary. If we had a drawing call to measure a string then we could be cleverer about this, but we don't. This problem can be demonstrated with "7x1:1//1//1//1/1.1.1.1" in the GTK port with the fonts my laptop has. I think overflow can still occur even with a small font, so once I've demonstrated that I'll try to fix it.
* Correct a comment in Pattern's clue-drawing codeBen Harris2023-04-24
|
* Emscripten: change the localStorage key used for preferences.Simon Tatham2023-04-24
| | | | | | | | | | | | I picked pathname + "#preferences" because Ben suggested either that or pathname + "/preferences", and I thought the former sounded neater. But Ben now suggests that it might be better to avoid using # in the key, just in case anyone should later want to use the whole URL _including_ the fragment ID as the key for some other localStorage usage - for example, autosaved progress per puzzle _instance_, keying off the puzzle URL with a fragment ID in the game description. So, per Ben's replacement suggestion, change the "#" to a space.
* Support user preferences in the Emscripten frontend.Simon Tatham2023-04-24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Here, user preferences are stored in localStorage, so that they can persist when you come back to the same puzzle page later. localStorage is global across a whole web server, which means we need to take care to put our uses of it in a namespace reasonably unlikely to collide with unrelated web pages on the same server. Ben suggested that a good way to do this would be to store things in localStorage under keys derived from location.pathname. In this case I've appended a fragment id "#preferences" to that, so that space alongside it remains for storing other things we might want in future (such as serialised saved-game files used as quick-save slots). When loading preferences, I've chosen to pass the whole serialised preferences buffer from Javascript to C as a single C string argument to a callback, rather than reusing the existing system for C to read the save file a chunk at a time. Partly that's because preferences data is bounded in size whereas saved games can keep growing; also it's because the way I'm storing preferences data means it will be a UTF-8 string, and I didn't fancy trying to figure out byte offsets in the data on the JS side. I think at this point I should stop keeping a list in the docs of which frontends support preferences. Most of the in-tree ones do now, and that means the remaining interesting frontends are ones I don't have a full list of. At this moment I guess no out-of-tree frontends support preferences (unless someone is _very_ quick off the mark), but as and when that changes, I won't necessarily know, and don't want to have to keep updating the docs when I find out.
* emcc.c: remove savefile_read_ctx.Simon Tatham2023-04-24
| | | | | | It wasn't ever used! Looks as if I pasted it in here from one of the other implementations, before realising that wasn't how I was going to read save files at all.
* emcc.c: missing (void) in a function definition.Simon Tatham2023-04-24
| | | | This isn't C++, ahem.
* Fix bounds check in buffer_append.Simon Tatham2023-04-24
| | | | | | | | | | We're about to append one character to the buffer _and_ put a \0 after it, so we need the buffer to be at least _two_ characters longer than where the current position is. I think this bug would have had a hard time showing up in normal use, but I managed to trigger it by completely messing up a prototype Emscripten preferences implementation, and a good thing too.
* Support user preferences in the Mac frontend.Simon Tatham2023-04-24
| | | | | | The low-level load and save routines are basically copy-pasted from gtk.c, with only minor changes to deal with the different locally appropriate config file location and the lack of savefile_write_ctx.