mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 08:01:30 -07:00
New puzzle: `Slant', picked from the Japanese-language section of
nikoli.co.jp (which has quite a few puzzles that they don't seem to have bothered to translate into English). Minor structural change: the disjoint set forest code used in the Net solver has come in handy again, so I've moved it out into its own module dsf.c. [originally from svn r6155]
This commit is contained in:
9
Recipe
9
Recipe
@ -15,15 +15,16 @@
|
|||||||
|
|
||||||
WINDOWS = windows user32.lib gdi32.lib comctl32.lib comdlg32.lib
|
WINDOWS = windows user32.lib gdi32.lib comctl32.lib comdlg32.lib
|
||||||
COMMON = midend misc malloc random version
|
COMMON = midend misc malloc random version
|
||||||
NET = net tree234
|
NET = net tree234 dsf
|
||||||
NETSLIDE = netslide tree234
|
NETSLIDE = netslide tree234
|
||||||
MINES = mines tree234
|
MINES = mines tree234
|
||||||
FLIP = flip tree234
|
FLIP = flip tree234
|
||||||
PEGS = pegs tree234
|
PEGS = pegs tree234
|
||||||
UNTANGLE = untangle tree234
|
UNTANGLE = untangle tree234
|
||||||
|
SLANT = slant dsf
|
||||||
|
|
||||||
ALL = list NET NETSLIDE cube fifteen sixteen rect pattern solo twiddle
|
ALL = list NET NETSLIDE cube fifteen sixteen rect pattern solo twiddle
|
||||||
+ MINES samegame FLIP guess PEGS dominosa UNTANGLE blackbox
|
+ MINES samegame FLIP guess PEGS dominosa UNTANGLE blackbox SLANT
|
||||||
|
|
||||||
net : [X] gtk COMMON NET
|
net : [X] gtk COMMON NET
|
||||||
netslide : [X] gtk COMMON NETSLIDE
|
netslide : [X] gtk COMMON NETSLIDE
|
||||||
@ -42,6 +43,7 @@ pegs : [X] gtk COMMON PEGS
|
|||||||
dominosa : [X] gtk COMMON dominosa
|
dominosa : [X] gtk COMMON dominosa
|
||||||
untangle : [X] gtk COMMON UNTANGLE
|
untangle : [X] gtk COMMON UNTANGLE
|
||||||
blackbox : [X] gtk COMMON blackbox
|
blackbox : [X] gtk COMMON blackbox
|
||||||
|
slant : [X] gtk COMMON SLANT
|
||||||
|
|
||||||
# Auxiliary command-line programs.
|
# Auxiliary command-line programs.
|
||||||
solosolver : [U] solo[STANDALONE_SOLVER] malloc
|
solosolver : [U] solo[STANDALONE_SOLVER] malloc
|
||||||
@ -71,6 +73,7 @@ pegs : [G] WINDOWS COMMON PEGS
|
|||||||
dominosa : [G] WINDOWS COMMON dominosa
|
dominosa : [G] WINDOWS COMMON dominosa
|
||||||
untangle : [G] WINDOWS COMMON UNTANGLE
|
untangle : [G] WINDOWS COMMON UNTANGLE
|
||||||
blackbox : [G] WINDOWS COMMON blackbox
|
blackbox : [G] WINDOWS COMMON blackbox
|
||||||
|
slant : [G] WINDOWS COMMON SLANT
|
||||||
|
|
||||||
# Mac OS X unified application containing all the puzzles.
|
# Mac OS X unified application containing all the puzzles.
|
||||||
Puzzles : [MX] osx osx.icns osx-info.plist COMMON ALL
|
Puzzles : [MX] osx osx.icns osx-info.plist COMMON ALL
|
||||||
@ -162,7 +165,7 @@ FORCE:
|
|||||||
install:
|
install:
|
||||||
for i in cube net netslide fifteen sixteen twiddle \
|
for i in cube net netslide fifteen sixteen twiddle \
|
||||||
pattern rect solo mines samegame flip guess \
|
pattern rect solo mines samegame flip guess \
|
||||||
pegs dominosa untangle blackbox; do \
|
pegs dominosa untangle blackbox slant; do \
|
||||||
$(INSTALL_PROGRAM) -m 755 $$i $(DESTDIR)$(gamesdir)/$$i; \
|
$(INSTALL_PROGRAM) -m 755 $$i $(DESTDIR)$(gamesdir)/$$i; \
|
||||||
done
|
done
|
||||||
!end
|
!end
|
||||||
|
28
dsf.c
Normal file
28
dsf.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* dsf.c: two small functions to handle a disjoint set forest,
|
||||||
|
* which is a data structure useful in any solver which has to
|
||||||
|
* worry about avoiding closed loops.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int dsf_canonify(int *dsf, int val)
|
||||||
|
{
|
||||||
|
int v2 = val;
|
||||||
|
|
||||||
|
while (dsf[val] != val)
|
||||||
|
val = dsf[val];
|
||||||
|
|
||||||
|
while (v2 != val) {
|
||||||
|
int tmp = dsf[v2];
|
||||||
|
dsf[v2] = val;
|
||||||
|
v2 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsf_merge(int *dsf, int v1, int v2)
|
||||||
|
{
|
||||||
|
v1 = dsf_canonify(dsf, v1);
|
||||||
|
v2 = dsf_canonify(dsf, v2);
|
||||||
|
dsf[v2] = v1;
|
||||||
|
}
|
2
list.c
2
list.c
@ -31,6 +31,7 @@ extern const game pegs;
|
|||||||
extern const game rect;
|
extern const game rect;
|
||||||
extern const game samegame;
|
extern const game samegame;
|
||||||
extern const game sixteen;
|
extern const game sixteen;
|
||||||
|
extern const game slant;
|
||||||
extern const game solo;
|
extern const game solo;
|
||||||
extern const game twiddle;
|
extern const game twiddle;
|
||||||
extern const game untangle;
|
extern const game untangle;
|
||||||
@ -50,6 +51,7 @@ const game *gamelist[] = {
|
|||||||
&rect,
|
&rect,
|
||||||
&samegame,
|
&samegame,
|
||||||
&sixteen,
|
&sixteen,
|
||||||
|
&slant,
|
||||||
&solo,
|
&solo,
|
||||||
&twiddle,
|
&twiddle,
|
||||||
&untangle,
|
&untangle,
|
||||||
|
23
net.c
23
net.c
@ -382,29 +382,6 @@ static char *validate_params(game_params *params, int full)
|
|||||||
* avoidance is required.
|
* avoidance is required.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int dsf_canonify(int *dsf, int val)
|
|
||||||
{
|
|
||||||
int v2 = val;
|
|
||||||
|
|
||||||
while (dsf[val] != val)
|
|
||||||
val = dsf[val];
|
|
||||||
|
|
||||||
while (v2 != val) {
|
|
||||||
int tmp = dsf[v2];
|
|
||||||
dsf[v2] = val;
|
|
||||||
v2 = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dsf_merge(int *dsf, int v1, int v2)
|
|
||||||
{
|
|
||||||
v1 = dsf_canonify(dsf, v1);
|
|
||||||
v2 = dsf_canonify(dsf, v2);
|
|
||||||
dsf[v2] = v1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct todo {
|
struct todo {
|
||||||
unsigned char *marked;
|
unsigned char *marked;
|
||||||
int *buffer;
|
int *buffer;
|
||||||
|
56
print.py
56
print.py
@ -365,13 +365,67 @@ def dominosa_format(s):
|
|||||||
((x+0.5)*gridpitch, (h-y-0.5)*gridpitch, grid[y*w+x]))
|
((x+0.5)*gridpitch, (h-y-0.5)*gridpitch, grid[y*w+x]))
|
||||||
return ret.coords, ret.s
|
return ret.coords, ret.s
|
||||||
|
|
||||||
|
def slant_format(s):
|
||||||
|
# Parse the game ID.
|
||||||
|
ret = Holder()
|
||||||
|
ret.s = ""
|
||||||
|
params, seed = string.split(s, ":")
|
||||||
|
w, h = map(string.atoi, string.split(params, "x"))
|
||||||
|
W = w+1
|
||||||
|
H = h+1
|
||||||
|
grid = []
|
||||||
|
while len(seed) > 0:
|
||||||
|
if seed[0] in string.lowercase:
|
||||||
|
grid.extend([-1] * (ord(seed[0]) - ord('a') + 1))
|
||||||
|
seed = seed[1:]
|
||||||
|
elif seed[0] in "01234":
|
||||||
|
grid.append(string.atoi(seed[0]))
|
||||||
|
seed = seed[1:]
|
||||||
|
assert W * H == len(grid)
|
||||||
|
# I'm going to arbitrarily choose to use 7pt text for the
|
||||||
|
# numbers, and a 14pt grid pitch.
|
||||||
|
textht = 7
|
||||||
|
gridpitch = 14
|
||||||
|
radius = textht * 2.0 / 3.0
|
||||||
|
# Set up coordinate system.
|
||||||
|
pw = gridpitch * w
|
||||||
|
ph = gridpitch * h
|
||||||
|
ret.coords = (pw/2, pw/2, ph/2, ph/2)
|
||||||
|
psprint(ret, "%g %g translate" % (-ret.coords[0], -ret.coords[2]))
|
||||||
|
# Draw round the grid exterior, thickly.
|
||||||
|
psprint(ret, "newpath 1 setlinewidth")
|
||||||
|
psprint(ret, "0 0 moveto 0 %g rlineto %g 0 rlineto 0 %g rlineto" % \
|
||||||
|
(h * gridpitch, w * gridpitch, -h * gridpitch))
|
||||||
|
psprint(ret, "closepath stroke")
|
||||||
|
# Draw the internal grid lines, _very_ thin (the player will
|
||||||
|
# need to draw over them visibly).
|
||||||
|
psprint(ret, "newpath 0.01 setlinewidth")
|
||||||
|
for x in xrange(1,w):
|
||||||
|
psprint(ret, "%g 0 moveto 0 %g rlineto" % (x * gridpitch, h * gridpitch))
|
||||||
|
for y in xrange(1,h):
|
||||||
|
psprint(ret, "0 %g moveto %g 0 rlineto" % (y * gridpitch, w * gridpitch))
|
||||||
|
psprint(ret, "stroke")
|
||||||
|
# And draw the numbers.
|
||||||
|
psprint(ret, "/Helvetica findfont %g scalefont setfont" % textht)
|
||||||
|
for y in xrange(H):
|
||||||
|
for x in xrange(W):
|
||||||
|
n = grid[y*W+x]
|
||||||
|
if n >= 0:
|
||||||
|
psprint(ret, "newpath %g %g %g 0 360 arc" % \
|
||||||
|
((x)*gridpitch, (h-y)*gridpitch, radius),
|
||||||
|
"gsave 1 setgray fill grestore stroke")
|
||||||
|
psprint(ret, "%g %g (%d) ctshow" % \
|
||||||
|
((x)*gridpitch, (h-y)*gridpitch, n))
|
||||||
|
return ret.coords, ret.s
|
||||||
|
|
||||||
formatters = {
|
formatters = {
|
||||||
"net": net_format,
|
"net": net_format,
|
||||||
"rect": rect_format,
|
"rect": rect_format,
|
||||||
"rectangles": rect_format,
|
"rectangles": rect_format,
|
||||||
"pattern": pattern_format,
|
"pattern": pattern_format,
|
||||||
"solo": solo_format,
|
"solo": solo_format,
|
||||||
"dominosa": dominosa_format
|
"dominosa": dominosa_format,
|
||||||
|
"slant": slant_format
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sys.argv) < 3:
|
if len(sys.argv) < 3:
|
||||||
|
74
puzzles.but
74
puzzles.but
@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
\define{by} \u00D7{x}
|
\define{by} \u00D7{x}
|
||||||
|
|
||||||
|
\define{dash} \u2013{-}
|
||||||
|
|
||||||
This is a collection of small one-player puzzle games.
|
This is a collection of small one-player puzzle games.
|
||||||
|
|
||||||
\copyright This manual is copyright 2004-5 Simon Tatham. All rights
|
\copyright This manual is copyright 2004-5 Simon Tatham. All rights
|
||||||
@ -43,9 +45,9 @@ both, and have more recently done a port to Mac OS X as well. When I
|
|||||||
find (or perhaps invent) further puzzle games that I like, they'll
|
find (or perhaps invent) further puzzle games that I like, they'll
|
||||||
be added to this collection and will immediately be available on
|
be added to this collection and will immediately be available on
|
||||||
both platforms. And if anyone feels like writing any other front
|
both platforms. And if anyone feels like writing any other front
|
||||||
ends - PocketPC, Mac OS pre-10, or whatever it might be - then all
|
ends \dash PocketPC, Mac OS pre-10, or whatever it might be \dash
|
||||||
the games in this framework will immediately become available on
|
then all the games in this framework will immediately become
|
||||||
another platform as well.
|
available on another platform as well.
|
||||||
|
|
||||||
The actual games in this collection were mostly not my invention; they
|
The actual games in this collection were mostly not my invention; they
|
||||||
are re-implementations of existing game concepts within my portable
|
are re-implementations of existing game concepts within my portable
|
||||||
@ -1208,12 +1210,12 @@ time (but always one that is known to have a solution).
|
|||||||
|
|
||||||
\cfg{winhelp-topic}{games.dominosa}
|
\cfg{winhelp-topic}{games.dominosa}
|
||||||
|
|
||||||
A normal set of dominoes - that is, one instance of every (unordered)
|
A normal set of dominoes \dash that is, one instance of every
|
||||||
pair of numbers from 0 to 6 - has been arranged irregularly into a
|
(unordered) pair of numbers from 0 to 6 \dash has been arranged
|
||||||
rectangle; then the number in each square has been written down and
|
irregularly into a rectangle; then the number in each square has
|
||||||
the dominoes themselves removed. Your task is to reconstruct the
|
been written down and the dominoes themselves removed. Your task is
|
||||||
pattern by arranging the set of dominoes to match the provided array
|
to reconstruct the pattern by arranging the set of dominoes to match
|
||||||
of numbers.
|
the provided array of numbers.
|
||||||
|
|
||||||
This puzzle is widely credited to O. S. Adler, and takes part of its
|
This puzzle is widely credited to O. S. Adler, and takes part of its
|
||||||
name from those initials.
|
name from those initials.
|
||||||
@ -1430,6 +1432,60 @@ using a different number to the original solution is still acceptable,
|
|||||||
if all the laser inputs and outputs match.
|
if all the laser inputs and outputs match.
|
||||||
|
|
||||||
|
|
||||||
|
\C{slant} \i{Slant}
|
||||||
|
|
||||||
|
\cfg{winhelp-topic}{games.slant}
|
||||||
|
|
||||||
|
You have a grid of squares. Your aim is to draw a diagonal line
|
||||||
|
through each square, and choose which way each line slants so that
|
||||||
|
the following conditions are met:
|
||||||
|
|
||||||
|
\b The diagonal lines never form a loop.
|
||||||
|
|
||||||
|
\b Any point with a circled number has precisely that many lines
|
||||||
|
meeting at it. (Thus, a 4 is the centre of a cross shape, whereas a
|
||||||
|
zero is the centre of a diamond shape \dash or rather, a partial
|
||||||
|
diamond shape, because a zero can never appear in the middle of the
|
||||||
|
grid because that would immediately cause a loop.)
|
||||||
|
|
||||||
|
Credit for this puzzle goes to \i{Nikoli} \k{nikoli-slant}.
|
||||||
|
|
||||||
|
\B{nikoli-slant}
|
||||||
|
\W{http://www.nikoli.co.jp/puzzles/39/index.htm}\cw{http://www.nikoli.co.jp/puzzles/39/index.htm}
|
||||||
|
(in Japanese)
|
||||||
|
|
||||||
|
|
||||||
|
\H{slant-controls} \i{Slant controls}
|
||||||
|
|
||||||
|
\IM{Slant controls} controls, for Slant
|
||||||
|
\IM{Slant controls} keys, for Slant
|
||||||
|
\IM{Slant controls} shortcuts (keyboard), for Slant
|
||||||
|
|
||||||
|
Left-clicking in a blank square will place a \cw{\\} in it (a line
|
||||||
|
leaning to the left, i.e. running from the top left of the square to
|
||||||
|
the bottom right). Right-clicking in a blank square will place a
|
||||||
|
\cw{/} in it (leaning to the right, running from top right to bottom
|
||||||
|
left).
|
||||||
|
|
||||||
|
Continuing to click either button will cycle between the three
|
||||||
|
possible square contents. Thus, if you left-click repeatedly in a
|
||||||
|
blank square it will change from blank to \cw{\\} to \cw{/} back to
|
||||||
|
blank, and if you right-click repeatedly the square will change from
|
||||||
|
blank to \cw{/} to \cw{\\} back to blank. (Therefore, you can play
|
||||||
|
the game entirely with one button if you need to.)
|
||||||
|
|
||||||
|
(All the actions described in \k{common-actions} are also available.)
|
||||||
|
|
||||||
|
\H{slant-parameters} \I{parameters, for slant}Slant parameters
|
||||||
|
|
||||||
|
These parameters are available from the \q{Custom...} option on the
|
||||||
|
\q{Type} menu.
|
||||||
|
|
||||||
|
\dt \e{Width}, \e{Height}
|
||||||
|
|
||||||
|
\dd Size of grid in squares.
|
||||||
|
|
||||||
|
|
||||||
\A{licence} \I{MIT licence}\ii{Licence}
|
\A{licence} \I{MIT licence}\ii{Licence}
|
||||||
|
|
||||||
This software is \i{copyright} 2004-2005 Simon Tatham.
|
This software is \i{copyright} 2004-2005 Simon Tatham.
|
||||||
|
@ -234,6 +234,12 @@ void shuffle(void *array, int nelts, int eltsize, random_state *rs);
|
|||||||
void draw_rect_outline(frontend *fe, int x, int y, int w, int h,
|
void draw_rect_outline(frontend *fe, int x, int y, int w, int h,
|
||||||
int colour);
|
int colour);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dsf.c
|
||||||
|
*/
|
||||||
|
int dsf_canonify(int *dsf, int val);
|
||||||
|
void dsf_merge(int *dsf, int v1, int v2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* version.c
|
* version.c
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user