1. 程式人生 > >Creating 3D twisty puzzles using programming

Creating 3D twisty puzzles using programming

2) Stitching

To be able to twist the puzzle, we need to know which stickers belong in a cycle. In our code, stitching will just be the process of creating collections of stickers which swap colors when the cycle is twisted.

The following figures give a visual representation of how these cycles might look like.

A cycle attached to the face of a 5x5x5 cube. Each stripe is a sub-cycle of period 4.
For Tetrahedron, the structure looks a bit more tricky. Here, Each stripe is a sub-cycle of period 3.

Note that for any puzzle of sufficiently large size most cycles will contain just one sub-cycle as there are a lot of slices that are not attached to any face.

At this point, we have all the stickers of all the faces & we can refer to them by the row & column to which they belong. To stitch them all into a cycle, we need to run algorithms that traverse those collections according to the patterns shown above.

For a example, assuming that we are generating a cycle of a Face turning Tetrahedron with size 3, the process will look somewhat like this:

Assume the sticker IDs to be in format `face-row-column`
Let the structure of the attached face (id=0) be as follows:            0-0-0      0-1-0 0-1-1 0-1-20-2-0 0-2-1 0-2-2 0-2-3 0-2-4
Also, assume that the faces with ids (1,2,3) have similar structures & have their last rows touching this face.
Then, the definition of the cycle that spans faces (1,2,3) & is attached to face (0) will be as follows:[  // Primary sub-cycle that spans faces (1,2,3):  [    1-2-4,1-2-3,1-2-2,1-2-1,1-2-0,    2-2-4,2-2-3,2-2-2,2-2-1,2-2-0,    3-2-4,3-2-3,3-2-2,3-2-1,3-2-0  ],  // Sub-cycles for the attached face (counter-clockwise):  [    0-0-0,0-1-0,    0-2-0,0-2-2,    0-2-4,0-1-2  ],  [    0-1-1,    0-2-1,    0-2-3  ]]

In a nutshell, for stitching the stickers into cycles, we need to create algorithms specific to the shape that take in some configurations specifying the orientations & connections between the different faces & generate these lists of stickers.

Once we have the full cycle definitions, the following is a possible implementation of how we can twist one,

cycle.forEach(subCycle => {  increment = direction * subCycle.length / period;
  subCycle.forEach((sticker, index) => {    sticker.newColor = subCycle[      mod(index - increment, collection.length)    ].color;  });
  subCycle.forEach(sticker => {    sticker.color = sticker.newColor;    delete sticker.newColor;  });});

Once we’re done with linking this method to cursor movements, there we have it! Fully functional twisty puzzles. But some problems we still haven’t covered like,

  1. Assuming that we know the unit vectors normal to cycle planes, the sticker on which the user clicked on, & a vector of some length that represents cursor movement, How can we figure out which of the cycles to twist & in which direction?
  2. An important aspect that we left out is animation. Can you think of a way to efficiently implement animated cycle twists?

After solving all these problems, the end result looks something like this,

That’s quite a lot to take in.. If you made it this far, Congratulations! I hope these ideas help you in creating something even more beautiful.

And there’s certainly no reason to stop at this level. Once you’re comfortable with these ideas, you can pick up some even more daunting challenge, like creating solver for Puzzles of arbitrary sizes, or even creating higher dimensional permutation puzzles!