the 'Killer Sudoku' puzzle type. As a side effect I've had to
increase the default tile size of Solo, so that the extra numbers
drawn in the squares in Killer mode were still legible.
[originally from svn r8455]
_conditionally_ able to format the current puzzle as text to be sent
to the clipboard. For instance, if a game were to support playing on
a square grid and on other kinds of grid such as hexagonal, then it
might reasonably feel that only the former could be sensibly
rendered in ASCII art; so it can now arrange for the "Copy" menu
item to be greyed out depending on the game_params.
To do this I've introduced a new backend function
(can_format_as_text_now()), and renamed the existing static backend
field "can_format_as_text" to "can_format_as_text_ever". The latter
will cause compile errors for anyone maintaining a third-party front
end; if any such person is reading this, I apologise to them for the
inconvenience, but I did do it deliberately so that they'd know to
update their front end.
As yet, no checked-in game actually uses this feature; all current
games can still either copy always or copy never.
[originally from svn r8161]
suggested by IWJ last night: grid generation can immediately choose
an entire grid row randomly, since all that's doing is nailing down
the names of the numbers, and that gets the whole thing started more
efficiently. But the main difference is that now grid generation is
given only area^2 steps to come up with a filled grid, and then cut
off unceremoniously, causing grid generation to fail and be retried
from scratch. This seems to prevent hangups on jigsaw layouts that
admit few useful solutions, by changing layout constantly. 9j
puzzles now generate at a sensible rate, and as an added bonus so do
5x5 normal puzzles, which they never used to.
[originally from svn r7978]
failed to point out a declaration after a statement, and gcc's
linker was clever enough to optimise the call to divvy_rectangle()
out of solosolver so that I didn't have to include divvy.c in that.)
[originally from svn r7975]
(require both main diagonals to have one of every digit in addition
to all the usual constraints) and Jigsaw Sudoku (replace the array
of rectangular sub-blocks with the sub-blocks being random
polyominoes). To implement the latter, I've moved my `divvy.c'
library routine out of the `unfinished' subdirectory.
Jigsaw mode is currently an undocumented feature: you enable it by
setting the rows parameter to 1 (and the columns parameter to your
desired grid size, which unlike normal Sudoku can be anything you
like including a prime number). The reason it's undocumented is
because generation times are not yet reliably short: sometimes
generating a jigsaw-type puzzle can hang for hours and still get
nowhere. (The algorithm should terminate in principle, but not in
any time you're prepared to wait.) I _think_ I know how to solve
this, but have yet to try it. Until then, jigsaw mode will remain a
hidden feature.
Printing of X-type puzzles is also substandard at present, because
the current print-colour API replaces the desired light shading of
the X-cells with heavy diagonal hatching. I plan to adjust the API
imminently to address this.
[originally from svn r7974]
about eating the letter `d' (for `diagonal') when it appears in a
symmtery description: it should only be used after `m', because
mirror symmetry is the only type that can be diagonal. This was
causing parsing of the parameter description `3x3adu' to produce the
wrong answer: the d would be swallowed, then the u ignored for being
incomprehensible, and you'd get default Trivial difficulty.
[originally from svn r7386]
is mostly done with ifdefs in windows.c; so mkfiles.pl generates a
new makefile (Makefile.wce) and Recipe enables it, but it's hardly
any different from Makefile.vc apart from a few definitions at the
top of the files.
Currently the PocketPC build is not enabled in the build script, but
with any luck I'll be able to do so reasonably soon.
[originally from svn r7337]
zero as a valid puzzle symbol, it can support at most 35 symbols,
not 36. (This is largely academic since IME anything above about 25
is impractical to generate, but there we go.)
[originally from svn r7115]
function, since it took no parameters by which to vary its decision,
and in any case it's hard to imagine a game which only
_conditionally_ wants a status bar. Changed it into a boolean data
field in the backend structure.
[originally from svn r6417]
was actually using it, and also it wasn't being called again for
different game states or different game parameters, so it would have
been a mistake to depend on anything in that game state. Games are
now expected to commit in advance to a single fixed list of all the
colours they will ever need, which was the case in practice already
and simplifies any later port to a colour-poor platform. Also this
change has removed a lot of unnecessary faff from midend_colours().
[originally from svn r6416]
in the game description, the solver will fail to notice it and
overrun an array leading to assertion failure, silent wrong answers
or (in extreme cases) segfaults. Hence, validate_desc() now spots
them and kicks them out.
[originally from svn r6383]
game_print(), wherever feasible. This fixes a specific bug in Loopy
(James H's new field ds->linewidth wasn't being set up, leading to
corrupted print output), but I've made the change in all affected
files because it also seems like a generally good idea to encourage
it for future games, to prevent other problems of this type.
There is one slight snag, which is that Map _can't_ do this because
its game_set_size() also initialises a blitter. I could fix this by
abstracting the common parts of Map's game_set_size() out into a
subfunction called by game_set_size() and also called directly by
game_print(); alternatively, I could introduce a means of
determining whether a `drawing *' was for screen or printing use.
Not sure which yet.
[originally from svn r6340]
r6160, I completely failed to ensure that generated grids were _at
most_ the required difficulty. It appears to have been only random
chance that prevented a request for a Trivial puzzle from producing
Extreme. Here's a one-line fix.
[originally from svn r6298]
[r6160 == e55838bc9b0d173ca539d0cfe714495b5c12b9dd]
a non-recursive level above Easy, which therefore moves the
recursive Hard mode further up still. Play-testing suggests that in
fact Tricky is often _harder_ than the old Hard mode, since the
latter had limited depth of recursion and would therefore spot
complex deductions only if it happened to start a recursion on the
right square; Tricky may be limited in the sophistication of its
complex deductions, but it never misses one, so its puzzles tend to
be hard all over.
Also in this checkin, a new source file `nullfe.c', containing all
the annoying stub functions required to make command-line solvers
link successfully. James wrote this for (the new) lightupsolver, and
I've used it to simplify the other stand-alone solvers.
[originally from svn r6254]
level: positional set elimination (which is so obvious I really
should have thought of it myself, though it's tricky to spot) and
forcing chains (which are a type of one-level proof by
contradiction, findable through a simple breadth-first search
without requiring recursion, but so ludicrously powerful that they
are able to solve _two thirds_ of grids that the pre-Extreme Solo
generated and rated as Unreasonable).
Of course this makes Unreasonable mode harder still...
[originally from svn r6239]
independently discovered an advanced reasoning technique in Map, and
then it occurred to me that since Solo can also be considered as a
graph-colouring game the same technique ought to be applicable. And
it is; so here's a new difficulty level, `Extreme', which sits just
above Advanced. Grids graded `Extreme' by new-Solo will of course
fall into old-Solo's `Unreasonable' category (since they're not
soluble using the old set of non-recursive methods). A brief and
unscientific experiment suggests that about one in six Unreasonable
grids generated by old-Solo are classified Extreme by the new
solver; so the remaining Unreasonable mode (now containing a subset
of the grids it used to) hasn't actually become much harder.
[originally from svn r6209]
as seen by the back ends from the one implemented by the front end,
and shoved a piece of middleware (drawing.c) in between to permit
interchange of multiple kinds of the latter. I've also added a
number of functions to the drawing API to permit printing as well as
on-screen drawing, and retired print.py in favour of integrated
printing done by means of that API.
The immediate visible change is that print.py is dead, and each
puzzle now does its own printing: where you would previously have
typed `print.py solo 2x3', you now type `solo --print 2x3' and it
should work in much the same way.
Advantages of the new mechanism available right now:
- Map is now printable, because the new print function can make use
of the output from the existing game ID decoder rather than me
having to replicate all those fiddly algorithms in Python.
- the new print functions can cope with non-initial game states,
which means each puzzle supporting --print also supports
--with-solutions.
- there's also a --scale option permitting users to adjust the size
of the printed puzzles.
Advantages which will be available at some point:
- the new API should permit me to implement native printing
mechanisms on Windows and OS X.
[originally from svn r6190]
clues from a filled grid, was using the algorithm
- loop over the whole grid looking for a clue (or symmetry group of
clues) which can be safely removed
- remove it
- loop over the whole grid again, and so on.
This was due to my vague feeling that removing one clue might affect
whether another can be removed. Of course this can happen - two
clues can be alternative ways of deducing the same vital fact so
that removing one makes the other necessary - but what _can't_
happen is for removing one clue to make another _become_ removable,
since you can only do that by _adding_ information. In other words,
after testing a clue and determining that it can't be removed, you
never need to test it again. Thus, a much simpler algorithm is
- loop over the possible clues (or symmetry groups) _once_, in a
random order
- for each clue (group), if it is removable, remove it.
This still guarantees to leave the grid in a state where no further
clues can be removed, but it greatly cuts down puzzle generation
time and also simplifies the code. I am a fool for not having
spotted this in three and a half months!
[originally from svn r6160]
more than 36 distinct symbols (it runs out of alphanumerics), check
this in validate_params. I hate to do this, since I like puzzle
sizes to at least be open-ended in _principle_, but in this case
there's a fundamental UI limitation which won't be fixed by getting
a faster CPU.
[originally from svn r6098]
- use the new `shuffle' utility function in a couple of places
- remove the random_state parameter from solver(). It was there
because I initially wanted to use the same solver for grid
generation, but since I had to abandon that plan the solver now
doesn't have any need for randomness at all.
[originally from svn r6093]
whether the timer is currently going is no longer solely dependent
on the current game_state: it can be dependent on more persistent
information stored in the game_ui. In particular, Mines now freezes
the timer permanently once you complete a grid for the first time,
so that you can then backtrack through your solution process without
destroying the information about how long it took you the first time
through.
[originally from svn r6088]
capability added to it, to be used only when all else fails, and is
simply called `solver'. This means that:
- solving of 5x5 Trivial grids using the `Solve' function, which
previously hung for ages because rsolve happened to take a wrong
turning at the start, is now zippy
- solosolver doesn't require the confusing -r and -n options
- solosolver can show its working even for Unreasonable grids.
Unfortunately, the new unified solver still isn't suitable for grid
generation. After it proved to be so much faster at solving 5x5s, I
hoped to be able to substitute it for rsolve during generation and
gain additional speed in 5x5 generation too; but no luck, because
it's slower _per recursion level_, and although during solving it
makes up for this by needing very few levels, there is a lot of
_unavoidable_ recursion during generation, especially at 5x5. A
hybrid strategy which starts off with rsolve and switches to the
unified solver at a critical point proved unsatisfactory as well,
because the critical point changes depending on the vagaries of the
recursion and can't be pinpointed easily. So rsolve is still in
there, only renamed `gridgen' because that's now all it's good for.
[originally from svn r6077]
encode_params(). This is necessary for cases where generation-time parameters
that are normally omitted from descriptive IDs can place restrictions on other
parameters; in particular, when the default value of a relevant generation-time
parameter is not the one used to generate the descriptive ID, validation could
reject self-generated IDs (e.g., Net `5x2w:56182ae7c2', and some cases in
`Pegs').
[originally from svn r6068]
command-line programs (solosolver, patternsolver, mineobfusc) to be
built as part of the normal Makefiles. This means mkfiles.pl now has
the capability to compile a source file more than once with
different #defines. Also, fixes for those auxiliary programs and one
fix in midend.c which the Borland compiler objected to while I was
testing its makefile generation.
[originally from svn r6066]
unpleasant and requiring lots of special cases to be taken care of
by every single game. The new interface exposes an integer `tile
size' or `scale' parameter to the midend and provides two much
simpler routines: one which computes the pixel window size given a
game_params and a tile size, and one which is given a tile size and
must set up a drawstate appropriately. All the rest of the
complexity is handled in the midend, mostly by binary search, so
grubby special cases only have to be dealt with once.
[originally from svn r6059]
constraint: because some front ends interpret `draw filled shape' to
mean `including its boundary' while others interpret it to mean `not
including its boundary' (and X seems to vacillate between the two
opinions as it moves around the shape!), you MUST NOT draw a filled
shape only. You can fill in one colour and outline in another, you
can fill or outline in the same colour, or you can just outline, but
just filling is a no-no.
This leads to a _lot_ of double calls to these functions, so I've
changed the interface. draw_circle() and draw_polygon() now each
take two colour arguments, a fill colour (which can be -1 for none)
and an outline colour (which must be valid). This should simplify
code in the game back ends, while also reducing the possibility for
coding error.
[originally from svn r6047]
- most game_size() functions now work in doubles internally and
round to nearest, meaning that they have less tendency to try to
alter a size they returned happily from a previous call
- couple of fiddly fixes (memory leaks, precautionary casts in
printf argument lists)
- midend_deserialise() now constructs an appropriate drawstate,
which I can't think how I overlooked myself since I _thought_ I
went through the entire midend structure field by field!
[originally from svn r6041]
retired, and replaced with a simple string. Most of the games which
use it simply encode the string in the same way that the Solve move
will also be encoded, i.e. solve_game() simply returns
dupstr(aux_info). Again, this is a better approach than writing
separate game_aux_info serialise/deserialise functions because doing
it this way is self-testing (the strings are created and parsed
during the course of any Solve operation at all).
[originally from svn r6029]
and restore anything vitally important in the game_ui. Most of the
game_ui is expected to be stuff about cursor positions and currently
active mouse drags, so it absolutely _doesn't_ want to be preserved
over a serialisation; but one or two things would be disorienting or
outright wrong to reset, such as the Net origin position and the
Mines death counter.
[originally from svn r6026]
split into two functions. The first, interpret_move(), takes all the
arguments that make_move() used to get and may have the usual side
effects of modifying the game_ui, but instead of returning a
modified game_state it instead returns a string description of the
move to be made. This string description is then passed to a second
function, execute_move(), together with an input game_state, which
is responsible for actually producing the new state. (solve_game()
also returns a string to be passed to execute_move().)
The point of this is to work towards being able to serialise the
whole of a game midend into a byte stream such as a disk file, which
will eventually support save and load functions in the desktop
puzzles, as well as restoring half-finished games after a quit and
restart in James Harvey's Palm port. Making each game supply a
convert-to-string function for its game_state format would have been
an unreliable way to do this, since those functions would not have
been used in normal play, so they'd only have been tested when you
actually tried to save and load - a recipe for latent bugs if ever I
heard one. This way, you won't even be able to _make_ a move if
execute_move() doesn't work properly, which means that if you can
play a game at all I can have pretty high confidence that
serialising it will work first time.
This is only the groundwork; there will be more checkins to come on
this theme. But the major upheaval should now be done, and as far as
I can tell everything's still working normally.
[originally from svn r6024]
symmetry which were not implemented in Solo. Now they are.
In the process I've completely retired symmetry_limit() on the
grounds that some of the new symmetries do not have a rectangular
base region; instead I determine the base region by going through
the grid and finding every square which is not transformed into a
lexicographically lower square by any symmetry operation. This means
that adding new symmetries is now _only_ a matter of encoding the
actual transformation rules.
[originally from svn r5965]
in terms of a constant TILE_SIZE (or equivalent). Here's a
surprisingly small patch which switches this constant into a
run-time variable.
The only observable behaviour change should be on Windows, which
physically does not permit the creation of windows larger than the
screen; if you try to create a puzzle (Net makes this plausible)
large enough to encounter this restriction, the Windows front end
should automatically re-adjust the puzzle's tile size so that it
does fit within the available space.
On GTK, I haven't done this, on the grounds that X _does_ permit
windows larger than the screen, and many X window managers already
provide the means to navigate around such a window. Gareth said he'd
rather navigate around a huge Net window than have it shrunk to fit
on one screen. I'm uncertain that this makes sense for all puzzles -
Pattern in particular strikes me as something that might be better
off shrunk to fit - so I may have to change policy later or make it
configurable.
On OS X, I also haven't done automatic shrinkage to fit on one
screen, largely because I didn't have the courage to address the
question of multiple monitors and what that means for the entire
concept :-)
[originally from svn r5913]
of these recently) whose job is to update a game_ui to be consistent
with a new game_state. This is called by midend.c in every situation
where the current game_state changes _other_ than as a result of
make_move (Undo, Redo, Restart, Solve).
The introduction of this function allows a game_ui to contain
information about selections or highlights within a game_state which
simply wouldn't make sense when transferred to another game_state.
In particular, I've used it to fix a subtle bug in Solo whereby,
although you couldn't right-click to pencil-mode highlight a filled
square, you could _get_ a pencil-mode highlight in a filled square
if you used Undo and Redo. (Undo to before the square was filled,
right-click to highlight it, then Redo. Alternatively, left-click
and clear the square, right-click to highlight it, then Undo.)
[originally from svn r5912]
and positioned according to how many there are in the cell, rather
than how many distinct digits there are in the entire puzzle. This
means that 4x4 Solo can now be played with pencil marks without
_too_ much difficulty; the marks will still get a bit crowded if you
have more than 12 in the same square, but with luck that shouldn't
happen often, and as long as you're down in the 2-9 range things
should be entirely legible.
[originally from svn r5909]