mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-22 16:32:13 -07:00
Completely re-engineered version of Loopy, courtesy of Lambros
Lambrou. Now capable of handling triangular and hexagonal grids as well as square ones, and then a number of semiregular plane tilings and duals of semiregular ones. In fact, most of the solver code supports an _arbitrary_ planar graph (well, provided both the graph and its dual have no self-edges), so it could easily be extended further with only a little more effort. [originally from svn r8162]
This commit is contained in:
96
grid.h
Normal file
96
grid.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* (c) Lambros Lambrou 2008
|
||||
*
|
||||
* Code for working with general grids, which can be any planar graph
|
||||
* with faces, edges and vertices (dots). Includes generators for a few
|
||||
* types of grid, including square, hexagonal, triangular and others.
|
||||
*/
|
||||
|
||||
#ifndef PUZZLES_GRID_H
|
||||
#define PUZZLES_GRID_H
|
||||
|
||||
/* Useful macros */
|
||||
#ifndef SQ
|
||||
# define SQ(x) ( (x) * (x) )
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Grid structures:
|
||||
* A grid is made up of faces, edges and dots. These structures hold
|
||||
* the incidence relationships between these types. For example, an
|
||||
* edge always joins two dots, and is adjacent to two faces.
|
||||
* The "grid_xxx **" members are lists of pointers which are dynamically
|
||||
* allocated during grid generation.
|
||||
* A pointer to a face/edge/dot will always point somewhere inside one of the
|
||||
* three lists of the main "grid" structure: faces, edges, dots.
|
||||
* Could have used integer offsets into these lists, but using actual
|
||||
* pointers instead gives us type-safety.
|
||||
*/
|
||||
|
||||
/* Need forward declarations */
|
||||
typedef struct grid_face grid_face;
|
||||
typedef struct grid_edge grid_edge;
|
||||
typedef struct grid_dot grid_dot;
|
||||
|
||||
struct grid_face {
|
||||
int order; /* Number of edges, also the number of dots */
|
||||
grid_edge **edges; /* edges around this face */
|
||||
grid_dot **dots; /* corners of this face */
|
||||
};
|
||||
struct grid_edge {
|
||||
grid_dot *dot1, *dot2;
|
||||
grid_face *face1, *face2; /* Use NULL for the infinite outside face */
|
||||
};
|
||||
struct grid_dot {
|
||||
int order;
|
||||
grid_edge **edges;
|
||||
grid_face **faces; /* A NULL grid_face* means infinite outside face */
|
||||
|
||||
/* Position in some fairly arbitrary (Cartesian) coordinate system.
|
||||
* Use large enough values such that we can get away with
|
||||
* integer arithmetic, but small enough such that arithmetic
|
||||
* won't overflow. */
|
||||
int x, y;
|
||||
};
|
||||
typedef struct grid {
|
||||
/* These are (dynamically allocated) arrays of all the
|
||||
* faces, edges, dots that are in the grid. */
|
||||
int num_faces; grid_face *faces;
|
||||
int num_edges; grid_edge *edges;
|
||||
int num_dots; grid_dot *dots;
|
||||
|
||||
/* Should be a face roughly near the middle of the grid.
|
||||
* Used to seed path-generation, and also for nearest-edge
|
||||
* detection. */
|
||||
grid_face *middle_face;
|
||||
|
||||
/* Cache the bounding-box of the grid, so the drawing-code can quickly
|
||||
* figure out the proper scaling to draw onto a given area. */
|
||||
int lowest_x, lowest_y, highest_x, highest_y;
|
||||
|
||||
/* A measure of tile size for this grid (in grid coordinates), to help
|
||||
* the renderer decide how large to draw the grid.
|
||||
* Roughly the size of a single tile - for example the side-length
|
||||
* of a square cell. */
|
||||
int tilesize;
|
||||
|
||||
/* We really don't want to copy this monstrosity!
|
||||
* A grid is immutable once generated.
|
||||
*/
|
||||
int refcount;
|
||||
} grid;
|
||||
|
||||
grid *grid_new_square(int width, int height);
|
||||
grid *grid_new_honeycomb(int width, int height);
|
||||
grid *grid_new_triangular(int width, int height);
|
||||
grid *grid_new_snubsquare(int width, int height);
|
||||
grid *grid_new_cairo(int width, int height);
|
||||
grid *grid_new_greathexagonal(int width, int height);
|
||||
grid *grid_new_octagonal(int width, int height);
|
||||
grid *grid_new_kites(int width, int height);
|
||||
|
||||
void grid_free(grid *g);
|
||||
|
||||
grid_edge *grid_nearest_edge(grid *g, int x, int y);
|
||||
|
||||
#endif /* PUZZLES_GRID_H */
|
6
loopy.R
6
loopy.R
@ -1,10 +1,10 @@
|
||||
# -*- makefile -*-
|
||||
|
||||
LOOPY = loopy tree234 dsf
|
||||
LOOPY = loopy tree234 dsf grid
|
||||
|
||||
loopy : [X] GTK COMMON LOOPY loopy-icon|no-icon
|
||||
loopy : [X] GTK COMMON LOOPY loopy-icon|no-icon
|
||||
|
||||
loopy : [G] WINDOWS COMMON LOOPY loopy.res|noicon.res
|
||||
loopy : [G] WINDOWS COMMON LOOPY loopy.res|noicon.res
|
||||
|
||||
ALL += LOOPY
|
||||
|
||||
|
48
puzzles.but
48
puzzles.but
@ -1797,17 +1797,26 @@ Unreasonable puzzles may require guessing and backtracking.
|
||||
|
||||
\cfg{winhelp-topic}{games.loopy}
|
||||
|
||||
You are given a grid of dots. Your aim is to draw a single unbroken
|
||||
You are given a grid of dots, marked with yellow lines to indicate
|
||||
which dots you are allowed to connect directly together. Your aim is
|
||||
to use some subset of those yellow lines to draw a single unbroken
|
||||
loop from dot to dot within the grid.
|
||||
|
||||
Some of the square spaces between the dots contain numbers. These
|
||||
numbers indicate how many of the four edges of that square are part
|
||||
of the loop. The loop you draw must correctly satisfy all of these
|
||||
clues to be considered a correct solution.
|
||||
Some of the spaces between the lines contain numbers. These numbers
|
||||
indicate how many of the lines around that space form part of the
|
||||
loop. The loop you draw must correctly satisfy all of these clues to
|
||||
be considered a correct solution.
|
||||
|
||||
Credit for this puzzle goes to \i{Nikoli} \k{nikoli-loopy}.
|
||||
In the default mode, the dots are arranged in a grid of squares;
|
||||
however, you can also play on triangular or hexagonal grids, or even
|
||||
more exotic ones.
|
||||
|
||||
Loopy was contributed to this collection by Mike Pinna.
|
||||
Credit for the basic puzzle idea goes to \i{Nikoli}
|
||||
\k{nikoli-loopy}.
|
||||
|
||||
Loopy was originally contributed to this collection by Mike Pinna,
|
||||
and subsequently enhanced to handle various types of non-square grid
|
||||
by Lambros Lambrou.
|
||||
|
||||
\B{nikoli-loopy}
|
||||
\W{http://www.nikoli.co.jp/puzzles/3/index-e.htm}\cw{http://www.nikoli.co.jp/puzzles/3/index-e.htm}
|
||||
@ -1817,12 +1826,14 @@ Loopy was contributed to this collection by Mike Pinna.
|
||||
|
||||
\IM{Loopy controls} controls, for Loopy
|
||||
|
||||
Click the left mouse button between two dots to add a line segment
|
||||
connecting them. Click again to remove that line segment.
|
||||
Click the left mouse button on a yellow line to turn it black,
|
||||
indicating that you think it is part of the loop. Click again to
|
||||
turn the line yellow again (meaning you aren't sure yet).
|
||||
|
||||
If you are sure that a particular line segment is \e{not} part of
|
||||
the loop, you can click the right mouse button to add a small cross
|
||||
indicating this. Click again to remove the cross.
|
||||
the loop, you can click the right mouse button to remove it
|
||||
completely. Again, clicking a second time will turn the line back to
|
||||
yellow.
|
||||
|
||||
(All the actions described in \k{common-actions} are also available.)
|
||||
|
||||
@ -1833,7 +1844,20 @@ These parameters are available from the \q{Custom...} option on the
|
||||
|
||||
\dt \e{Width}, \e{Height}
|
||||
|
||||
\dd Size of grid in squares.
|
||||
\dd Size of grid, measured in number of regions across and down. For
|
||||
square grids, it's clear how this is counted; for other types of
|
||||
grid you may have to think a bit to see how the dimensions are
|
||||
measured.
|
||||
|
||||
\dt \e{Grid type}
|
||||
|
||||
\dd Allows you to choose between a selection of types of tiling.
|
||||
Some have all the faces the same but may have multiple different
|
||||
types of vertex (e.g. the \e{Cairo} or \e{Kites} mode); others have
|
||||
all the vertices the same but may have differnt types of face (e.g.
|
||||
the \e{Great Hexagonal}). The square, triangular and honeycomb grids
|
||||
are fully regular, and have all their vertices \e{and} faces the
|
||||
same; this makes them the least confusing to play.
|
||||
|
||||
\dt \e{Difficulty}
|
||||
|
||||
|
Reference in New Issue
Block a user