There are a variety of puzzles in my puzzles collection. They are all derived from Puzzle generator.
A puzzle piece
It's admittedly easy to make a puzzle piece. All you need are a square, some circles, several operations such as intersection and difference.
length = 20;
spacing = 0.5;
p_offset = length * 9 / 16 + spacing / 2;
n_offset = -length * 7 / 16 - spacing / 2;
convex_radius = length / 8 - spacing / 2;
concave_radius = length / 8 + spacing / 2;
$fn = 24;
difference() {
union() {
square(length, center = true);
translate([p_offset, 0])
circle(convex_radius);
translate([0, p_offset])
circle(convex_radius);
}
translate([n_offset, 0])
circle(concave_radius);
translate([0, n_offset])
circle(concave_radius);
}
The square cuts the circles at the half radius to properly interlock pieces. Another consideration is leaving an enough gap between parts. If not to do this, pieces are too tight to fit each other. The gap length depends on the filament and parameters when 3D printing. 0.5 mm is enough for most situations. Leaving a parameter, however, is more flexible for further adjustment.
Here, the puzzle piece has just one concave or convex at each side for simplifying the example.
More puzzle pieces
Want more puzzle pieces? Copying the puzzle piece in your slicing software may solve this requirement. Well, OpenSCAD is a modeling program based on programming, so all you have to do is using a loop.
length = 20;
spacing = 0.5;
x_puzzles = 11;
y_puzzles = 6;
module puzzle_piece(length, spacing = 0.5) {
p_offset = length * 9 / 16 + spacing / 2;
n_offset = -length * 7 / 16 - spacing / 2;
convex_radius = length / 8 - spacing / 2;
concave_radius = length / 8 + spacing / 2;
$fn = 24;
translate([length / 2, length / 2]) difference() {
union() {
square(length, center = true);
translate([p_offset, 0])
circle(convex_radius);
translate([0, p_offset])
circle(convex_radius);
}
translate([n_offset, 0])
circle(concave_radius);
translate([0, n_offset])
circle(concave_radius);
}
}
for(x = [0:x_puzzles - 1]) {
for(y = [0:y_puzzles - 1]) {
translate([x * (length + spacing), y * (length + spacing)])
puzzle_piece(length, spacing = 0.5);
}
}
Cut the edges
I can actually end this topic right now, but I'm picky about it. How about cutting the edges of the puzzle, such as the figure below?
You may design specific pieces for the edges of the puzzle; however, there is a trick here. First, generate some circles to fill the hole of the edges.
Next, create a rectangle and intersect with the above model. Problem solved!
To implement the above idea, write the code below.
length = 20;
spacing = 0.5;
x_puzzles = 10;
y_puzzles = 5;
module puzzle_piece(length, spacing = 0.5) {
p_offset = length * 9 / 16 + spacing / 2;
n_offset = -length * 7 / 16 - spacing / 2;
convex_radius = length / 8 - spacing / 2;
concave_radius = length / 8 + spacing / 2;
$fn = 24;
translate([length / 2, length / 2]) difference() {
union() {
square(length, center = true);
translate([p_offset, 0])
circle(convex_radius);
translate([0, p_offset])
circle(convex_radius);
}
translate([n_offset, 0])
circle(concave_radius);
translate([0, n_offset])
circle(concave_radius);
}
}
module puzzle(x_puzzles, y_puzzles, length, spacing = 0.5) {
intersection() {
square([
x_puzzles * (length + spacing) - spacing,
y_puzzles * (length + spacing) - spacing]
);
for(x = [0:x_puzzles - 1]) {
for(y = [0:y_puzzles - 1]) {
translate([x * (length + spacing), y * (length + spacing)])
union() {
puzzle_piece(length, spacing = 0.5);
if(x == 0) {
translate([0, length / 2])
circle(length / 4, $fn = 24);
}
if(y == 0) {
translate([length / 2, 0])
circle(length / 4, $fn = 24);
}
}
}
}
}
}
puzzle(x_puzzles, y_puzzles, length, spacing);
Now, it's time to play with creativity. What would you like to put on the puzzle? The Multiplication puzzle generator could be a good start.
After that, you may find more ideas in my puzzles collection.