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:
Simon Tatham
2008-09-06 15:19:47 +00:00
parent a7431c0b7c
commit f38b711c73
5 changed files with 3341 additions and 2418 deletions

1348
grid.c Normal file

File diff suppressed because it is too large Load Diff

96
grid.h Normal file
View 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 */

View File

@ -1,10 +1,10 @@
# -*- makefile -*- # -*- 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 ALL += LOOPY

4261
loopy.c

File diff suppressed because it is too large Load Diff

View File

@ -1797,17 +1797,26 @@ Unreasonable puzzles may require guessing and backtracking.
\cfg{winhelp-topic}{games.loopy} \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. loop from dot to dot within the grid.
Some of the square spaces between the dots contain numbers. These Some of the spaces between the lines contain numbers. These numbers
numbers indicate how many of the four edges of that square are part indicate how many of the lines around that space form part of the
of the loop. The loop you draw must correctly satisfy all of these loop. The loop you draw must correctly satisfy all of these clues to
clues to be considered a correct solution. 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} \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} \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 \IM{Loopy controls} controls, for Loopy
Click the left mouse button between two dots to add a line segment Click the left mouse button on a yellow line to turn it black,
connecting them. Click again to remove that line segment. 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 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 the loop, you can click the right mouse button to remove it
indicating this. Click again to remove the cross. completely. Again, clicking a second time will turn the line back to
yellow.
(All the actions described in \k{common-actions} are also available.) (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} \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} \dt \e{Difficulty}