New puzzle: `Light Up', by James H.

Also in this checkin (committed by mistake - I meant to do it
separately), a behind-the-scenes change to Slant to colour the two
non-touching classes of diagonals in different colours. Both colours
are set to black by default, but configuration by way of
SLANT_COLOUR_* can distinguish them if you want.

[originally from svn r6164]
This commit is contained in:
Simon Tatham
2005-08-04 19:14:10 +00:00
parent 20b1a77244
commit 56e01e54fa
6 changed files with 1961 additions and 23 deletions

5
Recipe
View File

@ -25,6 +25,7 @@ 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 SLANT + MINES samegame FLIP guess PEGS dominosa UNTANGLE blackbox SLANT
+ lightup
net : [X] gtk COMMON NET net : [X] gtk COMMON NET
netslide : [X] gtk COMMON NETSLIDE netslide : [X] gtk COMMON NETSLIDE
@ -44,6 +45,7 @@ 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 slant : [X] gtk COMMON SLANT
lightup : [X] gtk COMMON lightup
# Auxiliary command-line programs. # Auxiliary command-line programs.
solosolver : [U] solo[STANDALONE_SOLVER] malloc solosolver : [U] solo[STANDALONE_SOLVER] malloc
@ -74,6 +76,7 @@ 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 slant : [G] WINDOWS COMMON SLANT
lightup : [G] WINDOWS COMMON lightup
# 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
@ -165,7 +168,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 slant; do \ pegs dominosa untangle blackbox slant lightup; do \
$(INSTALL_PROGRAM) -m 755 $$i $(DESTDIR)$(gamesdir)/$$i; \ $(INSTALL_PROGRAM) -m 755 $$i $(DESTDIR)$(gamesdir)/$$i; \
done done
!end !end

1780
lightup.c Normal file

File diff suppressed because it is too large Load Diff

2
list.c
View File

@ -23,6 +23,7 @@ extern const game dominosa;
extern const game fifteen; extern const game fifteen;
extern const game flip; extern const game flip;
extern const game guess; extern const game guess;
extern const game lightup;
extern const game mines; extern const game mines;
extern const game net; extern const game net;
extern const game netslide; extern const game netslide;
@ -43,6 +44,7 @@ const game *gamelist[] = {
&fifteen, &fifteen,
&flip, &flip,
&guess, &guess,
&lightup,
&mines, &mines,
&net, &net,
&netslide, &netslide,

View File

@ -418,6 +418,60 @@ def slant_format(s):
((x)*gridpitch, (h-y)*gridpitch, n)) ((x)*gridpitch, (h-y)*gridpitch, n))
return ret.coords, ret.s return ret.coords, ret.s
def lightup_format(s):
# Parse the game ID.
ret = Holder()
ret.s = ""
params, seed = string.split(s, ":")
w, h = map(string.atoi, string.split(params, "x"))
grid = []
while len(seed) > 0:
if seed[0] in string.lowercase:
grid.extend([-2] * (ord(seed[0]) - ord('a') + 1))
seed = seed[1:]
elif seed[0] == "B":
grid.append(-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 9pt text for the
# numbers, and a 14pt grid pitch.
textht = 10
gridpitch = 14
# 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.
psprint(ret, "newpath 0.02 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 black squares and numbers.
psprint(ret, "/Helvetica-Bold findfont %g scalefont setfont" % textht)
for y in xrange(h):
for x in xrange(w):
n = grid[y*w+x]
if n >= -1:
psprint(ret, ("newpath %g %g moveto 0 %g rlineto " +
"%g 0 rlineto 0 %g rlineto closepath fill") % \
((x)*gridpitch, (h-1-y)*gridpitch, gridpitch, gridpitch, \
-gridpitch))
if n >= 0:
psprint(ret, "gsave 1 setgray %g %g (%d) ctshow grestore" % \
((x+0.5)*gridpitch, (h-y-0.5)*gridpitch, n))
return ret.coords, ret.s
formatters = { formatters = {
"net": net_format, "net": net_format,
"rect": rect_format, "rect": rect_format,
@ -425,7 +479,8 @@ formatters = {
"pattern": pattern_format, "pattern": pattern_format,
"solo": solo_format, "solo": solo_format,
"dominosa": dominosa_format, "dominosa": dominosa_format,
"slant": slant_format "slant": slant_format,
"lightup": lightup_format
} }
if len(sys.argv) < 3: if len(sys.argv) < 3:

View File

@ -1476,7 +1476,7 @@ the game entirely with one button if you need to.)
(All the actions described in \k{common-actions} are also available.) (All the actions described in \k{common-actions} are also available.)
\H{slant-parameters} \I{parameters, for slant}Slant parameters \H{slant-parameters} \I{parameters, for Slant}Slant parameters
These parameters are available from the \q{Custom...} option on the These parameters are available from the \q{Custom...} option on the
\q{Type} menu. \q{Type} menu.
@ -1486,6 +1486,91 @@ These parameters are available from the \q{Custom...} option on the
\dd Size of grid in squares. \dd Size of grid in squares.
\C{lightup} \i{Light Up}
\cfg{winhelp-topic}{games.lightup}
You have a grid of squares. Some are filled in black; some of the
black squares are numbered. Your aim is to \q{light up} all the
empty squares by placing light bulbs in some of them.
Each light bulb illuminates the square it is on, plus all squares in
line with it horizontally or vertically unless a black square is
blocking the way.
To win the game, you must satisfy the following conditions:
\b All non-black squares are lit.
\b No light is lit by another light.
\b All numbered black squares have exactly that number of lights adjacent to
them (in the four squares above, below, and to the side).
Non-numbered black squares may have any number of lights adjacent to them.
Credit for this puzzle goes to \i{Nikoli} \k{nikoli-lightup}.
Light Up was contributed to this collection by James Harvey.
\B{nikoli-lightup}
\W{http://www.nikoli.co.jp/puzzles/32/index-e.htm}\cw{http://www.nikoli.co.jp/puzzles/32/index-e.htm}
(beware of Flash)
\H{lightup-controls} \i{Light Up controls}
\IM{Light Up controls} controls, for Light Up
\IM{Light Up controls} keys, for Light Up
\IM{Light Up controls} shortcuts (keyboard), for Light Up
Left-clicking in a non-black square will toggle the presence of a light
in that square. Right-clicking in a non-black square toggles a mark there to aid
solving; it can be used to highlight squares that cannot be lit, for example.
You may not place a light in a marked square, nor place a mark in a lit square.
The game will highlight obvious errors in red. Lights lit by other
lights are highlighted in this way, as are numbered squares which
do not (or cannot) have the right number of lights next to them.
Thus, the grid is solved when all non-black squares have yellow
highlights and there are no red lights.
\H{lightup-parameters} \I{parameters, for Light Up}Light Up 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.
\dt \e{%age of black squares}
\dd Rough percentage of black squares in the grid.
\lcont{
This is a hint rather than an instruction. If the grid generator is
unable to generate a puzzle to this precise specification, it will
increase the proportion of black squares until it can.
}
\dt \e{Symmetry}
\dd Allows you to specify the required symmetry of the black squares
in the grid. (This does not affect the difficulty of the puzzles
noticeably.)
\dt \e{Difficulty}
\dd \q{Easy} means that the puzzles should be soluble without
backtracking or guessing, \q{Hard} means that some guesses will
probably be necessary.
\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.

53
slant.c
View File

@ -35,6 +35,8 @@ enum {
COL_BACKGROUND, COL_BACKGROUND,
COL_GRID, COL_GRID,
COL_INK, COL_INK,
COL_SLANT1,
COL_SLANT2,
NCOLOURS NCOLOURS
}; };
@ -982,6 +984,14 @@ static float *game_colours(frontend *fe, game_state *state, int *ncolours)
ret[COL_INK * 3 + 1] = 0.0F; ret[COL_INK * 3 + 1] = 0.0F;
ret[COL_INK * 3 + 2] = 0.0F; ret[COL_INK * 3 + 2] = 0.0F;
ret[COL_SLANT1 * 3 + 0] = 0.0F;
ret[COL_SLANT1 * 3 + 1] = 0.0F;
ret[COL_SLANT1 * 3 + 2] = 0.0F;
ret[COL_SLANT2 * 3 + 0] = 0.0F;
ret[COL_SLANT2 * 3 + 1] = 0.0F;
ret[COL_SLANT2 * 3 + 2] = 0.0F;
*ncolours = NCOLOURS; *ncolours = NCOLOURS;
return ret; return ret;
} }
@ -1013,14 +1023,14 @@ static void draw_clue(frontend *fe, game_drawstate *ds,
int x, int y, int v) int x, int y, int v)
{ {
char p[2]; char p[2];
int col = ((x ^ y) & 1) ? COL_SLANT1 : COL_SLANT2;
if (v < 0) if (v < 0)
return; return;
p[0] = v + '0'; p[0] = v + '0';
p[1] = '\0'; p[1] = '\0';
draw_circle(fe, COORD(x), COORD(y), CLUE_RADIUS, draw_circle(fe, COORD(x), COORD(y), CLUE_RADIUS, COL_BACKGROUND, col);
COL_BACKGROUND, COL_INK);
draw_text(fe, COORD(x), COORD(y), FONT_VARIABLE, draw_text(fe, COORD(x), COORD(y), FONT_VARIABLE,
CLUE_TEXTSIZE, ALIGN_VCENTRE|ALIGN_HCENTRE, CLUE_TEXTSIZE, ALIGN_VCENTRE|ALIGN_HCENTRE,
COL_INK, p); COL_INK, p);
@ -1031,6 +1041,9 @@ static void draw_tile(frontend *fe, game_drawstate *ds, game_clues *clues,
{ {
int w = clues->w /*, h = clues->h*/, W = w+1 /*, H = h+1 */; int w = clues->w /*, h = clues->h*/, W = w+1 /*, H = h+1 */;
int xx, yy; int xx, yy;
int chesscolour = (x ^ y) & 1;
int fscol = chesscolour ? COL_SLANT2 : COL_SLANT1;
int bscol = chesscolour ? COL_SLANT1 : COL_SLANT2;
clip(fe, COORD(x), COORD(y), TILESIZE+1, TILESIZE+1); clip(fe, COORD(x), COORD(y), TILESIZE+1, TILESIZE+1);
@ -1049,17 +1062,17 @@ static void draw_tile(frontend *fe, game_drawstate *ds, game_clues *clues,
* Draw the slash. * Draw the slash.
*/ */
if (v & BACKSLASH) { if (v & BACKSLASH) {
draw_line(fe, COORD(x), COORD(y), COORD(x+1), COORD(y+1), COL_INK); draw_line(fe, COORD(x), COORD(y), COORD(x+1), COORD(y+1), bscol);
draw_line(fe, COORD(x)+1, COORD(y), COORD(x+1), COORD(y+1)-1, draw_line(fe, COORD(x)+1, COORD(y), COORD(x+1), COORD(y+1)-1,
COL_INK); bscol);
draw_line(fe, COORD(x), COORD(y)+1, COORD(x+1)-1, COORD(y+1), draw_line(fe, COORD(x), COORD(y)+1, COORD(x+1)-1, COORD(y+1),
COL_INK); bscol);
} else if (v & FORWSLASH) { } else if (v & FORWSLASH) {
draw_line(fe, COORD(x+1), COORD(y), COORD(x), COORD(y+1), COL_INK); draw_line(fe, COORD(x+1), COORD(y), COORD(x), COORD(y+1), fscol);
draw_line(fe, COORD(x+1)-1, COORD(y), COORD(x), COORD(y+1)-1, draw_line(fe, COORD(x+1)-1, COORD(y), COORD(x), COORD(y+1)-1,
COL_INK); fscol);
draw_line(fe, COORD(x+1), COORD(y)+1, COORD(x)+1, COORD(y+1), draw_line(fe, COORD(x+1), COORD(y)+1, COORD(x)+1, COORD(y+1),
COL_INK); fscol);
} }
/* /*
@ -1067,29 +1080,29 @@ static void draw_tile(frontend *fe, game_drawstate *ds, game_clues *clues,
* neighbouring cell. * neighbouring cell.
*/ */
if (v & L_T) if (v & L_T)
draw_rect(fe, COORD(x), COORD(y)+1, 1, 1, COL_INK); draw_rect(fe, COORD(x), COORD(y)+1, 1, 1, bscol);
if (v & L_B) if (v & L_B)
draw_rect(fe, COORD(x), COORD(y+1)-1, 1, 1, COL_INK); draw_rect(fe, COORD(x), COORD(y+1)-1, 1, 1, fscol);
if (v & R_T) if (v & R_T)
draw_rect(fe, COORD(x+1), COORD(y)+1, 1, 1, COL_INK); draw_rect(fe, COORD(x+1), COORD(y)+1, 1, 1, fscol);
if (v & R_B) if (v & R_B)
draw_rect(fe, COORD(x+1), COORD(y+1)-1, 1, 1, COL_INK); draw_rect(fe, COORD(x+1), COORD(y+1)-1, 1, 1, bscol);
if (v & T_L) if (v & T_L)
draw_rect(fe, COORD(x)+1, COORD(y), 1, 1, COL_INK); draw_rect(fe, COORD(x)+1, COORD(y), 1, 1, bscol);
if (v & T_R) if (v & T_R)
draw_rect(fe, COORD(x+1)-1, COORD(y), 1, 1, COL_INK); draw_rect(fe, COORD(x+1)-1, COORD(y), 1, 1, fscol);
if (v & B_L) if (v & B_L)
draw_rect(fe, COORD(x)+1, COORD(y+1), 1, 1, COL_INK); draw_rect(fe, COORD(x)+1, COORD(y+1), 1, 1, fscol);
if (v & B_R) if (v & B_R)
draw_rect(fe, COORD(x+1)-1, COORD(y+1), 1, 1, COL_INK); draw_rect(fe, COORD(x+1)-1, COORD(y+1), 1, 1, bscol);
if (v & C_TL) if (v & C_TL)
draw_rect(fe, COORD(x), COORD(y), 1, 1, COL_INK); draw_rect(fe, COORD(x), COORD(y), 1, 1, bscol);
if (v & C_TR) if (v & C_TR)
draw_rect(fe, COORD(x+1), COORD(y), 1, 1, COL_INK); draw_rect(fe, COORD(x+1), COORD(y), 1, 1, fscol);
if (v & C_BL) if (v & C_BL)
draw_rect(fe, COORD(x), COORD(y+1), 1, 1, COL_INK); draw_rect(fe, COORD(x), COORD(y+1), 1, 1, fscol);
if (v & C_BR) if (v & C_BR)
draw_rect(fe, COORD(x+1), COORD(y+1), 1, 1, COL_INK); draw_rect(fe, COORD(x+1), COORD(y+1), 1, 1, bscol);
/* /*
* And finally the clues at the corners. * And finally the clues at the corners.