Giant's Causeway puzzle

By Chris Lamb

https://d1icoid1cnixnp.cloudfront.net/yadt/blog.Image/image/original/23.jpeg

Over Christmas I found the above puzzle at my parent's house. I don't know if it has a name but it seemed apt to name it after The Giant's Causeway.

The idea is that you swap and/or rotate the outer tiles until the colours at the edges match. The center tile is fixed, or at least I assume it is as the wooden edges are deliberately less rounded.

Of course, solving it manually would be boring so here's a dumb brute force solution. I actually admire how inefficient and stupid it is...

import itertools

class Tile(list):
    def __getitem__(self, x):
        return super(Tile, self).__getitem__(x % len(self))

    def rotate(self, x):
        return Tile(self[x:] + self[:x])

COLOURS = ('YELLOW', 'WHITE', 'BLACK', 'RED', 'GREEN', 'BLUE')
YELLOW, WHITE, BLACK, RED, GREEN, BLUE = range(len(COLOURS))

TILES = (
    Tile((WHITE, YELLOW, RED, BLUE, BLACK, GREEN)),
    Tile((RED, BLUE, BLACK, YELLOW, GREEN, WHITE)),
    Tile((WHITE, BLACK, YELLOW, GREEN, BLUE, RED)),
    Tile((WHITE, BLUE, GREEN, YELLOW, BLACK, RED)),
    Tile((GREEN, BLUE, BLACK, YELLOW, RED, WHITE)),
    Tile((RED, YELLOW, GREEN, BLACK, BLUE, WHITE)),
)

CENTER = Tile((WHITE, BLACK, RED, GREEN, BLUE, YELLOW))

def pairwise(it):
    a, b = itertools.tee(it)

    next(b, None)

    return itertools.izip(a, b)

def validate(xs):
    for idx, x in enumerate(xs):
        if x[idx + 3] != CENTER[idx]:
            raise ValueError("Tile does not match center")

    for idx, (a, b) in enumerate(pairwise(xs)):
        if a[idx + 2] != b[idx + 5]:
            raise ValueError("Tile does not match previous anticlockwise tile")

    return xs

def find_solution():
    # For all possible tile permutations..
    for xs in itertools.permutations(TILES):

        # ... try all possible rotations
        for ys in itertools.product(range(len(COLOURS)), repeat=len(COLOURS)):
            try:
                return validate([x.rotate(y) for x, y in zip(xs, ys)])
            except ValueError:
                pass

    raise ValueError("Could not find a solution.")

for x in find_solution():
    print ', '.join(COLOURS[y] for y in x)

This prints (after 5 minutes!):

$ python giants.py
GREEN, BLUE, RED, WHITE, BLACK, YELLOW
WHITE, BLUE, GREEN, YELLOW, BLACK, RED
YELLOW, GREEN, BLACK, BLUE, WHITE, RED
GREEN, WHITE, YELLOW, RED, BLUE, BLACK
RED, BLUE, BLACK, YELLOW, GREEN, WHITE
BLUE, BLACK, YELLOW, RED, WHITE, GREEN
python giants.py  269.08s user 0.02s system 99% cpu 4:29.36 total

UPDATE: Seems like this puzzle is called "Circus Seven". Now to dust off my Prolog...


Chris Lamb is a freelance software developer and the current Debian Project Leader. You can read other posts by me, see software I have written or read more about me. You can also follow me @lolamby.


Tags: Misc Hacks

Planets: ALUG UWCS WUGLUG Debian

Monday 12th January 2015


Six comments