Tumblelog by Soup.io
Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

SVG Jigsaw Generation in Clojure

[Cross-post from Bonnie Eisenman’s blog at https://blog.bonnieeisenman.com/projects/clojure-puzzles/.  Bonnie is often found at the NYC Resistor craft nights]

I spent the last week learning Clojure and generating jigsaw puzzles as part of my one-week programming retreat at the Recurse Center.

Why jigsaw puzzles? I was motivated by two things: first, I wanted a good-sized language-learning project. Secondly, I was heavily inspired by the amazing, beautiful, intricate jigsaw puzzles produced by Nervous Systems and wanted to experiment with similar-ish generative methods. (I’m a sucker for generative things and hadn’t played with generative algorithms too much before.) If you want a crazy cool puzzle, seriously, go buy one from Nervous.

I think they turned out well!

A black-and-white outline of a jigsaw puzzle. There's a cat shaped piece in the top left. A hand holding the cat-shaped puzzle piece.

Because I have access to NYC Resistor’s laser cutter, the obvious thing to do was generate SVGs which I could then laser cut. If you haven’t worked with SVG before, it’s an XML-based format for describing vector graphics. It’s pretty easy to generate “by hand”.

Here is what an SVG looks like, if you open it up with a text editor:

 <svg width="100" height="100">
  <circle
    cx="50"
    cy="50"
    r="40"
    stroke="green"
    stroke-width="4"
    fill="yellow"
    />
</svg>

This produces a yellow circle, centered at (50, 50), with a radius of 40, and a four-pixel green outline. You can view an SVG file in any web browser, or edit it in an editor like Inkscape.

A yellow circle

See? Easy-peasy.

I started by generating a “classic” jigsaw puzzle shape, and figuring out how to tile it.

A single classic jigsaw puzzle piece. A grid of mostly-identical jigsaw puzzles

But I wanted something more interesting than just a grid of similar puzzle pieces! My next step was to use a Voronoi diagram to draw more irregularly-sized polygons around “seed” points. At first this created some amusing failures:

A grid of orange dots and some black lines between them. Something looks weird - the lines skew off in random directions!

Oops. This is what happens when you draw points at (x, x) instead of (x, y). Let’s fix those coordinates.

A grid of orange dots, surrounded by black lines representing voronoi edges. Now they actually are enclosed cells, like they're supposed to be.

If we replace those straight lines with puzzle-piece edges, we get something that starts to look like a more interesting puzzle. There are still obviously flaws to be ironed out here (e.g. edge overlap).

Similar to the previous image, polygons constructed by voronoi tiling then have their edges deformed using puzzle-piece-like squiggles. There is some overlap between lines so this would not make a good puzzle.

I wanted to make more novel puzzle piece shapes, though, so I turned to the SVG path type. You can draw Bézier curves in SVG pretty easily:

<path d="M 0 0 C 0 -100 50 -100 50 0 S 100 100 100 0"
      stroke="blue"
      fill="transparent"
      transform="translate(0 400)"/>

A blue curve that dips up then down.

OK, here’s what it looks like when we replace our puzzle piece shape with some random-ish curves:

More puzzle pieces, now with squiggles.

Add more curves and it gets even better!

Very squiggly pieces.

I also experimented with variations on how to place the seed points for my puzzle generation. Here’s one that’s based on a circular point distribution.

A puzzle arranged by concentric circles of squiggles.

Now I had some monstrously-irregular puzzle pieces to play with. Cool! I wanted to take it one step further by implementing whimsy pieces. In jigsaw jargon, a whimsy piece is a themed, recognizably-shaped puzzle piece. They might be butterflies or people or letters or…you name it!

I modified my puzzle-generator to clear space for a whimsy piece, first testing it with circular whimsy pieces.

A puzzle with two circular pieces placed inside it.

Then, using a kd-tree, I identified the whimsy piece’s nearest-neighbors and connected it back to the rest of the puzzle. Here’s a cat!

Same image as earlier - a puzzle with a cat-shaped piece in it.

And, finally, I took these files over to NYC Resistor and lasered them.

Laser cutting cutting puzzle pieces into white acrylicThe completed puzzle, with the cat whimsy removed.

It took a group of us about ninety minutes to solve the cat puzzle. Not bad for four days’ work!

Several people gathered around the puzzle, working on solving it.

All of the code is available on Github at bonniee/svg-puzzle-gen. (It’s my first Clojure program, so I’m sure there are plenty of non-idiomatic things happening there.)

Dependencies / thank-yous:

Testimonials from playtesters:

  • “This is awesome!”
  • “This is horrible!”
  • “This is amazing! And by amazing I mean terrible!”
  • “Why are all the puzzle pieces the same ???”
  • “Is this supposed to be evil?”
  • “How can I get one?”

Don't be the product, buy the product!

Schweinderl