shithub: puzzles

Download patch

ref: 8af0c29615fdfe30035f2d4c3a7d2ccf06d6efa9
parent: 69773d855b517ea356c3c02add97893201de2066
author: Simon Tatham <anakin@pobox.com>
date: Sat Nov 18 10:16:40 EST 2017

New grid type: the trihexagonal tiling, or 'kagome lattice'.

Regular hexagons and equilateral triangles in strict alternation, with
two of each interleaved around each vertex.
https://en.wikipedia.org/wiki/Trihexagonal_tiling

Thanks to Michael Quevillon for the patch.

--- a/LICENCE
+++ b/LICENCE
@@ -2,7 +2,8 @@
 
 Portions copyright Richard Boulton, James Harvey, Mike Pinna, Jonas
 K�lker, Dariusz Olszewski, Michael Schierl, Lambros Lambrou, Bernd
-Schmidt, Steffen Bauer, Lennard Sprong and Rogier Goossens.
+Schmidt, Steffen Bauer, Lennard Sprong, Rogier Goossens and Michael
+Quevillon.
 
 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation files
--- a/grid.c
+++ b/grid.c
@@ -2060,6 +2060,102 @@
     return g;
 }
 
+#define KAGOME_TILESIZE 18
+/* Vector for side of triangle - ratio is close to sqrt(3) */
+#define KAGOME_A 15
+#define KAGOME_B 26
+
+static void grid_size_kagome(int width, int height,
+                             int *tilesize, int *xextent, int *yextent)
+{
+    int a = KAGOME_A;
+    int b = KAGOME_B;
+
+    *tilesize = KAGOME_TILESIZE;
+    *xextent = (4*a) * (width-1) + 6*a;
+    *yextent = (2*b) * (height-1) + 2*b;
+}
+
+static grid *grid_new_kagome(int width, int height, const char *desc)
+{
+    int x, y;
+    int a = KAGOME_A;
+    int b = KAGOME_B;
+
+    /* Upper bounds - don't have to be exact */
+    int max_faces = 6 * (width + 1) * (height + 1);
+    int max_dots = 6 * width * height;
+
+    tree234 *points;
+
+    grid *g = grid_empty();
+    g->tilesize = KAGOME_TILESIZE;
+    g->faces = snewn(max_faces, grid_face);
+    g->dots = snewn(max_dots, grid_dot);
+
+    points = newtree234(grid_point_cmp_fn);
+
+    for (y = 0; y < height; y++) {
+        for (x = 0; x < width; x++) {
+            grid_dot *d;
+            /* centre of hexagon */
+            int px = (4*a) * x;
+            int py = (2*b) * y;
+            if (y % 2)
+                px += 2*a;
+
+            /* hexagon */
+            grid_face_add_new(g, 6);
+            d = grid_get_dot(g, points, px +   a, py -   b); grid_face_set_dot(g, d, 0);
+            d = grid_get_dot(g, points, px + 2*a, py      ); grid_face_set_dot(g, d, 1);
+            d = grid_get_dot(g, points, px +   a, py +   b); grid_face_set_dot(g, d, 2);
+            d = grid_get_dot(g, points, px -   a, py +   b); grid_face_set_dot(g, d, 3);
+            d = grid_get_dot(g, points, px - 2*a, py      ); grid_face_set_dot(g, d, 4);
+            d = grid_get_dot(g, points, px -   a, py -   b); grid_face_set_dot(g, d, 5);
+
+            /* Triangle above right */
+            if ((x < width - 1) || (!(y % 2) && y)) {
+                grid_face_add_new(g, 3);
+                d = grid_get_dot(g, points, px + 3*a, py - b); grid_face_set_dot(g, d, 0);
+                d = grid_get_dot(g, points, px + 2*a, py    ); grid_face_set_dot(g, d, 1);
+                d = grid_get_dot(g, points, px +   a, py - b); grid_face_set_dot(g, d, 2);
+            }
+
+            /* Triangle below right */
+            if ((x < width - 1) || (!(y % 2) && (y < height - 1))) {
+                grid_face_add_new(g, 3);
+                d = grid_get_dot(g, points, px + 3*a, py + b); grid_face_set_dot(g, d, 0);
+                d = grid_get_dot(g, points, px +   a, py + b); grid_face_set_dot(g, d, 1);
+                d = grid_get_dot(g, points, px + 2*a, py    ); grid_face_set_dot(g, d, 2);
+            }
+
+            /* Left triangles */
+            if (!x && (y % 2)) {
+                /* Triangle above left */
+                grid_face_add_new(g, 3);
+                d = grid_get_dot(g, points, px -   a, py - b); grid_face_set_dot(g, d, 0);
+                d = grid_get_dot(g, points, px - 2*a, py    ); grid_face_set_dot(g, d, 1);
+                d = grid_get_dot(g, points, px - 3*a, py - b); grid_face_set_dot(g, d, 2);
+
+                /* Triangle below left */
+                if (y < height - 1) {
+                    grid_face_add_new(g, 3);
+                    d = grid_get_dot(g, points, px -   a, py + b); grid_face_set_dot(g, d, 0);
+                    d = grid_get_dot(g, points, px - 3*a, py + b); grid_face_set_dot(g, d, 1);
+                    d = grid_get_dot(g, points, px - 2*a, py    ); grid_face_set_dot(g, d, 2);
+                }
+            }
+        }
+    }
+
+    freetree234(points);
+    assert(g->num_faces <= max_faces);
+    assert(g->num_dots <= max_dots);
+
+    grid_make_consistent(g);
+    return g;
+}
+
 #define OCTAGONAL_TILESIZE 40
 /* b/a approx sqrt(2) */
 #define OCTAGONAL_A 29
--- a/grid.h
+++ b/grid.h
@@ -100,6 +100,7 @@
   A(SNUBSQUARE,snubsquare) \
   A(CAIRO,cairo) \
   A(GREATHEXAGONAL,greathexagonal) \
+  A(KAGOME,kagome) \
   A(OCTAGONAL,octagonal) \
   A(KITE,kites) \
   A(FLORET,floret) \
--- a/loopy.c
+++ b/loopy.c
@@ -278,6 +278,7 @@
     A("Penrose (kite/dart)",PENROSE_P2,3,3)                     \
     A("Penrose (rhombs)",PENROSE_P3,3,3)                        \
     A("Great-Great-Dodecagonal",GREATGREATDODECAGONAL,2,2)      \
+    A("Kagome",KAGOME,3,3)                                      \
     /* end of list */
 
 #define GRID_NAME(title,type,amin,omin) title,
@@ -544,6 +545,7 @@
 #ifdef SMALL_SCREEN
     {  7,  7, DIFF_HARD,   LOOPY_GRID_HONEYCOMB },
     {  5,  4, DIFF_HARD,   LOOPY_GRID_GREATHEXAGONAL },
+    {  5,  4, DIFF_HARD,   LOOPY_GRID_KAGOME },
     {  5,  5, DIFF_HARD,   LOOPY_GRID_OCTAGONAL },
     {  3,  3, DIFF_HARD,   LOOPY_GRID_FLORET },
     {  3,  3, DIFF_HARD,   LOOPY_GRID_DODECAGONAL },
@@ -552,6 +554,7 @@
 #else
     { 10, 10, DIFF_HARD,   LOOPY_GRID_HONEYCOMB },
     {  5,  4, DIFF_HARD,   LOOPY_GRID_GREATHEXAGONAL },
+    {  5,  4, DIFF_HARD,   LOOPY_GRID_KAGOME },
     {  7,  7, DIFF_HARD,   LOOPY_GRID_OCTAGONAL },
     {  5,  5, DIFF_HARD,   LOOPY_GRID_FLORET },
     {  5,  4, DIFF_HARD,   LOOPY_GRID_DODECAGONAL },